Repository: sympy/sympy

Issue:
Add logo guide to the docs
We should have a page in the docs that just has our logo that people can copy, and a guide on how to use it. Right now the logo is available if you build it in the source, but it's not easily accessible from a Google search. 

Discussion:

Patch:
diff --git a/.mailmap b/.mailmap
index b9d437ccbb..df8403a474 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1030,10 +1030,6 @@ Oscar Benjamin <oscar.j.benjamin@gmail.com> <oscar@kar-wench.(none)>
 Oscar Gerardo Lazo Arjona <oscar.lazoarjona@physics.ox.ac.uk> oscarlazoarjona <oscar.lazoarjona@physics.ox.ac.uk>
 Oscar Gustafsson <oscar.gustafsson@gmail.com>
 P. Sai Prasanth <psai.prasanth.min16@itbhu.ac.in>
-Pablo Galindo Salgado <pablogsal@gmail.com> Pablo Galindo <pablogsal@gmail.com>
-Pablo Galindo Salgado <pablogsal@gmail.com> Pablo Galindo Salgado <Pablogsal@gmail.com>
-Pablo Galindo Salgado <pablogsal@gmail.com> pablogsal <Pablogsal@gmail.com>
-Pablo Galindo Salgado <pablogsal@gmail.com> pablogsal <pablogsal@gmail.com>
 Pablo Puente <ppuedom@gmail.com> <ppuedom@yahoo.com>
 Pablo Zubieta <pabloferz@yahoo.com.mx>
 Pan Peng <pengpanster@gmail.com>
diff --git a/doc/src/contributing/documentation-style-guide.rst b/doc/src/contributing/documentation-style-guide.rst
index 230a5df084..60f06fea06 100644
--- a/doc/src/contributing/documentation-style-guide.rst
+++ b/doc/src/contributing/documentation-style-guide.rst
@@ -177,7 +177,7 @@ Narrative documentation can be written using either Restructured Text
 (``.rst``) or Markdown (``.md``). Markdown documentation uses `MyST
 <https://myst-parser.readthedocs.io/en/latest/index.html>`_. See `this guide
 <https://myst-parser.readthedocs.io/en/latest/syntax/syntax.html>`_ for more
-information on how to write documents in MArkdown. Markdown is only supported
+information on how to write documents in Markdown. Markdown is only supported
 for narrative documentation. Docstrings should continue to use RST syntax. Any
 part of this style guide that is not specific to RST syntax should still apply
 to Markdown documents.
diff --git a/doc/src/contributing/new-contributors-guide/build-docs.rst b/doc/src/contributing/new-contributors-guide/build-docs.rst
index 9a9ff3597d..acde1219be 100644
--- a/doc/src/contributing/new-contributors-guide/build-docs.rst
+++ b/doc/src/contributing/new-contributors-guide/build-docs.rst
@@ -159,21 +159,6 @@ required dependencies locally, the documentation can be built by running the
 
    make html
 
-
-SymPy Logos
-~~~~~~~~~~~
-
-SymPy has a collection of official logos, which can be generated from sympy.svg in your local copy of SymPy by:
-
-.. code-block:: none
-
-    $ cd doc
-
-    $ make logo # will be stored in the _build/logo subdirectory
-
-The license of all the logos is the same as SymPy: BSD. See the
-`LICENSE file <https://github.com/sympy/sympy/blob/master/LICENSE>`_ for more information.
-
 View the Docs
 ^^^^^^^^^^^^^
 
diff --git a/doc/src/guides/index.rst b/doc/src/guides/index.rst
index 7a47a3dfbd..adf79f5ce8 100644
--- a/doc/src/guides/index.rst
+++ b/doc/src/guides/index.rst
@@ -18,4 +18,5 @@ For a deeper and elaborate exploration of other SymPy topics, see the
    custom-functions.md
    physics/index.rst
    solving/index.md
+   logo.rst
    ../citing.md
diff --git a/doc/src/guides/logo.rst b/doc/src/guides/logo.rst
new file mode 100644
index 0000000000..a8fd0ad859
--- /dev/null
+++ b/doc/src/guides/logo.rst
@@ -0,0 +1,45 @@
+===========
+SymPy Logo
+===========
+
+We would like to make it easy for you to include the SymPy project identity in
+your next academic paper, course materials, or presentation.
+
+.. image::  ../logo/sympy.svg
+  :width: 600
+  :align: center
+  :alt: SymPy Logo
+
+The above image logo is an SVG version of the logo. We also have a PNG version of the logo:
+
+.. image::  ../../_build/logo/sympy-500px.png
+  :width: 500
+  :align: center
+  :alt: SymPy Logo
+
+If you would like one without the "SymPy" text, we have that too:
+
+.. image::  ../../_build/logo/sympy-notext-500px.png
+  :width: 500
+  :align: center
+  :alt: SymPy Logo
+
+Note: The text version should be preferred unless the "SymPy" name is already present separately.
+
+If you would like to generate SymPy's collection of official logos yourself,
+you can do so by first :ref:`installing the required dependencies <build-the-documentation>`, and then running:
+
+.. code-block:: none
+
+    $ cd doc
+
+    $ make logo # will be stored in the _build/logo subdirectory
+
+which will generate the logos by using the ``sympy.svg`` file in your local
+copy of SymPy.
+
+There is also a ``sympy/doc/generate_logos.py`` script that allows for a wider
+variety of options while generating the logo.
+
+The license of all the logos is the same as SymPy: BSD. See the
+`LICENSE file <https://github.com/sympy/sympy/blob/master/LICENSE>`_ for more information.
diff --git a/sympy/parsing/sympy_parser.py b/sympy/parsing/sympy_parser.py
index c9fba7634b..4a45a9d5bf 100644
--- a/sympy/parsing/sympy_parser.py
+++ b/sympy/parsing/sympy_parser.py
@@ -627,10 +627,7 @@ def factorial_notation(tokens: List[TOKEN], local_dict: DICT, global_dict: DICT)
     result: List[TOKEN] = []
     nfactorial = 0
     for toknum, tokval in tokens:
