Skip to content

Commit 00b9047

Browse files
author
Release Manager
committed
gh-37004: Fixes in save_session() 1. fix test for cython functions in save_session() This fixes #37003 2. fix handling of lazy import variables in save_session() This fixes #37002 3. remove unused `extra_globals` attribute in class DocTestTask This was introduced for the transition from python 2 to 3, no longer used 4. don't sort the output of `sage.misc.session.show_identifiers()` There's no need to sort here... sorting was introduced in baedc41 in order to fix doctest errors, but dictionaries now keep the insertion order. Thus `show_identifiers()` will return the variables in the order they were introduced for the first time which seems reasonable and it's fine to test. ### 📝 Checklist - [x] The title is concise, informative, and self-explanatory. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. Fixes: #37002, #37003 URL: #37004 Reported by: Gonzalo Tornaría Reviewer(s): Frédéric Chapoton
2 parents 0dbab3c + 2673c8b commit 00b9047

File tree

2 files changed

+40
-43
lines changed

2 files changed

+40
-43
lines changed

src/sage/doctest/forker.py

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2489,19 +2489,6 @@ class DocTestTask():
24892489
['cputime', 'err', 'failures', 'optionals', 'tests', 'walltime', 'walltime_skips']
24902490
"""
24912491

2492-
extra_globals = {}
2493-
"""
2494-
Extra objects to place in the global namespace in which tests are run.
2495-
Normally this should be empty but there are special cases where it may
2496-
be useful.
2497-
2498-
For example, in Sage versions 9.1 and earlier, on Python 3 add
2499-
``long`` as an alias for ``int`` so that tests that use the
2500-
``long`` built-in (of which there are many) still pass. We did
2501-
this so that the test suite could run on Python 3 while Python 2
2502-
was still the default.
2503-
"""
2504-
25052492
def __init__(self, source):
25062493
"""
25072494
Initialization.
@@ -2630,10 +2617,6 @@ def _run(self, runner, options, results):
26302617
# Remove '__package__' item from the globals since it is not
26312618
# always in the globals in an actual Sage session.
26322619
dict_all.pop('__package__', None)
2633-
2634-
# Add any other special globals for testing purposes only
2635-
dict_all.update(self.extra_globals)
2636-
26372620
sage_namespace = RecordingDict(dict_all)
26382621
sage_namespace['__name__'] = '__main__'
26392622
doctests, extras = self.source.create_doctests(sage_namespace)

src/sage/misc/session.pyx

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ This saves a dictionary with ``w`` as one of the keys::
2727
2828
sage: z = load(os.path.join(d.name, 'session'))
2929
sage: list(z)
30-
['d', 'w']
30+
['w', 'd']
3131
sage: z['w']
3232
2/3
3333
@@ -68,19 +68,19 @@ AUTHOR:
6868
import builtins
6969
import types
7070

71-
# We want the caller's locals, but locals() is emulated in Cython
72-
cdef caller_locals = builtins.locals
73-
7471
# Sage imports
7572
from sage.misc.persist import load, save, loads, dumps
73+
from sage.misc.lazy_import import LazyImport
74+
75+
# We want the caller's locals, but locals() is emulated in Cython
76+
cdef caller_locals = builtins.locals
7677

7778
# This module-scope variables is used to save the
7879
# global state of the sage environment at the moment
7980
# before the user starts typing or running code.
8081

8182
state_at_init = None
8283

83-
CythonFunctionType = type(lambda: None)
8484

