void-packages/srcpkgs/sagemath/patches/37004-fix_save_session_when...

183 lines
6.9 KiB
Diff

diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py
index efd28d10abe..56a9fe5e8f6 100644
--- a/src/sage/doctest/forker.py
+++ b/src/sage/doctest/forker.py
@@ -2477,19 +2477,6 @@ class DocTestTask():
['cputime', 'err', 'failures', 'optionals', 'tests', 'walltime', 'walltime_skips']
"""
- extra_globals = {}
- """
- Extra objects to place in the global namespace in which tests are run.
- Normally this should be empty but there are special cases where it may
- be useful.
-
- For example, in Sage versions 9.1 and earlier, on Python 3 add
- ``long`` as an alias for ``int`` so that tests that use the
- ``long`` built-in (of which there are many) still pass. We did
- this so that the test suite could run on Python 3 while Python 2
- was still the default.
- """
-
def __init__(self, source):
"""
Initialization.
@@ -2614,10 +2601,6 @@ def _run(self, runner, options, results):
# Remove '__package__' item from the globals since it is not
# always in the globals in an actual Sage session.
dict_all.pop('__package__', None)
-
- # Add any other special globals for testing purposes only
- dict_all.update(self.extra_globals)
-
sage_namespace = RecordingDict(dict_all)
sage_namespace['__name__'] = '__main__'
doctests, extras = self.source.create_doctests(sage_namespace)
diff --git a/src/sage/misc/session.pyx b/src/sage/misc/session.pyx
index 31454dac993..53b732309da 100644
--- a/src/sage/misc/session.pyx
+++ b/src/sage/misc/session.pyx
@@ -27,7 +27,7 @@ This saves a dictionary with ``w`` as one of the keys::
sage: z = load(os.path.join(d.name, 'session'))
sage: list(z)
- ['d', 'w']
+ ['w', 'd']
sage: z['w']
2/3
@@ -68,11 +68,12 @@ AUTHOR:
import builtins
import types
-# We want the caller's locals, but locals() is emulated in Cython
-cdef caller_locals = builtins.locals
-
# Sage imports
from sage.misc.persist import load, save, loads, dumps
+from sage.misc.lazy_import import LazyImport
+
+# We want the caller's locals, but locals() is emulated in Cython
+cdef caller_locals = builtins.locals
# This module-scope variables is used to save the
# global state of the sage environment at the moment
@@ -80,7 +81,6 @@ from sage.misc.persist import load, save, loads, dumps
state_at_init = None
-CythonFunctionType = type(lambda: None)
def init(state=None):
"""
@@ -163,9 +163,13 @@ def _is_new_var(x, v, hidden):
# definitely new.
if x not in state_at_init:
return True
+ # A lazy import that was there at init time is not new
+ if isinstance(v, LazyImport):
+ return False
# A variable could also be new even if it was there at init, say if
# its value changed.
- return x not in state_at_init or state_at_init[x] is not v
+ return state_at_init[x] is not v
+
def show_identifiers(hidden=False):
r"""
@@ -196,7 +200,7 @@ def show_identifiers(hidden=False):
sage: a = 10
sage: factor = 20
sage: show_identifiers()
- ['a', 'factor']
+ ['factor', 'a']
To get the actual value of a variable from the list, use the
:func:`globals()` function.::
@@ -210,7 +214,7 @@ def show_identifiers(hidden=False):
sage: _hello = 10
sage: show_identifiers()
- ['a', 'factor']
+ ['factor', 'a']
sage: '_hello' in show_identifiers(hidden=True)
True
@@ -218,19 +222,13 @@ def show_identifiers(hidden=False):
least in command line mode.::
sage: show_identifiers(hidden=True) # random output
- ['__', '_i', '_6', '_4', '_3', '_1', '_ii', '__doc__', '__builtins__', '___', '_9', '__name__', '_', 'a', '_i12', '_i14', 'factor', '__file__', '_hello', '_i13', '_i11', '_i10', '_i15', '_i5', '_13', '_10', '_iii', '_i9', '_i8', '_i7', '_i6', '_i4', '_i3', '_i2', '_i1', '_init_cmdline', '_14']
+ ['__builtin__', '_ih', '_oh', '_dh', 'exit', 'quit', '_', '__', '___',
+ '_i', '_ii', '_iii', '_i1', 'factor', '_i2', '_2', '_i3', 'a', '_i4',
+ '_i5', '_5', '_i6', '_6', '_i7', '_hello', '_i8', '_8', '_i9', '_9',
+ '_i10']
"""
- from sage.doctest.forker import DocTestTask
state = caller_locals()
- # Ignore extra variables injected into the global namespace by the doctest
- # runner
- _none = object()
-
- def _in_extra_globals(name, val):
- return val == DocTestTask.extra_globals.get(name, _none)
-
- return sorted([x for x, v in state.items() if _is_new_var(x, v, hidden)
- and not _in_extra_globals(x, v)])
+ return [x for x, v in state.items() if _is_new_var(x, v, hidden)]
def save_session(name='sage_session', verbose=False):
@@ -293,28 +291,44 @@ def save_session(name='sage_session', verbose=False):
sage: f = lambda x : x^2
sage: save_session(tmp_f)
sage: save_session(tmp_f, verbose=True)
- Saving...
- Not saving f: f is a function, method, class or type
...
+ Not saving f: f is a function or method
Something similar happens for cython-defined functions::
sage: g = cython_lambda('double x', 'x*x + 1.5')
sage: save_session(tmp_f, verbose=True)
- Saving...
- Not saving g: g is a function, method, class or type
...
+ Not saving g: g is a cython function or method
+
+ And the same for a lazy import::
+
+ sage: from sage.misc.lazy_import import LazyImport
+ sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
+ sage: save_session(tmp_f, verbose=True)
+ ...
+ Not saving lazy_ZZ: lazy_ZZ is a lazy import
"""
state = caller_locals()
# This dict D will contain the session -- as a dict -- that we will save to disk.
D = {}
# We iterate only over the new variables that were defined in this
# session, since those are the only ones we will save.
- for k in show_identifiers(hidden = True):
+ for k in show_identifiers(hidden=True):
try:
x = state[k]
- if isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.BuiltinMethodType, CythonFunctionType, type)):
- raise TypeError('{} is a function, method, class or type'.format(k))
+
+ if isinstance(x, type):
+ raise TypeError('{} is a class or type'.format(k))
+
+ if isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.BuiltinMethodType)):
+ raise TypeError('{} is a function or method'.format(k))
+
+ if getattr(type(x), '__name__', None) == 'cython_function_or_method':
+ raise TypeError('{} is a cython function or method'.format(k))
+
+ if isinstance(x, LazyImport):
+ raise TypeError('{} is a lazy import'.format(k))
# We attempt to pickle *and* unpickle every variable to
# make *certain* that we can pickled D at the end below.