-        if toknum == OP and tokval == "!":
-            # In Python 3.12 "!" are OP instead of ERRORTOKEN
-            nfactorial += 1
-        elif toknum == ERRORTOKEN:
+        if toknum == ERRORTOKEN:
             op = tokval
             if op == '!':
                 nfactorial += 1
diff --git a/sympy/printing/mathml.py b/sympy/printing/mathml.py
index db02cf52bc..01e53e288a 100644
--- a/sympy/printing/mathml.py
+++ b/sympy/printing/mathml.py
@@ -73,6 +73,57 @@ def doprint(self, expr):
         res = xmlbstr.decode()
         return res
 
+    def apply_patch(self):
+        # Applying the patch of xml.dom.minidom bug
+        # Date: 2011-11-18
+        # Description: http://ronrothman.com/public/leftbraned/xml-dom-minidom\
+        #                   -toprettyxml-and-silly-whitespace/#best-solution
+        # Issue: https://bugs.python.org/issue4147
+        # Patch: https://hg.python.org/cpython/rev/7262f8f276ff/
+
+        from xml.dom.minidom import Element, Text, Node, _write_data
+
+        def writexml(self, writer, indent="", addindent="", newl=""):
+            # indent = current indentation
+            # addindent = indentation to add to higher levels
+            # newl = newline string
+            writer.write(indent + "<" + self.tagName)
+
+            attrs = self._get_attributes()
+            a_names = list(attrs.keys())
+            a_names.sort()
+
+            for a_name in a_names:
+                writer.write(" %s=\"" % a_name)
+                _write_data(writer, attrs[a_name].value)
+                writer.write("\"")
+            if self.childNodes:
+                writer.write(">")
+                if (len(self.childNodes) == 1 and
+                        self.childNodes[0].nodeType == Node.TEXT_NODE):
+                    self.childNodes[0].writexml(writer, '', '', '')
+                else:
+                    writer.write(newl)
+                    for node in self.childNodes:
+                        node.writexml(
+                            writer, indent + addindent, addindent, newl)
+                    writer.write(indent)
+                writer.write("</%s>%s" % (self.tagName, newl))
+            else:
+                writer.write("/>%s" % (newl))
+        self._Element_writexml_old = Element.writexml
+        Element.writexml = writexml
+
+        def writexml(self, writer, indent="", addindent="", newl=""):
+            _write_data(writer, "%s%s%s" % (indent, self.data, newl))
+        self._Text_writexml_old = Text.writexml
+        Text.writexml = writexml
+
+    def restore_patch(self):
+        from xml.dom.minidom import Element, Text
+        Element.writexml = self._Element_writexml_old
+        Text.writexml = self._Text_writexml_old
+
 
 class MathMLContentPrinter(MathMLPrinterBase):
     """Prints an expression to the Content MathML markup language.
@@ -2076,7 +2127,9 @@ def print_mathml(expr, printer='content', **settings):
     else:
         s = MathMLContentPrinter(settings)
     xml = s._print(sympify(expr))
+    s.apply_patch()
     pretty_xml = xml.toprettyxml()
+    s.restore_patch()
 
     print(pretty_xml)
 


Test patch:
diff --git a/.github/workflows/runtests.yml b/.github/workflows/runtests.yml
index 71eda65327..8ae6302207 100644
--- a/.github/workflows/runtests.yml
+++ b/.github/workflows/runtests.yml
@@ -282,7 +282,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python-version: ['3.8', '3.9', '3.10', '3.12-dev', 'pypy-3.8']
+        python-version: ['3.8', '3.9', '3.10', '3.12.0-alpha - 3.12', 'pypy-3.8']
         experimental: [false]
         group: [1, 2, 3, 4]
         # Maybe use this to add 3.12 when the time comes:
@@ -308,7 +308,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        python-version: ['3.8', '3.9', '3.10', '3.12-dev', 'pypy-3.8']
+        python-version: ['3.8', '3.9', '3.10', '3.12.0-alpha - 3.12', 'pypy-3.8']
         experimental: [false]
         # Maybe use this to add 3.12 when the time comes:
         #include:
diff --git a/sympy/printing/tests/test_mathml.py b/sympy/printing/tests/test_mathml.py
index 050994e1d7..438a6e4a1d 100644
--- a/sympy/printing/tests/test_mathml.py
+++ b/sympy/printing/tests/test_mathml.py
@@ -1215,6 +1215,24 @@ def test_presentation_settings():
                                      method="garbage"))
 
 
+def test_toprettyxml_hooking():
+    # test that the patch doesn't influence the behavior of the standard
+    # library
+    import xml.dom.minidom
+    doc1 = xml.dom.minidom.parseString(
+        "<apply><plus/><ci>x</ci><cn>1</cn></apply>")
+    doc2 = xml.dom.minidom.parseString(
+        "<mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow>")
+    prettyxml_old1 = doc1.toprettyxml()
+    prettyxml_old2 = doc2.toprettyxml()
+
+    mp.apply_patch()
+    mp.restore_patch()
+
+    assert prettyxml_old1 == doc1.toprettyxml()
+    assert prettyxml_old2 == doc2.toprettyxml()
+
+
 def test_print_domains():
     from sympy.sets import Integers, Naturals, Naturals0, Reals, Complexes