8585
def init(state=None):
8686
"""
@@ -163,9 +163,13 @@ def _is_new_var(x, v, hidden):
163163
# definitely new.
164164
if x not in state_at_init:
165165
return True
166+
# A lazy import that was there at init time is not new
167+
if isinstance(v, LazyImport):
168+
return False
166169
# A variable could also be new even if it was there at init, say if
167170
# its value changed.
168-
return x not in state_at_init or state_at_init[x] is not v
171+
return state_at_init[x] is not v
172+
169173

170174
def show_identifiers(hidden=False):
171175
r"""
@@ -196,7 +200,7 @@ def show_identifiers(hidden=False):
196200
sage: a = 10
197201
sage: factor = 20
198202
sage: show_identifiers()
199-
['a', 'factor']
203+
['factor', 'a']
200204
201205
To get the actual value of a variable from the list, use the
202206
:func:`globals()` function.::
@@ -210,27 +214,21 @@ def show_identifiers(hidden=False):
210214
211215
sage: _hello = 10
212216
sage: show_identifiers()
213-
['a', 'factor']
217+
['factor', 'a']
214218
sage: '_hello' in show_identifiers(hidden=True)
215219
True
216220
217221
Many of the hidden variables are part of the IPython command history, at
218222
least in command line mode.::
219223
220224
sage: show_identifiers(hidden=True) # random output
221-
['__', '_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']
225+
['__builtin__', '_ih', '_oh', '_dh', 'exit', 'quit', '_', '__', '___',
226+
'_i', '_ii', '_iii', '_i1', 'factor', '_i2', '_2', '_i3', 'a', '_i4',
227+
'_i5', '_5', '_i6', '_6', '_i7', '_hello', '_i8', '_8', '_i9', '_9',
228+
'_i10']
222229
"""
223-
from sage.doctest.forker import DocTestTask
224230
state = caller_locals()
225-
# Ignore extra variables injected into the global namespace by the doctest
226-
# runner
227-
_none = object()
228-
229-
def _in_extra_globals(name, val):
230-
return val == DocTestTask.extra_globals.get(name, _none)
231-
232-
return sorted([x for x, v in state.items() if _is_new_var(x, v, hidden)
233-
and not _in_extra_globals(x, v)])
231+
return [x for x, v in state.items() if _is_new_var(x, v, hidden)]
234232

235233

236234
def save_session(name='sage_session', verbose=False):
@@ -293,28 +291,44 @@ def save_session(name='sage_session', verbose=False):
293291
sage: f = lambda x : x^2
294292
sage: save_session(tmp_f)
295293
sage: save_session(tmp_f, verbose=True)
296-
Saving...
297-
Not saving f: f is a function, method, class or type
298294
...
295+
Not saving f: f is a function or method
299296
300297
Something similar happens for cython-defined functions::
301298
302299
sage: g = cython_lambda('double x', 'x*x + 1.5')
303300
sage: save_session(tmp_f, verbose=True)
304-
Saving...
305-
Not saving g: g is a function, method, class or type
306301
...
302+
Not saving g: g is a cython function or method
303+
304+
And the same for a lazy import::
305+
306+
sage: from sage.misc.lazy_import import LazyImport
307+
sage: lazy_ZZ = LazyImport('sage.rings.integer_ring', 'ZZ')
308+
sage: save_session(tmp_f, verbose=True)
309+
...
310+
Not saving lazy_ZZ: lazy_ZZ is a lazy import
307311
"""
308312
state = caller_locals()
309313
# This dict D will contain the session -- as a dict -- that we will save to disk.
310314
D = {}
311315
# We iterate only over the new variables that were defined in this
312316
# session, since those are the only ones we will save.
313-
for k in show_identifiers(hidden = True):
317+
for k in show_identifiers(hidden=True):
314318
try:
315319
x = state[k]
316-
if isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.BuiltinMethodType, CythonFunctionType, type)):
317-
raise TypeError('{} is a function, method, class or type'.format(k))
320+
321+
if isinstance(x, type):
322+
raise TypeError('{} is a class or type'.format(k))
323+
324+
if isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.BuiltinMethodType)):
325+
raise TypeError('{} is a function or method'.format(k))
326+
327+
if getattr(type(x), '__name__', None) == 'cython_function_or_method':
328+
raise TypeError('{} is a cython function or method'.format(k))
329+
330+
if isinstance(x, LazyImport):
331+
raise TypeError('{} is a lazy import'.format(k))
318332

319333
# We attempt to pickle *and* unpickle every variable to
320334
# make *certain* that we can pickled D at the end below.

0 commit comments

Comments
 (0)