Blob Blame History Raw
diff -up build/pkgs/ipython/src/IPython/core/interactiveshell.py.orig build/pkgs/ipython/src/IPython/core/interactiveshell.py
--- build/pkgs/ipython/src/IPython/core/interactiveshell.py.orig	2018-07-28 18:24:17.000000000 -0600
+++ build/pkgs/ipython/src/IPython/core/interactiveshell.py	2020-05-07 09:19:44.916646996 -0600
@@ -2813,7 +2813,7 @@ class InteractiveShell(SingletonConfigur
 
         try:
             for i, node in enumerate(to_run_exec):
-                mod = ast.Module([node])
+                mod = ast.Module([node], [])
                 code = compiler(mod, cell_name, "exec")
                 if self.run_code(code, result):
                     return True
diff -up build/pkgs/sagetex/src/extractsagecode.py.orig build/pkgs/sagetex/src/extractsagecode.py
--- build/pkgs/sagetex/src/extractsagecode.py.orig	2019-11-14 04:02:40.000000000 -0700
+++ build/pkgs/sagetex/src/extractsagecode.py	2020-02-25 13:42:46.674646884 -0700
@@ -45,7 +45,7 @@ See the SageTeX documentation for more d
 
 try:
   opts, args = getopt.getopt(sys.argv[1:], 'ho', ['help', 'overwrite'])
-except getopt.GetoptError, err:
+except getopt.GetoptError as err:
   print(str(err))
   usage()
   sys.exit(2)
diff -up build/pkgs/sagetex/src/makestatic.py.orig build/pkgs/sagetex/src/makestatic.py
--- build/pkgs/sagetex/src/makestatic.py.orig	2019-11-14 04:02:40.000000000 -0700
+++ build/pkgs/sagetex/src/makestatic.py	2020-02-25 13:42:46.674646884 -0700
@@ -45,7 +45,7 @@ See the SageTeX documentation for more d
 
 try:
   opts, args = getopt.getopt(sys.argv[1:], 'ho', ['help', 'overwrite'])
-except getopt.GetoptError, err:
+except getopt.GetoptError as err:
   print(str(err))
   usage()
   sys.exit(2)
diff -up build/pkgs/sagetex/src/remote-sagetex.py.orig build/pkgs/sagetex/src/remote-sagetex.py
--- build/pkgs/sagetex/src/remote-sagetex.py.orig	2019-11-14 04:02:40.000000000 -0700
+++ build/pkgs/sagetex/src/remote-sagetex.py	2020-02-25 13:42:46.674646884 -0700
@@ -24,12 +24,11 @@
 ## You should have received a copy of the GNU General Public License along
 ## with this program.  If not, see <http://www.gnu.org/licenses/>.
 ## 
-from __future__ import print_function
 import json
 import sys
 import time
 import re
-import urllib
+import urllib.request, urllib.parse, urllib.error
 import hashlib
 import os
 import os.path
@@ -156,7 +155,7 @@ class RemoteSage:
                                    '\n*(?P<output>.*)', re.DOTALL)
         self._404 = re.compile('404 Not Found')
         self._session = self._get_url('login',
-                                    urllib.urlencode({'username': user,
+                                    urllib.parse.urlencode({'username': user,
                                     'password':
                                     password}))['session']
         self._codewrap = """try:
@@ -176,18 +175,18 @@ except:
             _p_.save(filename=plotfilename, **kwargs)""")
 
     def _encode(self, d):
-        return 'session={0}&'.format(self._session) + urllib.urlencode(d)
+        return 'session={0}&'.format(self._session) + urllib.parse.urlencode(d)
 
     def _get_url(self, action, u):
-        with closing(urllib.urlopen(self._srv + '/simple/' + action +
-                                    '?' + u)) as h:
+        with closing(urllib.request.urlopen(self._srv + '/simple/' + action +
+                                            '?' + u)) as h:
             data = self._response.match(h.read())
             result = json.loads(data.group('header'))
             result['output'] = data.group('output').rstrip()
         return result
 
     def _get_file(self, fn, cell, ofn=None):
-        with closing(urllib.urlopen(self._srv + '/simple/' + 'file' + '?' +
+        with closing(urllib.request.urlopen(self._srv + '/simple/' + 'file' + '?' +
                      self._encode({'cell': cell, 'file': fn}))) as h:
             myfn = ofn if ofn else fn
             data = h.read()
@@ -277,13 +276,13 @@ if login_info_file:
                     password = get_val(line)
 
 if not server:
-    server = raw_input('Enter server: ')
+    server = input('Enter server: ')
 
 if not server.startswith('http'):
     server = 'https://' + server
 
 if not username:
-    username = raw_input('Enter username: ')
+    username = input('Enter username: ')
 
 if not password:
     from getpass import getpass
diff -up build/pkgs/sagetex/src/sagetexparse.py.orig build/pkgs/sagetex/src/sagetexparse.py
--- build/pkgs/sagetex/src/sagetexparse.py.orig	2019-11-14 04:02:40.000000000 -0700
+++ build/pkgs/sagetex/src/sagetexparse.py	2020-02-25 13:42:46.674646884 -0700
@@ -132,7 +132,7 @@ class SageCodeExtractor():
 
   def plotout(self, s, l, t):
     self.result += '# \\sageplot{} from line %s:\n' % lineno(l, s)
-    if t.format is not '':
+    if t.format != '':
       self.result += '# format: %s' % t.format[0][1:-1] + '\n'
     self.result += t.code[1:-1] + '\n\n'
 
diff -up src/sage/combinat/finite_state_machine.py.orig src/sage/combinat/finite_state_machine.py
--- src/sage/combinat/finite_state_machine.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/combinat/finite_state_machine.py	2020-07-06 16:47:19.198130202 -0600
@@ -935,7 +935,7 @@ import six
 from six.moves import range, zip_longest, zip
 
 from IPython.lib.pretty import pretty
-import collections
+import collections, collections.abc
 import itertools
 from copy import copy, deepcopy
 
@@ -14159,7 +14159,7 @@ def is_FSMProcessIterator(PI):
 
 
 class FSMProcessIterator(SageObject,
-                         collections.Iterator):
+                         collections.abc.Iterator):
     """
     This class takes an input, feeds it into a finite state machine
     (automaton or transducer, in particular), tests whether this was
diff -up src/sage/cpython/debugimpl.c.orig src/sage/cpython/debugimpl.c
--- src/sage/cpython/debugimpl.c.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/cpython/debugimpl.c	2020-07-07 13:56:17.121624915 -0600
@@ -155,6 +155,7 @@ static void _type_debug(PyTypeObject* tp
     printf("  tp_basicsize: %ld\n", (long)tp->tp_basicsize);
     printf("  tp_itemsize: %ld\n", (long)tp->tp_itemsize);
     printf("  tp_dictoffset: %ld\n", (long)tp->tp_dictoffset);
+    printf("  tp_vectorcall_offset: %ld\n", (long)tp->tp_vectorcall_offset);
     if HAVE_WEAKREFS(tp)
     {
         printf("  tp_weaklistoffset: %ld\n", (long)tp->tp_weaklistoffset);
@@ -185,7 +186,6 @@ static void _type_debug(PyTypeObject* tp
     attr_pointer(tp_free);
 
     attr_pointer_meth(tp_repr, "__repr__");
-    attr_pointer(tp_print);
     attr_pointer_meth(tp_hash, "__hash__");
     attr_pointer_meth(tp_call, "__call__");
     attr_pointer_meth(tp_str, "__str__");
diff -up src/sage/cpython/debug.pyx.orig src/sage/cpython/debug.pyx
--- src/sage/cpython/debug.pyx.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/cpython/debug.pyx	2020-07-07 13:57:49.169641697 -0600
@@ -232,6 +232,7 @@ def type_debug(cls):
           tp_basicsize: 16
           tp_itemsize: 0
           tp_dictoffset: 0
+          tp_vectorcall_offset: 0
           tp_weaklistoffset: 0
           tp_base (__base__): NULL
           tp_bases (__bases__): tuple:
@@ -259,7 +260,6 @@ def type_debug(cls):
           tp_dealloc (__dealloc__): 0x7fc57d757010
           tp_free: PyObject_Del
           tp_repr (__repr__): 0x7fc57d75b990
-          tp_print: NULL
           tp_hash (__hash__): _Py_HashPointer
           tp_call (__call__): NULL
           tp_str (__str__): 0x7fc57d757020
diff -up src/sage/geometry/triangulation/point_configuration.py.orig src/sage/geometry/triangulation/point_configuration.py
--- src/sage/geometry/triangulation/point_configuration.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/geometry/triangulation/point_configuration.py	2020-07-06 16:48:01.176121036 -0600
@@ -619,11 +619,11 @@ class PointConfiguration(UniqueRepresent
             ['{{0,1,2,4},{1,2,3,4}}']
         """
         timeout = 600
-        proc = pexpect.spawn(executable, timeout=timeout)
+        proc = pexpect.spawn(executable, timeout=timeout, encoding='utf-8')
         proc.expect(r'Evaluating Commandline Options \.\.\.')
         proc.expect(r'\.\.\. done\.')
         proc.setecho(0)
-        assert proc.readline().strip() == b''
+        assert proc.readline().strip() == ''
 
         if verbose:
             print("#### TOPCOM input ####")
diff -up src/sage/graphs/graph_latex.py.orig src/sage/graphs/graph_latex.py
--- src/sage/graphs/graph_latex.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/graphs/graph_latex.py	2020-07-06 16:48:01.177121036 -0600
@@ -1156,7 +1156,7 @@ class GraphLatex(SageObject):
             #
             elif name in color_dicts:
                 if not isinstance(value, dict):
-                    raise TypeError('%s option must be a dictionary, not %s' (name, value))
+                    raise TypeError('%s option must be a dictionary, not %s' % (name, value))
                 else:
                     for key, c in value.items():
                         try:
@@ -1165,42 +1165,42 @@ class GraphLatex(SageObject):
                             raise ValueError('%s option for %s needs to be a matplotlib color (always as a string), not %s' % (name, key, c))
             elif name in positive_scalar_dicts:
                 if not isinstance(value, dict):
-                    raise TypeError('%s option must be a dictionary, not %s' (name, value))
+                    raise TypeError('%s option must be a dictionary, not %s' % (name, value))
                 else:
                     for key, x in value.items():
                         if not type(x) in [int, Integer, float, RealLiteral] or not x >= 0.0:
                             raise ValueError('%s option for %s needs to be a positive number, not %s' % (name, key, x))
             elif name in boolean_dicts:
                 if not isinstance(value, dict):
-                    raise TypeError('%s option must be a dictionary, not %s' (name, value))
+                    raise TypeError('%s option must be a dictionary, not %s' % (name, value))
                 else:
                     for key, b in value.items():
                         if not isinstance(b, bool):
                             raise ValueError('%s option for %s needs to be True or False, not %s' % (name, key, b))
             elif name == 'vertex_shapes':
                 if not isinstance(value, dict):
-                    raise TypeError('%s option must be a dictionary, not %s' (name, value))
+                    raise TypeError('%s option must be a dictionary, not %s' % (name, value))
                 else:
                     for key, s in value.items():
                         if s not in shape_names:
                             raise ValueError('%s option for %s needs to be a vertex shape, not %s' % (name, key, s))
             elif name == 'vertex_label_placements':
                 if not isinstance(value, dict):
-                    raise TypeError('%s option must be a dictionary, not %s' (name, value))
+                    raise TypeError('%s option must be a dictionary, not %s' % (name, value))
                 else:
                     for key, p in value.items():
                         if not(p == 'center') and not(isinstance(p, tuple) and len(p) == 2 and type(p[0]) in number_types and p[0] >= 0 and type(p[1]) in number_types and p[1] >= 0):
                             raise ValueError('%s option for %s needs to be None or a pair of positive numbers, not %s' % (name, key, p))
             elif name == 'edge_label_placements':
                 if not isinstance(value, dict):
-                    raise TypeError('%s option must be a dictionary, not %s' (name, value))
+                    raise TypeError('%s option must be a dictionary, not %s' % (name, value))
                 else:
                     for key, p in value.items():
                         if not(type(p) in [float, RealLiteral] and (0 <= p) and (p <= 1)) and not(p in label_places):
                             raise ValueError('%s option for %s needs to be a number between 0.0 and 1.0 or a place (like "above"), not %s' % (name, key, p))
             elif name == 'loop_placements':
                 if not isinstance(value, dict):
-                    raise TypeError('%s option must be a dictionary, not %s' (name, value))
+                    raise TypeError('%s option must be a dictionary, not %s' % (name, value))
                 else:
                     for key, p in value.items():
                         if not((isinstance(p, tuple)) and (len(p) == 2) and (p[0] >= 0) and (p[1] in compass_points)):
diff -up src/sage/interfaces/frobby.py.orig src/sage/interfaces/frobby.py
--- src/sage/interfaces/frobby.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/interfaces/frobby.py	2020-07-06 16:48:01.178121036 -0600
@@ -79,7 +79,7 @@ class Frobby:
             print("Frobby command: ", repr(command))
             print("Frobby input:\n", input)
 
-        process = Popen(command, stdin = PIPE, stdout = PIPE, stderr = PIPE)
+        process = Popen(command, stdin = PIPE, stdout = PIPE, stderr = PIPE, encoding='utf-8')
         if input:
             frinput = str_to_bytes(input)
         else:
diff -up src/sage/interfaces/gfan.py.orig src/sage/interfaces/gfan.py
--- src/sage/interfaces/gfan.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/interfaces/gfan.py	2020-07-06 16:48:01.178121036 -0600
@@ -66,7 +66,7 @@ class Gfan(object):
         if six.PY2:
             enc_kwargs = {}
         else:
-            enc_kwargs = {'encoding': 'latin-1'}
+            enc_kwargs = {'encoding': 'utf-8'}
 
         gfan_processes = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE,
                                **enc_kwargs)
diff -up src/sage/interfaces/gp.py.orig src/sage/interfaces/gp.py
--- src/sage/interfaces/gp.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/interfaces/gp.py	2020-07-06 16:48:01.179121036 -0600
@@ -934,17 +934,6 @@ class GpElement(ExpectElement):
         """
         return repr(self.type()) == 't_STR'
 
-    def __long__(self):
-        """
-        Return Python long.
-
-        EXAMPLES::
-
-            sage: long(gp(10))
-            10L
-        """
-        return long(str(self))
-
     def __float__(self):
         """
         Return Python float.
diff -up src/sage/interfaces/latte.py.orig src/sage/interfaces/latte.py
--- src/sage/interfaces/latte.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/interfaces/latte.py	2020-07-06 16:48:01.180121036 -0600
@@ -152,6 +152,7 @@ def count(arg, ehrhart_polynomial=False,
     latte_proc = Popen(args,
                        stdin=PIPE, stdout=PIPE,
                        stderr=(None if verbose else PIPE),
+                       encoding='utf-8',
                        cwd=str(SAGE_TMP))
 
     ans, err = latte_proc.communicate(arg)
@@ -364,6 +365,7 @@ def integrate(arg, polynomial=None, algo
     latte_proc = Popen(args,
                        stdin=PIPE, stdout=PIPE,
                        stderr=(None if verbose else PIPE),
+                       encoding='utf-8',
                        cwd=str(SAGE_TMP))
 
     ans, err = latte_proc.communicate(arg)
diff -up src/sage/interfaces/sagespawn.pyx.orig src/sage/interfaces/sagespawn.pyx
--- src/sage/interfaces/sagespawn.pyx.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/interfaces/sagespawn.pyx	2020-07-06 16:48:01.180121036 -0600
@@ -1,6 +1,6 @@
 """
 Sage wrapper around pexpect's ``spawn`` class and
-the ptyprocess's ``PtyProcess`` class.
+the ptyprocess's ``PtyProcessUnicode`` class.
 
 AUTHOR:
 
@@ -21,7 +21,7 @@ AUTHOR:
 #*****************************************************************************
 
 from pexpect import *
-from ptyprocess import PtyProcess
+from ptyprocess import PtyProcessUnicode
 
 from cpython.ref cimport Py_INCREF
 from libc.signal cimport *
@@ -30,7 +30,6 @@ from posix.unistd cimport getpid, getpgi
 
 from time import sleep
 
-from sage.cpython.string cimport str_to_bytes
 from sage.interfaces.process cimport ContainChildren
 
 
@@ -171,7 +170,7 @@ class SageSpawn(spawn):
         return ret
 
 
-class SagePtyProcess(PtyProcess):
+class SagePtyProcess(PtyProcessUnicode):
     def close(self, force=None):
         """
         Quit the child process: send the quit string, close the
@@ -192,11 +191,7 @@ class SagePtyProcess(PtyProcess):
             if self.quit_string is not None:
                 try:
                     # This can fail if the process already exited
-                    # PtyProcess.write takes bytes; ideally we would use
-                    # an encoding picked specifically for the target process
-                    # but the default (UTF-8) will do now, since I don't
-                    # think we have any non-ASCII quit_strings anyways.
-                    self.write(str_to_bytes(self.quit_string))
+                    self.write(self.quit_string)
                 except (OSError, IOError):
                     pass
             self.fileobj.close()
diff -up src/sage/lfunctions/lcalc.py.orig src/sage/lfunctions/lcalc.py
diff -up src/sage/libs/coxeter3/coxeter.pyx.orig src/sage/libs/coxeter3/coxeter.pyx
--- src/sage/libs/coxeter3/coxeter.pyx.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/libs/coxeter3/coxeter.pyx	2020-07-06 16:48:01.181121035 -0600
@@ -33,7 +33,7 @@ cdef class String:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import String       # optional - coxeter3
-            sage: s = String("hello"); s                              # optional - coxeter3
+            sage: s = String(b"hello"); s                             # optional - coxeter3
             hello
             sage: del s                                               # optional - coxeter3
         """
@@ -44,11 +44,11 @@ cdef class String:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import String       # optional - coxeter3
-            sage: s = String('Hi')                                    # optional - coxeter3
+            sage: s = String(b'Hi')                                   # optional - coxeter3
             sage: s                                                   # optional - coxeter3
             Hi
         """
-        return bytes_to_str(self.x.ptr())
+        return self.x.ptr().decode('utf-8')
 
     def __hash__(self):
         """
@@ -60,7 +60,7 @@ cdef class String:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import String        # optional - coxeter3
-            sage: s = String('hello')                                  # optional - coxeter3
+            sage: s = String(b'hello')                                 # optional - coxeter3
             sage: hash(s) == hash('hello')                             # optional - coxeter3
             True
         """
@@ -71,9 +71,9 @@ cdef class String:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import String        # optional - coxeter3
-            sage: ta1 = String('A')                                    # optional - coxeter3
-            sage: ta2 = String('A')                                    # optional - coxeter3
-            sage: tb = String('b')                                     # optional - coxeter3
+            sage: ta1 = String(b'A')                                   # optional - coxeter3
+            sage: ta2 = String(b'A')                                   # optional - coxeter3
+            sage: tb = String(b'b')                                    # optional - coxeter3
             sage: ta1 == ta2                                           # optional - coxeter3
             True
             sage: tb != ta1                                            # optional - coxeter3
@@ -109,7 +109,7 @@ cdef class String:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import String       # optional - coxeter3
-            sage: s = String('Hi')                                    # optional - coxeter3
+            sage: s = String(b'Hi')                                   # optional - coxeter3
             sage: len(s)                                              # optional - coxeter3
             2
         """
@@ -120,7 +120,7 @@ cdef class String:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import String       # optional - coxeter3
-            sage: s = String('Hi')                                    # optional - coxeter3
+            sage: s = String(b'Hi')                                   # optional - coxeter3
             sage: TestSuite(s).run()                                  # optional - coxeter3
         """
         return (String, (repr(self),) )
@@ -134,7 +134,7 @@ cdef class Type:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import Type         # optional - coxeter3
-            sage: t = Type('A'); t                                    # optional - coxeter3
+            sage: t = Type(b'A'); t                                   # optional - coxeter3
             A
             sage: del t                                               # optional - coxeter3
         """
@@ -145,7 +145,7 @@ cdef class Type:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import Type         # optional - coxeter3
-            sage: t = Type('A'); t                                    # optional - coxeter3
+            sage: t = Type(b'A'); t                                   # optional - coxeter3
             A
         """
         return bytes_to_str(self.x.name().ptr())
@@ -155,7 +155,7 @@ cdef class Type:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import Type         # optional - coxeter3
-            sage: t = Type('A')                                       # optional - coxeter3
+            sage: t = Type(b'A')                                      # optional - coxeter3
             sage: t.name()                                            # optional - coxeter3
             A
         """
@@ -171,8 +171,8 @@ cdef class Type:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import Type          # optional - coxeter3
-            sage: a = Type('A')                                        # optional - coxeter3
-            sage: b = Type('B')                                        # optional - coxeter3
+            sage: a = Type(b'A')                                       # optional - coxeter3
+            sage: b = Type(b'B')                                       # optional - coxeter3
             sage: hash(a) == hash(b)                                   # optional - coxeter3
             False
             sage: d = {a: 1, b: 2}                                     # optional - coxeter3
@@ -184,9 +184,9 @@ cdef class Type:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import Type          # optional - coxeter3
-            sage: ta1 = Type('A')                                      # optional - coxeter3
-            sage: ta2 = Type('A')                                      # optional - coxeter3
-            sage: tb = Type('b')                                       # optional - coxeter3
+            sage: ta1 = Type(b'A')                                     # optional - coxeter3
+            sage: ta2 = Type(b'A')                                     # optional - coxeter3
+            sage: tb = Type(b'b')                                      # optional - coxeter3
             sage: ta1 == ta2                                           # optional - coxeter3
             True
             sage: tb != ta1                                            # optional - coxeter3
@@ -220,7 +220,7 @@ cdef class Type:
         EXAMPLES::
 
             sage: from sage.libs.coxeter3.coxeter import Type           # optional - coxeter3
-            sage: t = Type('A')                                         # optional - coxeter3
+            sage: t = Type(b'A')                                        # optional - coxeter3
             sage: TestSuite(t).run()                                    # optional - coxeter3
         """
         return (Type, (repr(self), ))
@@ -257,7 +257,7 @@ cdef class CoxGroup(SageObject):
             type = type.lower()
             rank = rank + 1
 
-        type = 'B' if type == 'C' else type
+        type = b'B' if type == 'C' else type.encode('utf-8')
 
         if rank == 0:
             raise NotImplementedError("Coxeter group of type ['A',0] using Coxeter 3 not yet implemented")
diff -up src/sage/misc/parser.pyx.orig src/sage/misc/parser.pyx
--- src/sage/misc/parser.pyx.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/misc/parser.pyx	2020-07-06 16:48:01.182121035 -0600
@@ -95,7 +95,7 @@ def token_to_str(int token):
 
 
 cdef inline bint is_alphanumeric(char c):
-    return 'a' <= c <= 'z' or 'A' <= c <= 'Z' or '0' <= c <= '9' or c == '_'
+    return c'a' <= c <= c'z' or c'A' <= c <= c'Z' or c'0' <= c <= c'9' or c == c'_'
 
 cdef inline bint is_whitespace(char c):
     return (c != 0) & (strchr(" \t\n\r", c) != NULL)
@@ -247,23 +247,23 @@ cdef class Tokenizer:
             return EOS
 
         # dipthongs
-        if s[pos+1] == '=':
-            if s[pos] == '<':
+        if s[pos+1] == c'=':
+            if s[pos] == c'<':
                 self.pos += 2
                 return LESS_EQ
-            elif s[pos] == '>':
+            elif s[pos] == c'>':
                 self.pos += 2
                 return GREATER_EQ
-            elif s[pos] == '!':
+            elif s[pos] == c'!':
                 self.pos += 2
                 return NOT_EQ
-            elif s[pos] == '=':
+            elif s[pos] == c'=':
                 self.pos += 2
-                return '='
+                return c'='
 
-        elif s[pos] == '*' and s[pos+1] == '*':
+        elif s[pos] == c'*' and s[pos+1] == c'*':
             self.pos += 2
-            return '^'
+            return c'^'
 
         # simple tokens
         if strchr("+-*/^()=<>,[]{}!", s[pos]):
@@ -272,29 +272,29 @@ cdef class Tokenizer:
             return type
 
         # numeric literals
-        if '0' <= s[pos] <= '9' or s[pos] == '.':
+        if c'0' <= s[pos] <= c'9' or s[pos] == c'.':
             type = INT
             seen_exp = False
             seen_decimal = False
             while True:
-                if '0' <= s[pos] <= '9':
+                if c'0' <= s[pos] <= c'9':
                     pass
-                elif s[pos] == '.':
+                elif s[pos] == c'.':
                     if seen_decimal or seen_exp:
                         self.pos = pos
                         return type
                     else:
                         type = FLOAT
                         seen_decimal = True
-                elif s[pos] == 'e' or s[pos] == 'E':
+                elif s[pos] == c'e' or s[pos] == c'E':
                     if seen_exp:
                         self.pos = pos
                         return type
                     else:
                         type = FLOAT
                         seen_exp = True
-                elif s[pos] == '+' or s[pos] == '-':
-                    if not (seen_exp and (s[pos-1] == 'e' or s[pos-1] == 'E')):
+                elif s[pos] == c'+' or s[pos] == c'-':
+                    if not (seen_exp and (s[pos-1] == c'e' or s[pos-1] == c'E')):
                         self.pos = pos
                         return type
                 else:
@@ -573,13 +573,13 @@ cdef class Parser:
         """
         cdef int token
         all = []
-        if tokens.next() == '(':
-            token = ','
-            while token == ',':
+        if tokens.next() == c'(':
+            token = c','
+            while token == c',':
                 all.append(self.p_list(tokens))
                 token = tokens.next()
 
-            if token == ')':
+            if token == c')':
                 from sage.matrix.constructor import matrix
                 return matrix(all)
             else:
@@ -601,8 +601,8 @@ cdef class Parser:
             [(1, 2, 3), [a + 1, b + 2, c + 3, (d + 4,)]]
         """
         all = []
-        cdef int token = ','
-        while token == ',':
+        cdef int token = c','
+        while token == c',':
             token = tokens.peek()
             if token == MATRIX:
                 tokens.next()
@@ -615,14 +615,14 @@ cdef class Parser:
                 else:
                     tokens.backtrack()
                     obj = self.p_eqn(tokens)
-            elif token == '[':
+            elif token == c'[':
                 obj = self.p_list(tokens)
-            elif token == '(':
+            elif token == c'(':
                 obj = self.p_tuple(tokens)
             elif token == EOS:
                 return all
-            elif token == ']' or token == ')':
-                tokens.token = ','
+            elif token == c']' or token == c')':
+                tokens.token = c','
                 return all
             else:
                 obj = self.p_eqn(tokens)
@@ -646,11 +646,11 @@ cdef class Parser:
             []
         """
         cdef int token = tokens.next()
-        if token != '[':
+        if token != c'[':
             self.parse_error(tokens, "Malformed list")
         all = self.p_sequence(tokens)
         token = tokens.next()
-        if token != ']':
+        if token != c']':
             self.parse_error(tokens, "Malformed list")
         return all
 
@@ -668,20 +668,20 @@ cdef class Parser:
         cdef int start = tokens.pos
         cdef int token = tokens.next()
         cdef bint real_tuple = True
-        if token != '(':
+        if token != c'(':
             self.parse_error(tokens, "Malformed tuple")
         all = self.p_sequence(tokens)
         if len(all) == 1:
             if tokens.last() != c',':
                 real_tuple = False
         token = tokens.next()
-        if token != ')':
+        if token != c')':
             self.parse_error(tokens, "Malformed tuple")
         if real_tuple:
             return tuple(all)
         else:
             token = tokens.peek()
-            if token == ',' or token == EOS:
+            if token == c',' or token == EOS:
                 return all[0]
             else:
                 # we have to reparse the entire thing as an expression
@@ -717,15 +717,15 @@ cdef class Parser:
         """
         lhs = self.p_expr(tokens)
         cdef int op = tokens.next()
-        if op == '=':
+        if op == c'=':
             return lhs == self.p_expr(tokens)
         elif op == NOT_EQ:
             return lhs != self.p_expr(tokens)
-        elif op == '<':
+        elif op == c'<':
             return lhs < self.p_expr(tokens)
         elif op == LESS_EQ:
             return lhs <= self.p_expr(tokens)
-        elif op == '>':
+        elif op == c'>':
             return lhs > self.p_expr(tokens)
         elif op == GREATER_EQ:
             return lhs >= self.p_expr(tokens)
@@ -757,9 +757,9 @@ cdef class Parser:
         cdef int op
         operand1 = self.p_term(tokens)
         op = tokens.next()
-        while op == '+' or op == '-':
+        while op == c'+' or op == c'-':
             operand2 = self.p_term(tokens)
-            if op == '+':
+            if op == c'+':
                 operand1 = operand1 + operand2
             else:
                 operand1 = operand1 - operand2
@@ -792,17 +792,17 @@ cdef class Parser:
         operand1 = self.p_factor(tokens)
         op = tokens.next()
         if op == NAME and self.implicit_multiplication:
-            op = '*'
+            op = c'*'
             tokens.backtrack()
-        while op == '*' or op == '/':
+        while op == c'*' or op == c'/':
             operand2 = self.p_factor(tokens)
-            if op == '*':
+            if op == c'*':
                 operand1 = operand1 * operand2
             else:
                 operand1 = operand1 / operand2
             op = tokens.next()
             if op == NAME and self.implicit_multiplication:
-                op = '*'
+                op = c'*'
                 tokens.backtrack()
         tokens.backtrack()
         return operand1
@@ -826,9 +826,9 @@ cdef class Parser:
             t^11
         """
         cdef int token = tokens.next()
-        if token == '+':
+        if token == c'+':
             return self.p_factor(tokens)
-        elif token == '-':
+        elif token == c'-':
             return -self.p_factor(tokens)
         else:
             tokens.backtrack()
@@ -862,13 +862,13 @@ cdef class Parser:
         """
         operand1 = self.p_atom(tokens)
         cdef int token = tokens.next()
-        if token == '^':
+        if token == c'^':
             operand2 = self.p_factor(tokens)
             return operand1 ** operand2
-        elif token == "!":
+        elif token == c"!":
             from sage.functions.all import factorial
             operand1 = factorial(operand1)
-            if tokens.peek() == '^':
+            if tokens.peek() == c'^':
                 tokens.next()
                 operand2 = self.p_factor(tokens)
                 return operand1 ** operand2
@@ -913,20 +913,20 @@ cdef class Parser:
         elif token == NAME:
             name = tokens.last_token_string()
             token = tokens.next()
-            if token == '(':
+            if token == c'(':
                 func = self.callable_constructor(name)
                 args, kwds = self.p_args(tokens)
                 token = tokens.next()
-                if token != ')':
+                if token != c')':
                     self.parse_error(tokens, "Bad function call")
                 return func(*args, **kwds)
             else:
                 tokens.backtrack()
                 return self.variable_constructor(name)
-        elif token == '(':
+        elif token == c'(':
             expr = self.p_expr(tokens)
             token = tokens.next()
-            if token != ')':
+            if token != c')':
                 self.parse_error(tokens, "Mismatched parentheses")
             return expr
         else:
@@ -948,10 +948,10 @@ cdef class Parser:
         """
         args = []
         kwds = {}
-        if tokens.peek() == ')':
+        if tokens.peek() == c')':
             return args, kwds
-        cdef int token = ','
-        while token == ',':
+        cdef int token = c','
+        while token == c',':
             arg = self.p_arg(tokens)
             if isinstance(arg, tuple):
                 name, value = arg
@@ -993,11 +993,11 @@ cdef class Parser:
 
         """
         cdef int token = tokens.next()
-        if token == NAME and tokens.peek() == '=':
+        if token == NAME and tokens.peek() == c'=':
             name = tokens.last_token_string()
             tokens.next()
             return name, self.p_expr(tokens)
-        if token == "[" :
+        if token == c"[" :
             tokens.backtrack()
             return self.p_list(tokens)
         else:
diff -up src/sage/misc/sageinspect.py.orig src/sage/misc/sageinspect.py
--- src/sage/misc/sageinspect.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/misc/sageinspect.py	2020-07-09 16:11:23.134895309 -0600
@@ -485,35 +485,46 @@ class SageArgSpecVisitor(ast.NodeVisitor
                 return False
         return node.id
 
-    if six.PY3:
-        def visit_NameConstant(self, node):
-            """
-            Visit a Python AST :class:`ast.NameConstant` node.
+    def visit_Constant(self, node):
+        r"""
+        Visit a Python AST :class:`ast.Constant` node.
 
-            This is an optimization added in Python 3.4 for the special cases
-            of True, False, and None.
+        INPUT:
 
-            INPUT:
+        - ``node`` - the node instance to visit
 
-            - ``node`` - the node instance to visit
+        OUTPUT:
 
-            OUTPUT:
+        - the boolean, number, or string the ``node`` represents
 
-            - None, True, False.
+        EXAMPLES::
 
-            EXAMPLES::
+            sage: import ast, sage.misc.sageinspect as sms
+            sage: visitor = sms.SageArgSpecVisitor()
+            sage: vis = lambda x: visitor.visit_Constant(ast.parse(x).body[0].value)
+            sage: [vis(n) for n in ['True', 'False', 'None']]
+            [True, False, None]
+            sage: [type(vis(n)) for n in ['True', 'False', 'None']]
+            [<type 'bool'>, <type 'bool'>, <type 'NoneType'>]
 
-                sage: import ast, sage.misc.sageinspect as sms  # py3
-                sage: visitor = sms.SageArgSpecVisitor()  # py3
-                sage: vis = lambda x: visitor.visit_NameConstant(ast.parse(x).body[0].value)  # py3
-                sage: [vis(n) for n in ['True', 'False', 'None']]  # py3
-                [True, False, None]
-                sage: [type(vis(n)) for n in ['True', 'False', 'None']]  # py3
-                [<type 'bool'>, <type 'bool'>, <type 'NoneType'>]
-            """
+            sage: vis = lambda x: visitor.visit_Constant(ast.parse(x).body[0].value)
+            sage: [vis(s) for s in ['"abstract"', "u'syntax'", r'''r"tr\ee"''']]
+            ['abstract', u'syntax', 'tr\\ee']
 
-            return node.value
+            sage: vis = lambda x: visitor.visit_Constant(ast.parse(x).body[0].value)
+            sage: [vis(n) for n in ['123', '0.0', str(-pi.n())]]  # py2
+            [123, 0.0, -3.14159265358979]
+            sage: [vis(n) for n in ['123', '0.0']]  # py3
+            [123, 0.0]
+
+        .. NOTE::
 
+            On Python 3 negative numbers are parsed first, for some reason, as
+            a UnaryOp node.
+        """
+        return node.value
+
+    if six.PY3:
         def visit_arg(self, node):
             r"""
             Visit a Python AST :class:`ast.arg` node.
@@ -543,57 +554,6 @@ class SageArgSpecVisitor(ast.NodeVisitor
             """
             return node.arg
 
-    def visit_Num(self, node):
-        """
-        Visit a Python AST :class:`ast.Num` node.
-
-        INPUT:
-
-        - ``node`` - the node instance to visit
-
-        OUTPUT:
-
-        - the number the ``node`` represents
-
-        EXAMPLES::
-
-            sage: import ast, sage.misc.sageinspect as sms
-            sage: visitor = sms.SageArgSpecVisitor()
-            sage: vis = lambda x: visitor.visit_Num(ast.parse(x).body[0].value)
-            sage: [vis(n) for n in ['123', '0.0', str(-pi.n())]]  # py2
-            [123, 0.0, -3.14159265358979]
-            sage: [vis(n) for n in ['123', '0.0']]  # py3
-            [123, 0.0]
-
-        .. NOTE::
-
-            On Python 3 negative numbers are parsed first, for some reason, as
-            a UnaryOp node.
-        """
-        return node.n
-
-    def visit_Str(self, node):
-        r"""
-        Visit a Python AST :class:`ast.Str` node.
-
-        INPUT:
-
-        - ``node`` - the node instance to visit
-
-        OUTPUT:
-
-        - the string the ``node`` represents
-
-        EXAMPLES::
-
-            sage: import ast, sage.misc.sageinspect as sms
-            sage: visitor = sms.SageArgSpecVisitor()
-            sage: vis = lambda x: visitor.visit_Str(ast.parse(x).body[0].value)
-            sage: [vis(s) for s in ['"abstract"', "u'syntax'", r'''r"tr\ee"''']]
-            ['abstract', u'syntax', 'tr\\ee']
-        """
-        return node.s
-
     def visit_List(self, node):
         """
         Visit a Python AST :class:`ast.List` node.
diff -up src/sage/plot/plot3d/plot3d.py.orig src/sage/plot/plot3d/plot3d.py
--- src/sage/plot/plot3d/plot3d.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/plot/plot3d/plot3d.py	2020-07-06 16:48:01.183121035 -0600
@@ -188,7 +188,8 @@ class _Coordinates(object):
             sage: arb((x+z,y*z,z), z, (x,y))
             Arbitrary Coordinates coordinate transform (z in terms of x, y)
         """
-        all_vars = sage_getargspec(self.transform).args[1:]
+        args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = inspect.getfullargspec(self.transform)
+        all_vars=args[1:]
         if set(all_vars) != set(indep_vars + [dep_var]):
             raise ValueError('variables were specified incorrectly for this coordinate system; incorrect variables were %s'%list(set(all_vars).symmetric_difference(set(indep_vars+[dep_var]))))
         self.dep_var = dep_var
diff -up src/sage/plot/point.py.orig src/sage/plot/point.py
--- src/sage/plot/point.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/plot/point.py	2020-07-06 16:48:01.184121035 -0600
@@ -29,7 +29,7 @@ TESTS::
 from sage.misc.decorators import options, rename_keyword
 from sage.plot.colors import to_mpl_color
 from sage.plot.primitive import GraphicPrimitive_xydata
-import collections
+import collections.abc
 
 
 # TODO: create _allowed_options for 3D point classes to
@@ -343,7 +343,7 @@ def point(points, **kwds):
         sage: point(iter([(1,2),(3,5)]))
         Graphics object consisting of 1 graphics primitive
     """
-    if isinstance(points, collections.Iterator):
+    if isinstance(points, collections.abc.Iterator):
         points = list(points)
 
     try:
diff -up src/sage/repl/display/fancy_repr.py.orig src/sage/repl/display/fancy_repr.py
--- src/sage/repl/display/fancy_repr.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/repl/display/fancy_repr.py	2020-07-06 16:48:01.184121035 -0600
@@ -15,7 +15,7 @@ Representations of objects
 import types
 
 from IPython.lib.pretty import (
-    _safe_getattr, _baseclass_reprs,
+    _safe_getattr,
     _type_pprinters,
 )
 
@@ -264,7 +264,7 @@ class PlainPythonRepr(ObjectReprABC):
         """
         klass = _safe_getattr(obj, '__class__', None) or type(obj)
         klass_repr = _safe_getattr(klass, '__repr__', None)
-        if klass_repr in _baseclass_reprs:
+        if klass_repr is object.__repr__:
             p.text(klass_repr(obj))
         else:
             # A user-provided repr. Find newlines and replace them with p.break_()
diff -up src/sage/repl/ipython_kernel/interact.py.orig src/sage/repl/ipython_kernel/interact.py
--- src/sage/repl/ipython_kernel/interact.py.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/repl/ipython_kernel/interact.py	2020-07-06 16:48:01.185121034 -0600
@@ -35,7 +35,8 @@ EXAMPLES::
 
 from ipywidgets.widgets import SelectionSlider, ValueWidget, ToggleButtons
 from ipywidgets.widgets.interaction import interactive, signature
-from collections import Iterable, Iterator, OrderedDict
+from collections.abc import Iterable, Iterator
+from collections import OrderedDict
 from .widgets import EvalText, SageColorPicker
 from .widgets_sagenb import input_grid
 from sage.structure.element import parent
diff -up src/sage/rings/integer.pyx.orig src/sage/rings/integer.pyx
--- src/sage/rings/integer.pyx.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/rings/integer.pyx	2020-07-06 16:48:01.187121034 -0600
@@ -7135,7 +7135,7 @@ cdef int mpz_set_str_python(mpz_ptr z, c
     while x[0] == c' ': x += 1  # Strip spaces
 
     # Disallow a sign here
-    if x[0] == '-' or x[0] == '+':
+    if x[0] == c'-' or x[0] == c'+':
         x = ""  # Force an error below
 
     assert base >= 2
diff -up src/sage/rings/polynomial/pbori.pyx.orig src/sage/rings/polynomial/pbori.pyx
--- src/sage/rings/polynomial/pbori.pyx.orig	2020-07-06 16:13:17.464497408 -0600
+++ src/sage/rings/polynomial/pbori.pyx	2020-07-06 16:48:01.190121033 -0600
@@ -4764,8 +4764,7 @@ cdef class PolynomialConstruct:
             # So, it is just a conversion. [Simon King]
             return (<BooleanPolynomialRing>ring)._element_constructor_(x)
 
-        raise TypeError("Cannot generate Boolean polynomial from %s , %s" %
-                        (type(x), type(ring)))
+        raise TypeError(f"Cannot generate Boolean polynomial from {type(x)}, {type(ring)}")
 
 
 cdef class MonomialConstruct:
diff -up src/sage/rings/real_mpfi.pyx.orig src/sage/rings/real_mpfi.pyx
--- src/sage/rings/real_mpfi.pyx.orig	2020-07-06 16:19:17.719457638 -0600
+++ src/sage/rings/real_mpfi.pyx	2020-07-06 16:48:01.192121033 -0600
@@ -1941,12 +1941,12 @@ cdef class RealIntervalFieldElement(Ring
 
         cdef long digits
         digits = strlen(lower_s)
-        if lower_s[0] == '-':
+        if lower_s[0] == c'-':
             digits -= 1
         lower_expo -= digits
 
         digits = strlen(upper_s)
-        if upper_s[0] == '-':
+        if upper_s[0] == c'-':
             digits -= 1
         upper_expo -= digits
 
@@ -2115,7 +2115,7 @@ cdef class RealIntervalFieldElement(Ring
             raise MemoryError("Unable to allocate memory for the mantissa of an interval")
         mpz_get_str(tmp_cstr, base, lower_mpz)
         digits = strlen(tmp_cstr)
-        if tmp_cstr[0] == '-':
+        if tmp_cstr[0] == c'-':
             digits -= 1
             mant_string = bytes_to_str(tmp_cstr+1)
             sign_string = bytes_to_str(b'-')
diff -up src/sage/rings/real_mpfr.pyx.orig src/sage/rings/real_mpfr.pyx
--- src/sage/rings/real_mpfr.pyx.orig	2020-07-06 16:19:17.720457638 -0600
+++ src/sage/rings/real_mpfr.pyx	2020-07-06 16:48:01.194121032 -0600
@@ -2045,7 +2045,7 @@ cdef class RealNumber(sage.structure.ele
         if s is NULL:
             raise RuntimeError("unable to convert an mpfr number to a string")
         # t contains just digits (no sign, decimal point or exponent)
-        if s[0] == '-':
+        if s[0] == c'-':
             sgn = "-"
             t = char_to_str(s + 1)
         else:
diff -up src/sage/structure/sage_object.pyx.orig src/sage/structure/sage_object.pyx
--- src/sage/structure/sage_object.pyx.orig	2020-05-20 16:33:41.000000000 -0600
+++ src/sage/structure/sage_object.pyx	2020-07-06 16:48:01.194121032 -0600
@@ -680,7 +680,7 @@ cdef class SageObject:
             try:
                 s = self._interface_init_(I)
             except Exception:
-                raise NotImplementedError("coercion of object %s to %s not implemented:\n%s\n%s" % (repr(self), I))
+                raise NotImplementedError(f"coercion of object {repr(self)} to {I} not implemented")
         X = I(s)
         if c:
             try:
diff -up src/sage/symbolic/expression.pyx.orig src/sage/symbolic/expression.pyx
--- src/sage/symbolic/expression.pyx.orig	2020-07-06 16:22:36.515435688 -0600
+++ src/sage/symbolic/expression.pyx	2020-07-06 16:48:01.198121032 -0600
@@ -12990,7 +12990,7 @@ cdef class hold_class:
             sage: SR(2)^5
             32
         """
-        g_set_state('hold', True)
+        g_set_state(b'hold', True)
 
     def __exit__(self, *args):
         """
@@ -13003,7 +13003,7 @@ cdef class hold_class:
             sage: SR(2)^5
             32
         """
-        g_set_state('hold', False)
+        g_set_state(b'hold', False)
 
     def start(self):
         """
diff -up src/sage/symbolic/ring.pyx.orig src/sage/symbolic/ring.pyx
--- src/sage/symbolic/ring.pyx.orig	2020-07-06 16:20:02.592452688 -0600
+++ src/sage/symbolic/ring.pyx	2020-07-10 09:09:09.512400345 -0600
@@ -32,7 +32,6 @@ from sage.rings.all import RR, CC, ZZ
 
 import keyword
 import operator
-import parser
 
 # Do not allow any of these keywords as identifiers for symbolic variables
 KEYWORDS = set(keyword.kwlist).union(['exec', 'print', 'None', 'True',
@@ -1405,8 +1404,8 @@ def isidentifier(x):
         pass  # py2
 
     try:
-        code = parser.expr(x).compile()
+        code = compile(x, '<string>', 'eval')
     except (MemoryError, OverflowError, SyntaxError,
-            SystemError, parser.ParserError):
+            SystemError, ValueError):
         return False
     return len(code.co_names) == 1 and code.co_names[0] == x