passagemath-repl 10.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. passagemath_repl-10.5.1.data/scripts/sage-cachegrind +25 -0
  2. passagemath_repl-10.5.1.data/scripts/sage-callgrind +16 -0
  3. passagemath_repl-10.5.1.data/scripts/sage-cleaner +230 -0
  4. passagemath_repl-10.5.1.data/scripts/sage-coverage +327 -0
  5. passagemath_repl-10.5.1.data/scripts/sage-eval +14 -0
  6. passagemath_repl-10.5.1.data/scripts/sage-fixdoctests +710 -0
  7. passagemath_repl-10.5.1.data/scripts/sage-inline-fortran +12 -0
  8. passagemath_repl-10.5.1.data/scripts/sage-ipynb2rst +50 -0
  9. passagemath_repl-10.5.1.data/scripts/sage-ipython +16 -0
  10. passagemath_repl-10.5.1.data/scripts/sage-massif +25 -0
  11. passagemath_repl-10.5.1.data/scripts/sage-notebook +267 -0
  12. passagemath_repl-10.5.1.data/scripts/sage-omega +25 -0
  13. passagemath_repl-10.5.1.data/scripts/sage-preparse +302 -0
  14. passagemath_repl-10.5.1.data/scripts/sage-run +27 -0
  15. passagemath_repl-10.5.1.data/scripts/sage-run-cython +10 -0
  16. passagemath_repl-10.5.1.data/scripts/sage-runtests +9 -0
  17. passagemath_repl-10.5.1.data/scripts/sage-startuptime.py +163 -0
  18. passagemath_repl-10.5.1.data/scripts/sage-valgrind +34 -0
  19. passagemath_repl-10.5.1.dist-info/METADATA +77 -0
  20. passagemath_repl-10.5.1.dist-info/RECORD +162 -0
  21. passagemath_repl-10.5.1.dist-info/WHEEL +5 -0
  22. passagemath_repl-10.5.1.dist-info/top_level.txt +1 -0
  23. sage/all__sagemath_repl.py +119 -0
  24. sage/doctest/__init__.py +4 -0
  25. sage/doctest/__main__.py +236 -0
  26. sage/doctest/all.py +4 -0
  27. sage/doctest/check_tolerance.py +261 -0
  28. sage/doctest/control.py +1727 -0
  29. sage/doctest/external.py +534 -0
  30. sage/doctest/fixtures.py +383 -0
  31. sage/doctest/forker.py +2665 -0
  32. sage/doctest/marked_output.py +102 -0
  33. sage/doctest/parsing.py +1708 -0
  34. sage/doctest/parsing_test.py +79 -0
  35. sage/doctest/reporting.py +733 -0
  36. sage/doctest/rif_tol.py +124 -0
  37. sage/doctest/sources.py +1657 -0
  38. sage/doctest/test.py +584 -0
  39. sage/doctest/tests/1second.rst +4 -0
  40. sage/doctest/tests/99seconds.rst +4 -0
  41. sage/doctest/tests/abort.rst +5 -0
  42. sage/doctest/tests/atexit.rst +7 -0
  43. sage/doctest/tests/fail_and_die.rst +6 -0
  44. sage/doctest/tests/initial.rst +15 -0
  45. sage/doctest/tests/interrupt.rst +7 -0
  46. sage/doctest/tests/interrupt_diehard.rst +14 -0
  47. sage/doctest/tests/keyboardinterrupt.rst +11 -0
  48. sage/doctest/tests/longtime.rst +5 -0
  49. sage/doctest/tests/nodoctest +5 -0
  50. sage/doctest/tests/random_seed.rst +4 -0
  51. sage/doctest/tests/show_skipped.rst +18 -0
  52. sage/doctest/tests/sig_on.rst +9 -0
  53. sage/doctest/tests/simple_failure.rst +8 -0
  54. sage/doctest/tests/sleep_and_raise.rst +106 -0
  55. sage/doctest/tests/tolerance.rst +31 -0
  56. sage/doctest/util.py +750 -0
  57. sage/interfaces/cleaner.py +48 -0
  58. sage/interfaces/quit.py +163 -0
  59. sage/misc/all__sagemath_repl.py +51 -0
  60. sage/misc/banner.py +235 -0
  61. sage/misc/benchmark.py +221 -0
  62. sage/misc/classgraph.py +134 -0
  63. sage/misc/copying.py +22 -0
  64. sage/misc/cython.py +694 -0
  65. sage/misc/dev_tools.py +745 -0
  66. sage/misc/edit_module.py +304 -0
  67. sage/misc/explain_pickle.py +3079 -0
  68. sage/misc/gperftools.py +361 -0
  69. sage/misc/inline_fortran.py +212 -0
  70. sage/misc/messaging.py +86 -0
  71. sage/misc/pager.py +21 -0
  72. sage/misc/profiler.py +179 -0
  73. sage/misc/python.py +70 -0
  74. sage/misc/remote_file.py +53 -0
  75. sage/misc/sage_eval.py +249 -0
  76. sage/misc/sage_input.py +3621 -0
  77. sage/misc/sagedoc.py +1742 -0
  78. sage/misc/sh.py +38 -0
  79. sage/misc/trace.py +90 -0
  80. sage/repl/__init__.py +16 -0
  81. sage/repl/all.py +15 -0
  82. sage/repl/attach.py +625 -0
  83. sage/repl/configuration.py +186 -0
  84. sage/repl/display/__init__.py +1 -0
  85. sage/repl/display/fancy_repr.py +354 -0
  86. sage/repl/display/formatter.py +318 -0
  87. sage/repl/display/jsmol_iframe.py +290 -0
  88. sage/repl/display/pretty_print.py +153 -0
  89. sage/repl/display/util.py +163 -0
  90. sage/repl/image.py +302 -0
  91. sage/repl/inputhook.py +91 -0
  92. sage/repl/interface_magic.py +298 -0
  93. sage/repl/interpreter.py +854 -0
  94. sage/repl/ipython_extension.py +593 -0
  95. sage/repl/ipython_kernel/__init__.py +1 -0
  96. sage/repl/ipython_kernel/__main__.py +4 -0
  97. sage/repl/ipython_kernel/all_jupyter.py +10 -0
  98. sage/repl/ipython_kernel/install.py +301 -0
  99. sage/repl/ipython_kernel/interact.py +278 -0
  100. sage/repl/ipython_kernel/kernel.py +217 -0
  101. sage/repl/ipython_kernel/widgets.py +466 -0
  102. sage/repl/ipython_kernel/widgets_sagenb.py +587 -0
  103. sage/repl/ipython_tests.py +163 -0
  104. sage/repl/load.py +326 -0
  105. sage/repl/preparse.py +2218 -0
  106. sage/repl/prompts.py +90 -0
  107. sage/repl/rich_output/__init__.py +4 -0
  108. sage/repl/rich_output/backend_base.py +648 -0
  109. sage/repl/rich_output/backend_doctest.py +316 -0
  110. sage/repl/rich_output/backend_emacs.py +151 -0
  111. sage/repl/rich_output/backend_ipython.py +596 -0
  112. sage/repl/rich_output/buffer.py +311 -0
  113. sage/repl/rich_output/display_manager.py +829 -0
  114. sage/repl/rich_output/example.avi +0 -0
  115. sage/repl/rich_output/example.canvas3d +1 -0
  116. sage/repl/rich_output/example.dvi +0 -0
  117. sage/repl/rich_output/example.flv +0 -0
  118. sage/repl/rich_output/example.gif +0 -0
  119. sage/repl/rich_output/example.jpg +0 -0
  120. sage/repl/rich_output/example.mkv +0 -0
  121. sage/repl/rich_output/example.mov +0 -0
  122. sage/repl/rich_output/example.mp4 +0 -0
  123. sage/repl/rich_output/example.ogv +0 -0
  124. sage/repl/rich_output/example.pdf +0 -0
  125. sage/repl/rich_output/example.png +0 -0
  126. sage/repl/rich_output/example.svg +54 -0
  127. sage/repl/rich_output/example.webm +0 -0
  128. sage/repl/rich_output/example.wmv +0 -0
  129. sage/repl/rich_output/example_jmol.spt.zip +0 -0
  130. sage/repl/rich_output/example_wavefront_scene.mtl +7 -0
  131. sage/repl/rich_output/example_wavefront_scene.obj +17 -0
  132. sage/repl/rich_output/output_basic.py +391 -0
  133. sage/repl/rich_output/output_browser.py +103 -0
  134. sage/repl/rich_output/output_catalog.py +54 -0
  135. sage/repl/rich_output/output_graphics.py +320 -0
  136. sage/repl/rich_output/output_graphics3d.py +345 -0
  137. sage/repl/rich_output/output_video.py +231 -0
  138. sage/repl/rich_output/preferences.py +432 -0
  139. sage/repl/rich_output/pretty_print.py +339 -0
  140. sage/repl/rich_output/test_backend.py +201 -0
  141. sage/repl/user_globals.py +214 -0
  142. sage/tests/all.py +0 -0
  143. sage/tests/all__sagemath_repl.py +3 -0
  144. sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +630 -0
  145. sage/tests/arxiv_0812_2725.py +351 -0
  146. sage/tests/benchmark.py +1925 -0
  147. sage/tests/book_schilling_zabrocki_kschur_primer.py +795 -0
  148. sage/tests/book_stein_ent.py +651 -0
  149. sage/tests/book_stein_modform.py +558 -0
  150. sage/tests/cmdline.py +796 -0
  151. sage/tests/combinatorial_hopf_algebras.py +52 -0
  152. sage/tests/finite_poset.py +623 -0
  153. sage/tests/functools_partial_src.py +27 -0
  154. sage/tests/gosper-sum.py +218 -0
  155. sage/tests/lazy_imports.py +28 -0
  156. sage/tests/modular_group_cohomology.py +80 -0
  157. sage/tests/numpy.py +21 -0
  158. sage/tests/parigp.py +76 -0
  159. sage/tests/startup.py +27 -0
  160. sage/tests/symbolic-series.py +76 -0
  161. sage/tests/sympy.py +16 -0
  162. sage/tests/test_deprecation.py +31 -0
@@ -0,0 +1,3079 @@
1
+ # sage_setup: distribution = sagemath-repl
2
+ """
3
+ A tool for inspecting Python pickles
4
+
5
+ AUTHORS:
6
+
7
+ - Carl Witty (2009-03)
8
+
9
+ The :func:`explain_pickle` function takes a pickle and produces Sage code that
10
+ will evaluate to the contents of the pickle. Ideally, the combination
11
+ of :func:`explain_pickle` to produce Sage code and :func:`sage_eval` to evaluate the code
12
+ would be a 100% compatible implementation of cPickle's unpickler; this
13
+ is almost the case now.
14
+
15
+ EXAMPLES::
16
+
17
+ sage: explain_pickle(dumps(12345))
18
+ pg_make_integer = unpickle_global('sage.rings.integer', 'make_integer')
19
+ pg_make_integer('c1p')
20
+ sage: explain_pickle(dumps(polygen(QQ)))
21
+ pg_Polynomial_rational_flint = unpickle_global('sage.rings.polynomial.polynomial_rational_flint', 'Polynomial_rational_flint')
22
+ pg_unpickle_PolynomialRing = unpickle_global('sage.rings.polynomial.polynomial_ring_constructor', 'unpickle_PolynomialRing')
23
+ pg_RationalField = unpickle_global('sage.rings.rational_field', 'RationalField')
24
+ pg = unpickle_instantiate(pg_RationalField, ())
25
+ pg_make_rational = unpickle_global('sage.rings.rational', 'make_rational')
26
+ pg_Polynomial_rational_flint(pg_unpickle_PolynomialRing(pg, ('x',), None, False), [pg_make_rational('0'), pg_make_rational('1')], False, True)
27
+ sage: sage_eval(explain_pickle(dumps(polygen(QQ)))) == polygen(QQ)
28
+ True
29
+
30
+ By default (as above) the code produced contains calls to several
31
+ utility functions (:func:`unpickle_global`, etc.); this is done so that the
32
+ code is truly equivalent to the pickle. If the pickle can be loaded
33
+ into a future version of Sage, then the code that :func:`explain_pickle`
34
+ produces today should work in that future Sage as well.
35
+
36
+ It is also possible to produce simpler code, that is tied to the current
37
+ version of Sage; here are the above two examples again::
38
+
39
+ sage: explain_pickle(dumps(12345), in_current_sage=True)
40
+ from sage.rings.integer import make_integer
41
+ make_integer('c1p')
42
+ sage: explain_pickle(dumps(polygen(QQ)), in_current_sage=True)
43
+ from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint
44
+ from sage.rings.polynomial.polynomial_ring_constructor import unpickle_PolynomialRing
45
+ from sage.rings.rational import make_rational
46
+ Polynomial_rational_flint(unpickle_PolynomialRing(RationalField(), ('x',), None, False), [make_rational('0'), make_rational('1')], False, True)
47
+
48
+ The :func:`explain_pickle` function has several use cases.
49
+
50
+ - Write pickling support for your classes
51
+
52
+ You can use :func:`explain_pickle` to see what will happen when a pickle
53
+ is unpickled. Consider: is this sequence of commands something
54
+ that can be easily supported in all future Sage versions, or does
55
+ it expose internal design decisions that are subject to change?
56
+
57
+ - Debug old pickles
58
+
59
+ If you have a pickle from an old version of Sage that no longer
60
+ unpickles, you can use :func:`explain_pickle` to see what it is trying to
61
+ do, to figure out how to fix it.
62
+
63
+ - Use :func:`explain_pickle` in doctests to help maintenance
64
+
65
+ If you have a ``loads(dumps(S))`` doctest, you could also add an
66
+ ``explain_pickle(dumps(S))`` doctest. Then if something changes
67
+ in a way that would invalidate old pickles, the output of
68
+ :func:`explain_pickle` will also change. At that point, you can add
69
+ the previous output of :obj:`explain_pickle` as a new set of
70
+ doctests (and then update the :obj:`explain_pickle` doctest to use
71
+ the new output), to ensure that old pickles will continue to work.
72
+
73
+ As mentioned above, there are several output modes for :func:`explain_pickle`,
74
+ that control fidelity versus simplicity of the output. For example,
75
+ the GLOBAL instruction takes a module name and a class name and
76
+ produces the corresponding class. So GLOBAL of ``sage.rings.integer``,
77
+ ``Integer`` is approximately equivalent to ``sage.rings.integer.Integer``.
78
+
79
+ However, this class lookup process can be customized (using
80
+ :func:`sage.misc.persist.register_unpickle_override`). For instance,
81
+ if some future version of Sage renamed ``sage/rings/integer.pyx`` to
82
+ ``sage/rings/knuth_was_here.pyx``, old pickles would no longer work unless
83
+ register_unpickle_override was used; in that case, GLOBAL of
84
+ ``sage.rings.integer``, ``integer`` would mean
85
+ ``sage.rings.knuth_was_here.integer``.
86
+
87
+ By default, :func:`explain_pickle` will map this GLOBAL instruction to
88
+ ``unpickle_global('sage.rings.integer', 'integer')``. Then when this code
89
+ is evaluated, :func:`unpickle_global` will look up the current mapping in the
90
+ :func:`register_unpickle_override` table, so the generated code will continue
91
+ to work even in hypothetical future versions of Sage where ``integer.pyx``
92
+ has been renamed.
93
+
94
+ If you pass the flag ``in_current_sage=True``, then
95
+ :func:`explain_pickle` will generate code that may only work in the
96
+ current version of Sage, not in future versions. In this case, it
97
+ would generate::
98
+
99
+ from sage.rings.integer import integer
100
+
101
+ and if you ran :func:`explain_pickle` in hypothetical future sage, it would generate:
102
+
103
+ from sage.rings.knuth_was_here import integer
104
+
105
+ but the current code wouldn't work in the future sage.
106
+
107
+ If you pass the flag ``default_assumptions=True``, then
108
+ :func:`explain_pickle` will generate code that would work in the
109
+ absence of any special unpickling information. That is, in either
110
+ current Sage or hypothetical future Sage, it would generate::
111
+
112
+ from sage.rings.integer import integer
113
+
114
+ The intention is that ``default_assumptions`` output is prettier (more
115
+ human-readable), but may not actually work; so it is only intended for
116
+ human reading.
117
+
118
+ There are several functions used in the output of :func:`explain_pickle`.
119
+ Here I give a brief description of what they usually do, as well as
120
+ how to modify their operation (for instance, if you're trying to get
121
+ old pickles to work).
122
+
123
+ - ``unpickle_global(module, classname)``:
124
+ ``unpickle_global('sage.foo.bar', 'baz')`` is usually equivalent to
125
+ ``sage.foo.bar.baz``, but this can be customized with
126
+ :func:`register_unpickle_override`.
127
+
128
+ - ``unpickle_newobj(klass, args)``:
129
+ Usually equivalent to ``klass.__new__(klass, *args)``. If
130
+ ``klass`` is a Python class, then you can define :meth:`__new__`
131
+ to control the result (this result actually need not be an
132
+ instance of ``klass``). (This doesn't work for Cython classes.)
133
+
134
+ - ``unpickle_build(obj, state)``:
135
+ If ``obj`` has a :meth:`__setstate__` method, then this is equivalent to
136
+ ``obj.__setstate__(state)``. Otherwise uses ``state`` to set the attributes
137
+ of ``obj``. Customize by defining :meth:`__setstate__`.
138
+
139
+ - ``unpickle_instantiate(klass, args)``:
140
+ Usually equivalent to ``klass(*args)``. Cannot be customized.
141
+
142
+ - ``unpickle_appends(lst, vals)``:
143
+ Appends the values in ``vals`` to ``lst``. If not ``isinstance(lst, list)``,
144
+ can be customized by defining a :meth:`append` method.
145
+ """
146
+
147
+ # *****************************************************************************
148
+ # Copyright (C) 2009 Carl Witty <Carl.Witty@gmail.com>
149
+ #
150
+ # This program is free software: you can redistribute it and/or modify
151
+ # it under the terms of the GNU General Public License as published by
152
+ # the Free Software Foundation, either version 2 of the License, or
153
+ # (at your option) any later version.
154
+ # http://www.gnu.org/licenses/
155
+ # *****************************************************************************
156
+
157
+
158
+ import pickletools
159
+ import re
160
+ import sys
161
+ import types
162
+
163
+ import zlib as comp
164
+ import bz2 as comp_other
165
+
166
+ from pickletools import genops
167
+
168
+ from sage.misc.sage_input import SageInputBuilder, SageInputExpression
169
+ from sage.misc.sage_eval import sage_eval
170
+ from sage.misc.persist import (unpickle_override, unpickle_global, dumps,
171
+ register_unpickle_override, SageUnpickler)
172
+
173
+
174
+ # Python 3 does not have a "ClassType". Instead, we ensure that
175
+ # isinstance(foo, ClassType) will always return False.
176
+ ClassType = ()
177
+
178
+
179
+ def explain_pickle(pickle=None, file=None, compress=True, **kwargs):
180
+ r"""
181
+ Explain a pickle. That is, produce source code such that evaluating
182
+ the code is equivalent to loading the pickle. Feeding the result
183
+ of :func:`explain_pickle` to :func:`sage_eval` should be totally equivalent to loading
184
+ the ``pickle`` with ``cPickle``.
185
+
186
+ INPUT:
187
+
188
+ - ``pickle`` -- string (default: ``None``); the pickle to explain
189
+ - ``file`` -- a filename of a pickle (default: ``None``)
190
+ - ``compress`` -- boolean (default: ``True``); if ``False``, don't attempt
191
+ to decompress the pickle
192
+ - ``in_current_sage`` -- boolean (default: ``False``); if ``True``,
193
+ produce potentially simpler code that is tied to the current version of
194
+ Sage
195
+ - ``default_assumptions`` -- boolean (default: ``False``); if ``True``,
196
+ produce potentially simpler code that assumes that generic unpickling
197
+ code will be used. This code may not actually work.
198
+ - ``eval`` -- boolean (default: ``False``); if ``True``, then evaluate the
199
+ resulting code and return the evaluated result
200
+ - ``preparse`` -- if ``True``, then produce code to be evaluated with
201
+ Sage's preparser; if ``False``, then produce standard
202
+ Python code; if ``None``, then produce code that will work
203
+ either with or without the preparser. (default: ``True``)
204
+ - ``pedantic`` -- boolean (default: ``False``); if ``True``, then carefully
205
+ ensures that the result has at least as much sharing as the result of
206
+ cPickle (it may have more, for immutable objects)
207
+
208
+ Exactly one of ``pickle`` (a string containing a pickle) or
209
+ ``file`` (the filename of a pickle) must be provided.
210
+
211
+ EXAMPLES::
212
+
213
+ sage: explain_pickle(dumps({('a', 'b'): [1r, 2r]}))
214
+ {('a', 'b'):[1r, 2r]}
215
+ sage: explain_pickle(dumps(RR(pi)), in_current_sage=True) # needs sage.symbolic
216
+ from sage.rings.real_mpfr import __create__RealNumber_version0
217
+ from sage.rings.real_mpfr import __create__RealField_version0
218
+ __create__RealNumber_version0(__create__RealField_version0(53r, False, 'RNDN'), '3.4gvml245kc0@0', 32r)
219
+ sage: s = 'hi'
220
+ sage: explain_pickle(dumps((s, s)))
221
+ ('hi', 'hi')
222
+ sage: explain_pickle(dumps((s, s)), pedantic=True)
223
+ si = 'hi'
224
+ (si, si)
225
+ sage: explain_pickle(dumps(5r))
226
+ 5r
227
+ sage: explain_pickle(dumps(5r), preparse=False)
228
+ 5
229
+ sage: explain_pickle(dumps(5r), preparse=None)
230
+ int(5)
231
+ sage: explain_pickle(dumps(22/7))
232
+ pg_make_rational = unpickle_global('sage.rings.rational', 'make_rational')
233
+ pg_make_rational('m/7')
234
+ sage: explain_pickle(dumps(22/7), in_current_sage=True)
235
+ from sage.rings.rational import make_rational
236
+ make_rational('m/7')
237
+ sage: explain_pickle(dumps(22/7), default_assumptions=True)
238
+ from sage.rings.rational import make_rational
239
+ make_rational('m/7')
240
+ """
241
+ if pickle is not None:
242
+ p = pickle
243
+ elif file is not None:
244
+ with open(file) as f:
245
+ p = f.read()
246
+ else:
247
+ raise ValueError("Either pickle or file must be specified")
248
+
249
+ if compress:
250
+ try:
251
+ p = comp.decompress(p)
252
+ except Exception:
253
+ try:
254
+ p = comp_other.decompress(p)
255
+ except Exception:
256
+ # Maybe data is uncompressed?
257
+ pass
258
+
259
+ return explain_pickle_string(p, **kwargs)
260
+
261
+
262
+ def explain_pickle_string(pickle, in_current_sage=False,
263
+ default_assumptions=False, eval=False, preparse=True,
264
+ pedantic=False):
265
+ r"""
266
+ This is a helper function for :func:`explain_pickle`. It takes a decompressed
267
+ pickle string as input; other than that, its options are all the same
268
+ as :func:`explain_pickle`.
269
+
270
+ EXAMPLES::
271
+
272
+ sage: sage.misc.explain_pickle.explain_pickle_string(dumps("Hello, world", compress=False))
273
+ 'Hello, world'
274
+
275
+ (See the documentation for :func:`explain_pickle` for many more examples.)
276
+ """
277
+ sib = SageInputBuilder(preparse=preparse)
278
+
279
+ pe = PickleExplainer(sib, in_current_sage=in_current_sage,
280
+ default_assumptions=default_assumptions,
281
+ pedantic=pedantic)
282
+
283
+ v = pe.run_pickle(pickle)
284
+
285
+ ans = sib.result(sib(v))
286
+
287
+ if eval:
288
+ if default_assumptions:
289
+ raise ValueError("Not safe to evaluate code generated with default_assumptions")
290
+ from sage.misc.sage_eval import sage_eval
291
+ result = sage_eval(ans, preparse=preparse)
292
+ print(ans)
293
+ return result
294
+ else:
295
+ return ans
296
+
297
+
298
+ valid_name_re = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
299
+
300
+
301
+ def name_is_valid(name):
302
+ r"""
303
+ Test whether a string is a valid Python identifier. (We use a
304
+ conservative test, that only allows ASCII identifiers.)
305
+
306
+ EXAMPLES::
307
+
308
+ sage: from sage.misc.explain_pickle import name_is_valid
309
+ sage: name_is_valid('fred')
310
+ True
311
+ sage: name_is_valid('Yes!ValidName')
312
+ False
313
+ sage: name_is_valid('_happy_1234')
314
+ True
315
+ """
316
+ # Technically, we also need to reject keywords...
317
+ return bool(valid_name_re.match(name))
318
+
319
+
320
+ # The pickle interpreter can push and pop "marks" on the stack.
321
+ # This string is used as the representation of a mark.
322
+ the_mark = 'mark'
323
+
324
+
325
+ class PickleObject:
326
+ r"""
327
+ Pickles have a stack-based virtual machine. The :func:`explain_pickle`
328
+ pickle interpreter mostly uses :class:`sage.misc.sage_input.SageInputExpression` objects
329
+ as the stack values. However, sometimes we want some more information
330
+ about the value on the stack, so that we can generate better
331
+ (prettier, less confusing) code. In such cases, we push
332
+ a :class:`PickleObject` instead of a :class:`~sage.misc.sage_input.SageInputExpression`.
333
+ A :class:`PickleObject`
334
+ contains a value (which may be a standard Python value, or a
335
+ :class:`PickleDict` or :class:`PickleInstance`), an expression
336
+ (a :class:`~sage.misc.sage_input.SageInputExpression`),
337
+ and an "immutable" flag (which checks whether this object
338
+ has been converted to a :class:`SageInputExpression`; if it has, then we
339
+ must not mutate the object, since the :class:`SageInputExpression` would not
340
+ reflect the changes).
341
+ """
342
+
343
+ def __init__(self, value, expression):
344
+ r"""
345
+ Construct a PickleObject.
346
+
347
+ TESTS::
348
+
349
+ sage: from sage.misc.explain_pickle import *
350
+ sage: v = PickleObject(1, 2)
351
+ sage: v.value
352
+ 1
353
+ sage: v.expression
354
+ 2
355
+ sage: v.immutable
356
+ False
357
+ """
358
+ self.value = value
359
+ self.expression = expression
360
+ self.immutable = False
361
+
362
+ def _sage_input_(self, sib, coerced):
363
+ r"""
364
+ Extracts the expression from a PickleObject, and sets the immutable
365
+ flag.
366
+
367
+ TESTS::
368
+
369
+ sage: from sage.misc.explain_pickle import *
370
+ sage: v = PickleObject(1, 2)
371
+ sage: v.immutable
372
+ False
373
+ sage: v._sage_input_('sib', False)
374
+ 2
375
+ sage: v.immutable
376
+ True
377
+ """
378
+ self.immutable = True
379
+ return self.expression
380
+
381
+
382
+ class PickleDict:
383
+ r"""
384
+ An object which can be used as the value of a :class:`PickleObject`. The items
385
+ is a list of key-value pairs, where the keys and values are
386
+ :class:`SageInputExpression` objects. We use this to help construct dictionary literals,
387
+ instead of always starting with an empty dictionary and assigning to
388
+ it.
389
+ """
390
+ def __init__(self, items):
391
+ r"""
392
+ Initialize a PickleDict.
393
+
394
+ EXAMPLES::
395
+
396
+ sage: from sage.misc.explain_pickle import *
397
+ sage: PickleDict([('a', 1)]).items
398
+ [('a', 1)]
399
+ """
400
+ self.items = items
401
+
402
+
403
+ class PickleInstance:
404
+ r"""
405
+ An object which can be used as the value of a :class:`PickleObject`. Unlike
406
+ other possible values of a :class:`PickleObject`, a :class:`PickleInstance` doesn't represent
407
+ an exact value; instead, it gives the class (type) of the object.
408
+ """
409
+ def __init__(self, klass):
410
+ r"""
411
+ Initialize a PickleInstance.
412
+
413
+ EXAMPLES::
414
+
415
+ sage: from sage.misc.explain_pickle import *
416
+ sage: PickleInstance(Integer).klass
417
+ <class 'sage.rings.integer.Integer'>
418
+ """
419
+ self.klass = klass
420
+
421
+
422
+ class PickleExplainer:
423
+ r"""
424
+ An interpreter for the pickle virtual machine, that executes
425
+ symbolically and constructs :class:`SageInputExpression` objects instead of
426
+ directly constructing values.
427
+ """
428
+ def __init__(self, sib, in_current_sage=False, default_assumptions=False,
429
+ pedantic=False):
430
+ r"""
431
+ Initialize a PickleExplainer interpreter for the pickle virtual machine.
432
+
433
+ EXAMPLES::
434
+
435
+ sage: from sage.misc.explain_pickle import *
436
+ sage: from sage.misc.sage_input import SageInputBuilder
437
+ sage: pe = PickleExplainer(SageInputBuilder(), in_current_sage=True, default_assumptions=False, pedantic=True)
438
+ sage: pe.in_current_sage
439
+ True
440
+ sage: pe.pedantic
441
+ True
442
+ """
443
+ self.sib = sib
444
+ self.in_current_sage = in_current_sage
445
+ self.default_assumptions = default_assumptions
446
+ self.pedantic = pedantic
447
+ self.stopped = False
448
+ self.stack = []
449
+ self.memo = {}
450
+ if in_current_sage and default_assumptions:
451
+ raise ValueError("in_current_sage and default_assumptions must not both be true")
452
+
453
+ self.new_instance = self.sib.import_name('types', 'InstanceType')
454
+
455
+ def run_pickle(self, p):
456
+ r"""
457
+ Given an (uncompressed) pickle as a string, run the pickle
458
+ in this virtual machine. Once a STOP has been executed, return
459
+ the result (a :class:`SageInputExpression` representing code which, when
460
+ evaluated, will give the value of the pickle).
461
+
462
+ EXAMPLES::
463
+
464
+ sage: from sage.misc.explain_pickle import *
465
+ sage: from sage.misc.sage_input import SageInputBuilder
466
+ sage: sib = SageInputBuilder()
467
+ sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True)
468
+ sage: sib(pe.run_pickle('T\5\0\0\0hello.')) # py2
469
+ {atomic:'hello'}
470
+ """
471
+ for op, arg, pos in genops(p):
472
+ assert not self.stopped
473
+ try:
474
+ handler = getattr(self, op.name)
475
+ except AttributeError:
476
+ raise NotImplementedError('PickleExplainer does not yet handle opcode %s' % op.name)
477
+ if arg is None:
478
+ handler()
479
+ else:
480
+ handler(arg)
481
+
482
+ assert self.stopped
483
+ assert len(self.stack) == 1
484
+ return self.stack[0]
485
+
486
+ def check_value(self, v):
487
+ r"""
488
+ Check that the given value is either a :class:`SageInputExpression` or a
489
+ :class:`PickleObject`. Used for internal sanity checking.
490
+
491
+ EXAMPLES::
492
+
493
+ sage: from sage.misc.explain_pickle import *
494
+ sage: from sage.misc.sage_input import SageInputBuilder
495
+ sage: sib = SageInputBuilder()
496
+ sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True)
497
+ sage: pe.check_value(7)
498
+ Traceback (most recent call last):
499
+ ...
500
+ AssertionError
501
+ sage: pe.check_value(sib(7))
502
+ """
503
+ assert isinstance(v, (SageInputExpression, PickleObject))
504
+
505
+ def push(self, v):
506
+ r"""
507
+ Push a value onto the virtual machine's stack.
508
+
509
+ EXAMPLES::
510
+
511
+ sage: from sage.misc.explain_pickle import *
512
+ sage: from sage.misc.sage_input import SageInputBuilder
513
+ sage: sib = SageInputBuilder()
514
+ sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True)
515
+ sage: pe.push(sib(7))
516
+ sage: pe.stack[-1]
517
+ {atomic:7}
518
+ """
519
+ self.check_value(v)
520
+ self.stack.append(v)
521
+
522
+ def push_and_share(self, v):
523
+ r"""
524
+ Push a value onto the virtual machine's stack; also mark it as shared
525
+ for :func:`sage_input` if we are in pedantic mode.
526
+
527
+ EXAMPLES::
528
+
529
+ sage: from sage.misc.explain_pickle import *
530
+ sage: from sage.misc.sage_input import SageInputBuilder
531
+ sage: sib = SageInputBuilder()
532
+ sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True)
533
+ sage: pe.push_and_share(sib(7))
534
+ sage: pe.stack[-1]
535
+ {atomic:7}
536
+ sage: pe.stack[-1]._sie_share
537
+ True
538
+ """
539
+ self.share(v)
540
+ self.push(v)
541
+
542
+ def pop(self):
543
+ r"""
544
+ Pop a value from the virtual machine's stack, and return it.
545
+
546
+ EXAMPLES::
547
+
548
+ sage: from sage.misc.explain_pickle import *
549
+ sage: from sage.misc.sage_input import SageInputBuilder
550
+ sage: sib = SageInputBuilder()
551
+ sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True)
552
+ sage: pe.push(sib(7))
553
+ sage: pe.pop()
554
+ {atomic:7}
555
+ """
556
+ v = self.stack.pop()
557
+ self.check_value(v)
558
+ return v
559
+
560
+ def push_mark(self):
561
+ r"""
562
+ Push a 'mark' onto the virtual machine's stack.
563
+
564
+ EXAMPLES::
565
+
566
+ sage: from sage.misc.explain_pickle import *
567
+ sage: from sage.misc.sage_input import SageInputBuilder
568
+ sage: sib = SageInputBuilder()
569
+ sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True)
570
+ sage: pe.push_mark()
571
+ sage: pe.stack[-1]
572
+ 'mark'
573
+ sage: pe.stack[-1] is the_mark
574
+ True
575
+ """
576
+ self.stack.append(the_mark)
577
+
578
+ def pop_to_mark(self):
579
+ r"""
580
+ Pop all values down to the 'mark' from the virtual machine's stack,
581
+ and return the values as a list.
582
+
583
+ EXAMPLES::
584
+
585
+ sage: from sage.misc.explain_pickle import *
586
+ sage: from sage.misc.sage_input import SageInputBuilder
587
+ sage: sib = SageInputBuilder()
588
+ sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True)
589
+ sage: pe.push_mark()
590
+ sage: pe.push(sib(7))
591
+ sage: pe.push(sib('hello'))
592
+ sage: pe.pop_to_mark()
593
+ [{atomic:7}, {atomic:'hello'}]
594
+ """
595
+ slice = []
596
+ while True:
597
+ v = self.stack.pop()
598
+ if v is the_mark:
599
+ slice.reverse()
600
+ return slice
601
+ self.check_value(v)
602
+ slice.append(v)
603
+
604
+ def share(self, v):
605
+ r"""
606
+ Mark a :func:`sage_input` value as shared, if we are in pedantic mode.
607
+
608
+ EXAMPLES::
609
+
610
+ sage: from sage.misc.explain_pickle import *
611
+ sage: from sage.misc.sage_input import SageInputBuilder
612
+ sage: sib = SageInputBuilder()
613
+ sage: pe = PickleExplainer(sib, in_current_sage=True,
614
+ ....: default_assumptions=False, pedantic=True)
615
+ sage: v = sib(7)
616
+ sage: v._sie_share
617
+ False
618
+ sage: pe.share(v)
619
+ {atomic:7}
620
+ sage: v._sie_share
621
+ True
622
+ """
623
+ if self.pedantic:
624
+ self.sib.share(v)
625
+ return v
626
+
627
+ def is_mutable_pickle_object(self, v):
628
+ r"""
629
+ Test whether a :class:`PickleObject` is mutable (has never been converted
630
+ to a :class:`SageInputExpression`).
631
+
632
+ EXAMPLES::
633
+
634
+ sage: from sage.misc.explain_pickle import *
635
+ sage: from sage.misc.sage_input import SageInputBuilder
636
+ sage: sib = SageInputBuilder()
637
+ sage: pe = PickleExplainer(sib, in_current_sage=True,
638
+ ....: default_assumptions=False, pedantic=True)
639
+ sage: v = PickleObject(1, sib(1))
640
+ sage: pe.is_mutable_pickle_object(v)
641
+ True
642
+ sage: sib(v)
643
+ {atomic:1}
644
+ sage: pe.is_mutable_pickle_object(v)
645
+ False
646
+ """
647
+ return isinstance(v, PickleObject) and not v.immutable
648
+
649
+ # Opcodes are in alphabetical order
650
+
651
+ def APPEND(self):
652
+ r"""
653
+ TESTS::
654
+
655
+ sage: from sage.misc.explain_pickle import *
656
+ sage: test_pickle(['a'])
657
+ 0: \x80 PROTO 2
658
+ 2: ] EMPTY_LIST
659
+ 3: q BINPUT 0
660
+ 5: X BINUNICODE 'a'
661
+ 11: q BINPUT 1
662
+ 13: a APPEND
663
+ 14: . STOP
664
+ highest protocol among opcodes = 2
665
+ explain_pickle in_current_sage=True/False:
666
+ ['a']
667
+ result: ['a']
668
+
669
+ As shown above, we prefer to create a list literal. This is not
670
+ possible if the list is recursive::
671
+
672
+ sage: v = []
673
+ sage: v.append(v)
674
+ sage: test_pickle(v)
675
+ 0: \x80 PROTO 2
676
+ 2: ] EMPTY_LIST
677
+ 3: q BINPUT 0
678
+ 5: h BINGET 0
679
+ 7: a APPEND
680
+ 8: . STOP
681
+ highest protocol among opcodes = 2
682
+ explain_pickle in_current_sage=True/False:
683
+ si = []
684
+ list.append(si, si)
685
+ si
686
+ result: [[...]]
687
+ """
688
+
689
+ obj = self.pop()
690
+ lst = self.pop()
691
+ self._APPENDS_helper(lst, [obj])
692
+
693
+ def APPENDS(self):
694
+ r"""
695
+ TESTS::
696
+
697
+ sage: from sage.misc.explain_pickle import *
698
+ sage: test_pickle(['a', 'b'])
699
+ 0: \x80 PROTO 2
700
+ 2: ] EMPTY_LIST
701
+ 3: q BINPUT 0
702
+ 5: ( MARK
703
+ 6: X BINUNICODE 'a'
704
+ 12: q BINPUT 1
705
+ 14: X BINUNICODE 'b'
706
+ 20: q BINPUT 2
707
+ 22: e APPENDS (MARK at 5)
708
+ 23: . STOP
709
+ highest protocol among opcodes = 2
710
+ explain_pickle in_current_sage=True/False:
711
+ ['a', 'b']
712
+ result: ['a', 'b']
713
+
714
+ As shown above, we prefer to create a list literal. This is not
715
+ possible if the list is recursive::
716
+
717
+ sage: v = []
718
+ sage: v.append(v)
719
+ sage: v.append(v)
720
+ sage: test_pickle(v)
721
+ 0: \x80 PROTO 2
722
+ 2: ] EMPTY_LIST
723
+ 3: q BINPUT 0
724
+ 5: ( MARK
725
+ 6: h BINGET 0
726
+ 8: h BINGET 0
727
+ 10: e APPENDS (MARK at 5)
728
+ 11: . STOP
729
+ highest protocol among opcodes = 2
730
+ explain_pickle in_current_sage=True/False:
731
+ si = []
732
+ list.extend(si, [si, si])
733
+ si
734
+ result: [[...], [...]]
735
+ """
736
+ slice = self.pop_to_mark()
737
+ lst = self.pop()
738
+ self._APPENDS_helper(lst, slice)
739
+
740
+ def _APPENDS_helper(self, lst, slice):
741
+ r"""
742
+ TESTS:
743
+
744
+ See the doctests for APPEND and APPENDS for some simple indirect
745
+ tests of this method. Here we test some subtle behavior.
746
+
747
+ For subtypes of list, we use list.append/list.extend instead of
748
+ the append method of the object (TestAppendList.append raises
749
+ an exception, so we can tell that cPickle doesn't call it either)::
750
+
751
+ sage: from sage.misc.explain_pickle import *
752
+ sage: test_pickle(TestAppendList((True,))) # indirect doctest
753
+ 0: \x80 PROTO 2
754
+ 2: c GLOBAL 'sage.misc.explain_pickle TestAppendList'
755
+ 43: q BINPUT 0
756
+ 45: ) EMPTY_TUPLE
757
+ 46: \x81 NEWOBJ
758
+ 47: q BINPUT 1
759
+ 49: \x88 NEWTRUE
760
+ 50: a APPEND
761
+ 51: . STOP
762
+ highest protocol among opcodes = 2
763
+ explain_pickle in_current_sage=True:
764
+ from sage.misc.explain_pickle import TestAppendList
765
+ si = unpickle_newobj(TestAppendList, ())
766
+ list.append(si, True)
767
+ si
768
+ explain_pickle in_current_sage=False:
769
+ pg_TestAppendList = unpickle_global('sage.misc.explain_pickle', 'TestAppendList')
770
+ si = unpickle_newobj(pg_TestAppendList, ())
771
+ unpickle_appends(si, [True])
772
+ si
773
+ result: [True] (cPickle raised an exception!)
774
+
775
+ For values which are not subtypes of list, we use their own append
776
+ method::
777
+
778
+ sage: v = TestAppendNonlist()
779
+ sage: v.list = [False, None]
780
+ sage: test_pickle(v, verbose_eval=True)
781
+ 0: \x80 PROTO 2
782
+ 2: c GLOBAL 'sage.misc.explain_pickle TestAppendNonlist'
783
+ 46: q BINPUT 0
784
+ 48: ) EMPTY_TUPLE
785
+ 49: R REDUCE
786
+ 50: q BINPUT 1
787
+ 52: ( MARK
788
+ 53: \x89 NEWFALSE
789
+ 54: N NONE
790
+ 55: e APPENDS (MARK at 52)
791
+ 56: . STOP
792
+ highest protocol among opcodes = 2
793
+ explain_pickle in_current_sage=True:
794
+ from sage.misc.explain_pickle import TestAppendNonlist
795
+ si = TestAppendNonlist()
796
+ si.append(False)
797
+ si.append(None)
798
+ si
799
+ explain_pickle in_current_sage=False:
800
+ pg_TestAppendNonlist = unpickle_global('sage.misc.explain_pickle', 'TestAppendNonlist')
801
+ pg = unpickle_instantiate(pg_TestAppendNonlist, ())
802
+ unpickle_appends(pg, [False, None])
803
+ pg
804
+ evaluating explain_pickle in_current_sage=True:
805
+ Fetching append attribute
806
+ Fetching append attribute
807
+ evaluating explain_pickle in_current_sage=False:
808
+ Fetching append attribute
809
+ loading pickle with cPickle:
810
+ Fetching append attribute
811
+ result: [False, None]
812
+
813
+ We see above that the in_current_sage=True code doesn't quite match
814
+ the other cases, because it fetches the append attribute twice
815
+ instead of once. If we set pedantic=True, then this is fixed.
816
+ (We show only the changed parts of the output)::
817
+
818
+ sage: test_pickle(v, verbose_eval=True, pedantic=True)
819
+ 0: \x80 PROTO 2
820
+ ...
821
+ explain_pickle in_current_sage=True:
822
+ from sage.misc.explain_pickle import TestAppendNonlist
823
+ si1 = TestAppendNonlist()
824
+ si2 = si1.append
825
+ si2(False)
826
+ si2(None)
827
+ si1
828
+ ...
829
+ evaluating explain_pickle in_current_sage=True:
830
+ Fetching append attribute
831
+ ...
832
+ """
833
+ # This has the side-effect of marking lst as immutable, if
834
+ # slice happens to include lst.
835
+ slice_exp = self.sib(slice)
836
+ if self.is_mutable_pickle_object(lst) and isinstance(lst.value, list):
837
+ lst.value.extend(slice)
838
+ lst.expression = self.sib(lst.value)
839
+ elif isinstance(lst, PickleObject) or self.default_assumptions:
840
+ if isinstance(lst.value, list) or \
841
+ (isinstance(lst.value, PickleInstance) and
842
+ issubclass(lst.value.klass, list)) or \
843
+ self.default_assumptions:
844
+ if len(slice) > 1:
845
+ self.sib.command(lst, self.sib.name('list').extend(lst, slice))
846
+ else:
847
+ for s in slice:
848
+ self.sib.command(lst, self.sib.name('list').append(lst, self.sib(s)))
849
+ else:
850
+ if self.pedantic:
851
+ app = self.sib(lst).append
852
+ for s in slice:
853
+ self.sib.command(lst, app(self.sib(s)))
854
+ else:
855
+ for s in slice:
856
+ self.sib.command(lst, self.sib(lst).append(self.sib(s)))
857
+ else:
858
+ self.sib.command(lst, self.sib.name('unpickle_appends')(self.sib(lst), slice_exp))
859
+ self.push(lst)
860
+
861
+ def BINFLOAT(self, f):
862
+ r"""
863
+ TESTS::
864
+
865
+ sage: from sage.misc.explain_pickle import *
866
+ sage: test_pickle(float(pi)) # needs sage.symbolic
867
+ 0: \x80 PROTO 2
868
+ 2: G BINFLOAT 3.141592653589793
869
+ 11: . STOP
870
+ highest protocol among opcodes = 2
871
+ explain_pickle in_current_sage=True/False:
872
+ 3.141592653589793
873
+ result: 3.141592653589793
874
+ """
875
+ self.push(self.sib(f))
876
+
877
+ def BINGET(self, n):
878
+ r"""
879
+ TESTS::
880
+
881
+ sage: from pickle import *
882
+ sage: from sage.misc.explain_pickle import *
883
+ sage: test_pickle(EMPTY_LIST + BINPUT + 'x' + POP + BINGET + 'x' + '.') # py2
884
+ 0: ] EMPTY_LIST
885
+ 1: q BINPUT 120
886
+ 3: 0 POP
887
+ 4: h BINGET 120
888
+ 6: . STOP
889
+ highest protocol among opcodes = 1
890
+ explain_pickle in_current_sage=True/False:
891
+ []
892
+ result: []
893
+ """
894
+ self.push(self.memo[n])
895
+
896
+ def BININT(self, n):
897
+ r"""
898
+ TESTS::
899
+
900
+ sage: from sage.misc.explain_pickle import *
901
+ sage: test_pickle(dumps(100000r, compress=False)) # py2
902
+ 0: \x80 PROTO 2
903
+ 2: J BININT 100000
904
+ 7: . STOP
905
+ highest protocol among opcodes = 2
906
+ explain_pickle in_current_sage=True/False:
907
+ 100000
908
+ result: 100000
909
+ """
910
+ self.push_and_share(self.sib(n))
911
+
912
+ def BININT1(self, n):
913
+ r"""
914
+ TESTS::
915
+
916
+ sage: from sage.misc.explain_pickle import *
917
+ sage: test_pickle(dumps(100r, compress=False)) # py2
918
+ 0: \x80 PROTO 2
919
+ 2: K BININT1 100
920
+ 4: . STOP
921
+ highest protocol among opcodes = 2
922
+ explain_pickle in_current_sage=True/False:
923
+ 100
924
+ result: 100
925
+ """
926
+ self.push_and_share(self.sib(n))
927
+
928
+ def BININT2(self, n):
929
+ r"""
930
+ TESTS::
931
+
932
+ sage: from sage.misc.explain_pickle import *
933
+ sage: test_pickle(dumps(1000r, compress=False)) # py2
934
+ 0: \x80 PROTO 2
935
+ 2: M BININT2 1000
936
+ 5: . STOP
937
+ highest protocol among opcodes = 2
938
+ explain_pickle in_current_sage=True/False:
939
+ 1000
940
+ result: 1000
941
+ """
942
+ self.push_and_share(self.sib(n))
943
+
944
+ def BINPUT(self, n):
945
+ r"""
946
+ TESTS::
947
+
948
+ sage: from pickle import *
949
+ sage: from sage.misc.explain_pickle import *
950
+ sage: test_pickle(EMPTY_LIST + BINPUT + 'x' + POP + BINGET + 'x') # py2
951
+ 0: ] EMPTY_LIST
952
+ 1: q BINPUT 120
953
+ 3: 0 POP
954
+ 4: h BINGET 120
955
+ 6: . STOP
956
+ highest protocol among opcodes = 1
957
+ explain_pickle in_current_sage=True/False:
958
+ []
959
+ result: []
960
+ """
961
+ v = self.pop()
962
+ self.memo[n] = v
963
+ self.push(v)
964
+
965
+ def BINSTRING(self, s):
966
+ r"""
967
+ TESTS::
968
+
969
+ sage: from sage.misc.explain_pickle import *
970
+ sage: test_pickle('T\5\0\0\0hello.') # py2
971
+ 0: T BINSTRING 'hello'
972
+ 10: . STOP
973
+ highest protocol among opcodes = 1
974
+ explain_pickle in_current_sage=True/False:
975
+ 'hello'
976
+ result: 'hello'
977
+ """
978
+ self.push(PickleObject(s, self.share(self.sib(s))))
979
+
980
+ def BINUNICODE(self, s):
981
+ r"""
982
+ TESTS::
983
+
984
+ sage: from sage.misc.explain_pickle import *
985
+ sage: test_pickle(u'hi\u1234\U00012345') # py2
986
+ 0: \x80 PROTO 2
987
+ 2: X BINUNICODE u'hi\u1234\U00012345'
988
+ 16: q BINPUT 1
989
+ 18: . STOP
990
+ highest protocol among opcodes = 2
991
+ explain_pickle in_current_sage=True/False:
992
+ u'hi\u1234\U00012345'
993
+ result: u'hi\u1234\U00012345'
994
+ """
995
+ self.push_and_share(self.sib(s))
996
+
997
+ def BUILD(self):
998
+ r"""
999
+ TESTS::
1000
+
1001
+ sage: from sage.misc.explain_pickle import *
1002
+ sage: test_pickle(TestBuild())
1003
+ 0: \x80 PROTO 2
1004
+ 2: c GLOBAL 'sage.misc.explain_pickle TestBuild'
1005
+ 38: q BINPUT 0
1006
+ 40: ) EMPTY_TUPLE
1007
+ 41: \x81 NEWOBJ
1008
+ 42: q BINPUT 1
1009
+ 44: } EMPTY_DICT
1010
+ 45: q BINPUT 2
1011
+ 47: X BINUNICODE 'x'
1012
+ 53: q BINPUT 3
1013
+ 55: K BININT1 3
1014
+ 57: s SETITEM
1015
+ 58: } EMPTY_DICT
1016
+ 59: q BINPUT 4
1017
+ 61: X BINUNICODE 'y'
1018
+ 67: q BINPUT 5
1019
+ 69: K BININT1 4
1020
+ 71: s SETITEM
1021
+ 72: \x86 TUPLE2
1022
+ 73: q BINPUT 6
1023
+ 75: b BUILD
1024
+ 76: . STOP
1025
+ highest protocol among opcodes = 2
1026
+ explain_pickle in_current_sage=True:
1027
+ from sage.misc.explain_pickle import TestBuild
1028
+ si = unpickle_newobj(TestBuild, ())
1029
+ si.__dict__['x'] = 3
1030
+ setattr(si, 'y', 4)
1031
+ si
1032
+ explain_pickle in_current_sage=False:
1033
+ pg_TestBuild = unpickle_global('sage.misc.explain_pickle', 'TestBuild')
1034
+ si = unpickle_newobj(pg_TestBuild, ())
1035
+ unpickle_build(si, ({'x':3}, {'y':4}))
1036
+ si
1037
+ result: TestBuild: x=3; y=4
1038
+
1039
+ ::
1040
+
1041
+ sage: test_pickle(TestBuildSetstate(), verbose_eval=True)
1042
+ 0: \x80 PROTO 2
1043
+ 2: c GLOBAL 'sage.misc.explain_pickle TestBuildSetstate'
1044
+ 46: q BINPUT 0
1045
+ 48: ) EMPTY_TUPLE
1046
+ 49: \x81 NEWOBJ
1047
+ 50: q BINPUT 1
1048
+ 52: } EMPTY_DICT
1049
+ 53: q BINPUT 2
1050
+ 55: X BINUNICODE 'x'
1051
+ 61: q BINPUT 3
1052
+ 63: K BININT1 3
1053
+ 65: s SETITEM
1054
+ 66: } EMPTY_DICT
1055
+ 67: q BINPUT 4
1056
+ 69: X BINUNICODE 'y'
1057
+ 75: q BINPUT 5
1058
+ 77: K BININT1 4
1059
+ 79: s SETITEM
1060
+ 80: \x86 TUPLE2
1061
+ 81: q BINPUT 6
1062
+ 83: b BUILD
1063
+ 84: . STOP
1064
+ highest protocol among opcodes = 2
1065
+ explain_pickle in_current_sage=True:
1066
+ from sage.misc.explain_pickle import TestBuildSetstate
1067
+ si = unpickle_newobj(TestBuildSetstate, ())
1068
+ si.__setstate__(({'x':3}, {'y':4}))
1069
+ si
1070
+ explain_pickle in_current_sage=False:
1071
+ pg_TestBuildSetstate = unpickle_global('sage.misc.explain_pickle', 'TestBuildSetstate')
1072
+ si = unpickle_newobj(pg_TestBuildSetstate, ())
1073
+ unpickle_build(si, ({'x':3}, {'y':4}))
1074
+ si
1075
+ evaluating explain_pickle in_current_sage=True:
1076
+ setting state from ({'x': 3}, {'y': 4})
1077
+ evaluating explain_pickle in_current_sage=False:
1078
+ setting state from ({'x': 3}, {'y': 4})
1079
+ loading pickle with cPickle:
1080
+ setting state from ({'x': 3}, {'y': 4})
1081
+ result: TestBuild: x=4; y=3
1082
+ """
1083
+ args = self.pop()
1084
+ obj = self.pop()
1085
+ use_setstate = False
1086
+ direct_set = False
1087
+ if self.default_assumptions:
1088
+ direct_set = True
1089
+ elif self.in_current_sage:
1090
+ if isinstance(obj, PickleObject) and isinstance(obj.value, PickleInstance):
1091
+ if hasattr(obj.value.klass, '__setstate__'):
1092
+ use_setstate = True
1093
+ else:
1094
+ direct_set = True
1095
+
1096
+ can_handle_direct_set = False
1097
+ if direct_set:
1098
+ if isinstance(args, PickleObject):
1099
+ if isinstance(args.value, PickleDict):
1100
+ can_handle_direct_set = True
1101
+ if isinstance(args.value, tuple) and isinstance(args.value[0], PickleObject) and isinstance(args.value[0].value, PickleDict) and isinstance(args.value[1], PickleObject) and isinstance(args.value[1].value, PickleDict):
1102
+ can_handle_direct_set = True
1103
+ if not can_handle_direct_set:
1104
+ direct_set = False
1105
+
1106
+ if use_setstate:
1107
+ self.sib.command(obj, self.sib.getattr(obj, '__setstate__')(args))
1108
+ elif direct_set:
1109
+ state = args.value
1110
+ slots = None
1111
+ if isinstance(state, tuple):
1112
+ slots = state[1].value
1113
+ state = state[0].value
1114
+ d = self.sib.getattr(obj, '__dict__')
1115
+ for k, v in state.items:
1116
+ self.sib.command(obj, self.sib.assign(d[k], v))
1117
+ if slots is not None:
1118
+ for k, v in slots.items:
1119
+ if isinstance(k, PickleObject) and isinstance(k.value, str):
1120
+ self.sib.command(obj, self.sib.assign(self.sib.getattr(obj, k.value), v))
1121
+ else:
1122
+ self.sib.command(obj, self.sib.name('setattr')(obj, k, v))
1123
+ else:
1124
+ self.sib.command(obj, self.sib.name('unpickle_build')(obj, args))
1125
+
1126
+ self.push(obj)
1127
+
1128
+ def DICT(self):
1129
+ r"""
1130
+ TESTS::
1131
+
1132
+ sage: from pickle import *
1133
+ sage: from sage.misc.explain_pickle import *
1134
+ sage: test_pickle(DICT, args=('mark', 'a', 1, 2, 'b')) # py2
1135
+ 0: ( MARK
1136
+ 1: P PERSID '1'
1137
+ 4: P PERSID '2'
1138
+ 7: P PERSID '3'
1139
+ 10: P PERSID '4'
1140
+ 13: d DICT (MARK at 0)
1141
+ 14: . STOP
1142
+ highest protocol among opcodes = 0
1143
+ explain_pickle in_current_sage=True/False:
1144
+ {unpickle_persistent('1'):unpickle_persistent('2'), unpickle_persistent('3'):unpickle_persistent('4')}
1145
+ result: {'a': 1, 2: 'b'}
1146
+ """
1147
+ slice = self.pop_to_mark()
1148
+ self.EMPTY_DICT()
1149
+ self._SETITEMS_helper(slice)
1150
+
1151
+ def DUP(self):
1152
+ r"""
1153
+ TESTS::
1154
+
1155
+ sage: from pickle import *
1156
+ sage: from sage.misc.explain_pickle import *
1157
+ sage: test_pickle(EMPTY_LIST + DUP + TUPLE2 + STOP) # py2
1158
+ 0: ] EMPTY_LIST
1159
+ 1: 2 DUP
1160
+ 2: \x86 TUPLE2
1161
+ 3: . STOP
1162
+ highest protocol among opcodes = 2
1163
+ explain_pickle in_current_sage=True/False:
1164
+ si = []
1165
+ (si, si)
1166
+ result: ([], [])
1167
+ """
1168
+ v = self.pop()
1169
+ self.push(v)
1170
+ self.push(v)
1171
+
1172
+ def EMPTY_DICT(self):
1173
+ r"""
1174
+ TESTS::
1175
+
1176
+ sage: from pickle import *
1177
+ sage: from sage.misc.explain_pickle import *
1178
+ sage: test_pickle(EMPTY_DICT) # py2
1179
+ 0: } EMPTY_DICT
1180
+ 1: . STOP
1181
+ highest protocol among opcodes = 1
1182
+ explain_pickle in_current_sage=True/False:
1183
+ {}
1184
+ result: {}
1185
+ """
1186
+ self.push(PickleObject(PickleDict([]), self.sib({})))
1187
+
1188
+ def EMPTY_LIST(self):
1189
+ r"""
1190
+ TESTS::
1191
+
1192
+ sage: from pickle import *
1193
+ sage: from sage.misc.explain_pickle import *
1194
+ sage: test_pickle(EMPTY_LIST) # py2
1195
+ 0: ] EMPTY_LIST
1196
+ 1: . STOP
1197
+ highest protocol among opcodes = 1
1198
+ explain_pickle in_current_sage=True/False:
1199
+ []
1200
+ result: []
1201
+ """
1202
+ self.push(PickleObject([], self.sib([])))
1203
+
1204
+ def EMPTY_TUPLE(self):
1205
+ r"""
1206
+ TESTS::
1207
+
1208
+ sage: from pickle import *
1209
+ sage: from sage.misc.explain_pickle import *
1210
+ sage: test_pickle(EMPTY_TUPLE) # py2
1211
+ 0: ) EMPTY_TUPLE
1212
+ 1: . STOP
1213
+ highest protocol among opcodes = 1
1214
+ explain_pickle in_current_sage=True/False:
1215
+ ()
1216
+ result: ()
1217
+ """
1218
+ self.push(PickleObject((), self.sib(())))
1219
+
1220
+ def EXT1(self, n):
1221
+ r"""
1222
+ TESTS::
1223
+
1224
+ sage: from copyreg import *
1225
+ sage: from sage.misc.explain_pickle import *
1226
+ sage: add_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 42)
1227
+ sage: test_pickle(EmptyNewstyleClass())
1228
+ 0: \x80 PROTO 2
1229
+ 2: \x82 EXT1 42
1230
+ 4: ) EMPTY_TUPLE
1231
+ 5: \x81 NEWOBJ
1232
+ 6: q BINPUT 0
1233
+ 8: . STOP
1234
+ highest protocol among opcodes = 2
1235
+ explain_pickle in_current_sage=True/False:
1236
+ unpickle_newobj(unpickle_extension(42), ())
1237
+ result: EmptyNewstyleClass
1238
+ sage: remove_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 42)
1239
+ """
1240
+ self.push(self.sib.name('unpickle_extension')(n))
1241
+
1242
+ def EXT2(self, n):
1243
+ r"""
1244
+ TESTS::
1245
+
1246
+ sage: from copyreg import *
1247
+ sage: from sage.misc.explain_pickle import *
1248
+ sage: add_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 31415)
1249
+ sage: test_pickle(EmptyNewstyleClass())
1250
+ 0: \x80 PROTO 2
1251
+ 2: \x83 EXT2 31415
1252
+ 5: ) EMPTY_TUPLE
1253
+ 6: \x81 NEWOBJ
1254
+ 7: q BINPUT 0
1255
+ 9: . STOP
1256
+ highest protocol among opcodes = 2
1257
+ explain_pickle in_current_sage=True/False:
1258
+ unpickle_newobj(unpickle_extension(31415), ())
1259
+ result: EmptyNewstyleClass
1260
+ sage: remove_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 31415)
1261
+ """
1262
+ self.push(self.sib.name('unpickle_extension')(n))
1263
+
1264
+ def EXT4(self, n):
1265
+ r"""
1266
+ TESTS::
1267
+
1268
+ sage: from copyreg import *
1269
+ sage: from sage.misc.explain_pickle import *
1270
+ sage: add_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 27182818)
1271
+ sage: test_pickle(EmptyNewstyleClass())
1272
+ 0: \x80 PROTO 2
1273
+ 2: \x84 EXT4 27182818
1274
+ 7: ) EMPTY_TUPLE
1275
+ 8: \x81 NEWOBJ
1276
+ 9: q BINPUT 0
1277
+ 11: . STOP
1278
+ highest protocol among opcodes = 2
1279
+ explain_pickle in_current_sage=True/False:
1280
+ unpickle_newobj(unpickle_extension(27182818), ())
1281
+ result: EmptyNewstyleClass
1282
+ sage: remove_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 27182818)
1283
+ """
1284
+ self.push(self.sib.name('unpickle_extension')(n))
1285
+
1286
+ def FLOAT(self, f):
1287
+ r"""
1288
+ TESTS::
1289
+
1290
+ sage: from pickle import *
1291
+ sage: from sage.misc.explain_pickle import *
1292
+ sage: test_pickle(FLOAT + '2.71828\n') # py2
1293
+ 0: F FLOAT 2.71828
1294
+ 9: . STOP
1295
+ highest protocol among opcodes = 0
1296
+ explain_pickle in_current_sage=True/False:
1297
+ 2.71828
1298
+ result: 2.71828
1299
+ """
1300
+ self.push(self.sib(f))
1301
+
1302
+ def GET(self, n):
1303
+ r"""
1304
+ TESTS::
1305
+
1306
+ sage: from pickle import *
1307
+ sage: from sage.misc.explain_pickle import *
1308
+ sage: test_pickle(EMPTY_LIST + PUT + '1\n' + POP + GET + '1\n' + '.') # py2
1309
+ 0: ] EMPTY_LIST
1310
+ 1: p PUT 1
1311
+ 4: 0 POP
1312
+ 5: g GET 1
1313
+ 8: . STOP
1314
+ highest protocol among opcodes = 1
1315
+ explain_pickle in_current_sage=True/False:
1316
+ []
1317
+ result: []
1318
+ """
1319
+ self.push(self.memo[n])
1320
+
1321
+ def GLOBAL(self, name):
1322
+ r"""
1323
+ TESTS::
1324
+
1325
+ sage: from sage.misc.explain_pickle import *
1326
+
1327
+ We've used register_unpickle_override so that unpickle_global
1328
+ will map TestGlobalOldName to TestGlobalNewName.
1329
+
1330
+ ::
1331
+
1332
+ sage: test_pickle(TestGlobalOldName())
1333
+ 0: \x80 PROTO 2
1334
+ 2: c GLOBAL 'sage.misc.explain_pickle TestGlobalOldName'
1335
+ 46: q BINPUT 0
1336
+ 48: ) EMPTY_TUPLE
1337
+ 49: \x81 NEWOBJ
1338
+ 50: q BINPUT 1
1339
+ 52: . STOP
1340
+ highest protocol among opcodes = 2
1341
+ explain_pickle in_current_sage=True:
1342
+ from sage.misc.explain_pickle import TestGlobalNewName
1343
+ unpickle_newobj(TestGlobalNewName, ())
1344
+ explain_pickle in_current_sage=False:
1345
+ pg_TestGlobalOldName = unpickle_global('sage.misc.explain_pickle', 'TestGlobalOldName')
1346
+ unpickle_newobj(pg_TestGlobalOldName, ())
1347
+ result: TestGlobalNewName
1348
+
1349
+ Note that default_assumptions blithely assumes that it should
1350
+ use the old name, giving code that doesn't actually work as
1351
+ desired::
1352
+
1353
+ sage: explain_pickle(dumps(TestGlobalOldName()), default_assumptions=True)
1354
+ from sage.misc.explain_pickle import TestGlobalOldName
1355
+ unpickle_newobj(TestGlobalOldName, ())
1356
+
1357
+ A class name need not be a valid identifier::
1358
+
1359
+ sage: sage.misc.explain_pickle.__dict__['funny$name'] = TestGlobalFunnyName # see comment at end of file
1360
+ sage: test_pickle((TestGlobalFunnyName(), TestGlobalFunnyName()))
1361
+ 0: \x80 PROTO 2
1362
+ 2: c GLOBAL 'sage.misc.explain_pickle TestGlobalFunnyName'
1363
+ 48: q BINPUT 0
1364
+ 50: ) EMPTY_TUPLE
1365
+ 51: \x81 NEWOBJ
1366
+ 52: q BINPUT 1
1367
+ 54: h BINGET 0
1368
+ 56: ) EMPTY_TUPLE
1369
+ 57: \x81 NEWOBJ
1370
+ 58: q BINPUT 2
1371
+ 60: \x86 TUPLE2
1372
+ 61: q BINPUT 3
1373
+ 63: . STOP
1374
+ highest protocol among opcodes = 2
1375
+ explain_pickle in_current_sage=True:
1376
+ from sage.misc.explain_pickle import TestGlobalFunnyName
1377
+ (unpickle_newobj(TestGlobalFunnyName, ()), unpickle_newobj(TestGlobalFunnyName, ()))
1378
+ explain_pickle in_current_sage=False:
1379
+ pg_TestGlobalFunnyName = unpickle_global('sage.misc.explain_pickle', 'TestGlobalFunnyName')
1380
+ (unpickle_newobj(pg_TestGlobalFunnyName, ()), unpickle_newobj(pg_TestGlobalFunnyName, ()))
1381
+ result: (TestGlobalFunnyName, TestGlobalFunnyName)
1382
+ """
1383
+ module, func = name.split(' ')
1384
+
1385
+ if self.default_assumptions:
1386
+ # Should the default assumption be that sage.all does, or
1387
+ # does not, have a conflicting variable name?
1388
+ # I'm going to go with "does not conflict".
1389
+ self.push(self.sib.import_name(module, func))
1390
+ return
1391
+
1392
+ name_ok = name_is_valid(func)
1393
+
1394
+ if self.in_current_sage and name_ok:
1395
+ override = unpickle_override.get((module, func))
1396
+ if override is None:
1397
+ __import__(module)
1398
+ f = getattr(sys.modules[module], func)
1399
+ else:
1400
+ f, new_mf = override
1401
+ if new_mf is not None:
1402
+ module, func = new_mf
1403
+ if override is None or new_mf is not None:
1404
+ # OK, we know what module and function name will actually
1405
+ # be used, as well as the actual function.
1406
+ # Is this already available at the command line?
1407
+ try:
1408
+ import sage.all
1409
+ except ImportError:
1410
+ cmdline_f = None
1411
+ else:
1412
+ cmdline_f = getattr(sage.all, func, None)
1413
+ if cmdline_f is f:
1414
+ self.push(PickleObject(f, self.sib.name(func)))
1415
+ return
1416
+ if cmdline_f is None:
1417
+ # OK, we'll go ahead and import it under the original
1418
+ # name.
1419
+ self.push(PickleObject(f, self.sib.import_name(module, func)))
1420
+ return
1421
+ # The original name is in use.
1422
+ self.push(PickleObject(f, self.sib.import_name(module, func, 'pg_' + func)))
1423
+ return
1424
+
1425
+ # We don't know the full name of the function that will
1426
+ # actually be used (either we're being generic, or
1427
+ # unpickle_override only has the function, not its name).
1428
+ v = self.sib.name('unpickle_global')(module, func)
1429
+ if name_ok:
1430
+ self.sib.use_variable(v, 'pg_' + func)
1431
+ self.push(v)
1432
+
1433
+ def INST(self, name):
1434
+ r"""
1435
+ TESTS::
1436
+
1437
+ sage: import pickle
1438
+ sage: from sage.misc.explain_pickle import *
1439
+ sage: test_pickle(pickle.dumps(EmptyOldstyleClass(), protocol=0)) # py2
1440
+ 0: ( MARK
1441
+ 1: i INST 'sage.misc.explain_pickle EmptyOldstyleClass' (MARK at 0)
1442
+ 46: p PUT 0
1443
+ 49: ( MARK
1444
+ 50: d DICT (MARK at 49)
1445
+ 51: p PUT 1
1446
+ 54: b BUILD
1447
+ 55: . STOP
1448
+ highest protocol among opcodes = 0
1449
+ explain_pickle in_current_sage=True:
1450
+ from types import InstanceType
1451
+ from sage.misc.explain_pickle import EmptyOldstyleClass
1452
+ InstanceType(EmptyOldstyleClass)
1453
+ explain_pickle in_current_sage=False:
1454
+ pg_EmptyOldstyleClass = unpickle_global('sage.misc.explain_pickle', 'EmptyOldstyleClass')
1455
+ pg = unpickle_instantiate(pg_EmptyOldstyleClass, ())
1456
+ unpickle_build(pg, {})
1457
+ pg
1458
+ result: EmptyOldstyleClass
1459
+ """
1460
+ self.TUPLE()
1461
+ v = self.pop()
1462
+ self.GLOBAL(name)
1463
+ self.push(v)
1464
+ self.REDUCE()
1465
+
1466
+ def INT(self, n):
1467
+ r"""
1468
+ TESTS::
1469
+
1470
+ sage: from pickle import *
1471
+ sage: from sage.misc.explain_pickle import *
1472
+ sage: test_pickle(INT + "-12345\n") # py2
1473
+ 0: I INT -12345
1474
+ 8: . STOP
1475
+ highest protocol among opcodes = 0
1476
+ explain_pickle in_current_sage=True/False:
1477
+ -12345
1478
+ result: -12345
1479
+
1480
+ INT can also be used to record True and False::
1481
+
1482
+ sage: test_pickle(INT + "00\n") # py2
1483
+ 0: I INT False
1484
+ 4: . STOP
1485
+ highest protocol among opcodes = 0
1486
+ explain_pickle in_current_sage=True/False:
1487
+ False
1488
+ result: False
1489
+ sage: test_pickle(INT + "01\n") # py2
1490
+ 0: I INT True
1491
+ 4: . STOP
1492
+ highest protocol among opcodes = 0
1493
+ explain_pickle in_current_sage=True/False:
1494
+ True
1495
+ result: True
1496
+ """
1497
+ self.push_and_share(self.sib(n))
1498
+
1499
+ def LIST(self):
1500
+ r"""
1501
+ TESTS::
1502
+
1503
+ sage: from pickle import *
1504
+ sage: from sage.misc.explain_pickle import *
1505
+ sage: test_pickle(MARK + NONE + NEWFALSE + LIST) # py2
1506
+ 0: ( MARK
1507
+ 1: N NONE
1508
+ 2: \x89 NEWFALSE
1509
+ 3: l LIST (MARK at 0)
1510
+ 4: . STOP
1511
+ highest protocol among opcodes = 2
1512
+ explain_pickle in_current_sage=True/False:
1513
+ [None, False]
1514
+ result: [None, False]
1515
+ """
1516
+ lst = self.pop_to_mark()
1517
+ self.push(PickleObject(lst, self.sib(lst)))
1518
+
1519
+ def LONG(self, n):
1520
+ r"""
1521
+ TESTS::
1522
+
1523
+ sage: from pickle import *
1524
+ sage: from sage.misc.explain_pickle import *
1525
+ sage: test_pickle(LONG + "12345678909876543210123456789L\n") # py2
1526
+ 0: L LONG 12345678909876543210123456789L
1527
+ 32: . STOP
1528
+ highest protocol among opcodes = 0
1529
+ explain_pickle in_current_sage=True/False:
1530
+ 12345678909876543210123456789
1531
+ result: 12345678909876543210123456789L
1532
+ """
1533
+ self.push(self.sib(n))
1534
+
1535
+ def LONG1(self, n):
1536
+ r"""
1537
+ TESTS::
1538
+
1539
+ sage: from sage.misc.explain_pickle import *
1540
+ sage: test_pickle(1L) # py2
1541
+ 0: \x80 PROTO 2
1542
+ 2: \x8a LONG1 1L
1543
+ 5: . STOP
1544
+ highest protocol among opcodes = 2
1545
+ explain_pickle in_current_sage=True/False:
1546
+ 1L
1547
+ result: 1L
1548
+ """
1549
+ self.push(self.sib(n))
1550
+
1551
+ def LONG4(self, n):
1552
+ r"""
1553
+ TESTS::
1554
+
1555
+ sage: from pickle import *
1556
+ sage: from sage.misc.explain_pickle import *
1557
+ sage: test_pickle(LONG4 + '\014\0\0\0' + 'hello, world') # py2
1558
+ 0: \x8b LONG4 31079605376604435891501163880L
1559
+ 17: . STOP
1560
+ highest protocol among opcodes = 2
1561
+ explain_pickle in_current_sage=True/False:
1562
+ 31079605376604435891501163880
1563
+ result: 31079605376604435891501163880L
1564
+ """
1565
+ self.push(self.sib(n))
1566
+
1567
+ def LONG_BINGET(self, n):
1568
+ r"""
1569
+ TESTS::
1570
+
1571
+ sage: from pickle import *
1572
+ sage: from sage.misc.explain_pickle import *
1573
+ sage: test_pickle(EMPTY_LIST + LONG_BINPUT + 'Sage' + POP + LONG_BINGET + 'Sage') # py2
1574
+ 0: ] EMPTY_LIST
1575
+ 1: r LONG_BINPUT 1701273939
1576
+ 6: 0 POP
1577
+ 7: j LONG_BINGET 1701273939
1578
+ 12: . STOP
1579
+ highest protocol among opcodes = 1
1580
+ explain_pickle in_current_sage=True/False:
1581
+ []
1582
+ result: []
1583
+ """
1584
+ self.push(self.memo[n])
1585
+
1586
+ def LONG_BINPUT(self, n):
1587
+ r"""
1588
+ TESTS::
1589
+
1590
+ sage: from pickle import *
1591
+ sage: from sage.misc.explain_pickle import *
1592
+ sage: test_pickle(EMPTY_LIST + LONG_BINPUT + 'Sage' + POP + LONG_BINGET + 'Sage') # py2
1593
+ 0: ] EMPTY_LIST
1594
+ 1: r LONG_BINPUT 1701273939
1595
+ 6: 0 POP
1596
+ 7: j LONG_BINGET 1701273939
1597
+ 12: . STOP
1598
+ highest protocol among opcodes = 1
1599
+ explain_pickle in_current_sage=True/False:
1600
+ []
1601
+ result: []
1602
+ """
1603
+ v = self.pop()
1604
+ self.memo[n] = v
1605
+ self.push(v)
1606
+
1607
+ def MARK(self):
1608
+ r"""
1609
+ TESTS::
1610
+
1611
+ sage: from pickle import *
1612
+ sage: from sage.misc.explain_pickle import *
1613
+ sage: test_pickle(MARK + TUPLE) # py2
1614
+ 0: ( MARK
1615
+ 1: t TUPLE (MARK at 0)
1616
+ 2: . STOP
1617
+ highest protocol among opcodes = 0
1618
+ explain_pickle in_current_sage=True/False:
1619
+ ()
1620
+ result: ()
1621
+ """
1622
+ self.push_mark()
1623
+
1624
+ def NEWFALSE(self):
1625
+ r"""
1626
+ TESTS::
1627
+
1628
+ sage: from pickle import *
1629
+ sage: from sage.misc.explain_pickle import *
1630
+ sage: test_pickle(NEWFALSE) # py2
1631
+ 0: \x89 NEWFALSE
1632
+ 1: . STOP
1633
+ highest protocol among opcodes = 2
1634
+ explain_pickle in_current_sage=True/False:
1635
+ False
1636
+ result: False
1637
+ """
1638
+ self.push(self.sib.name('False'))
1639
+
1640
+ def NEWTRUE(self):
1641
+ r"""
1642
+ TESTS::
1643
+
1644
+ sage: from pickle import *
1645
+ sage: from sage.misc.explain_pickle import *
1646
+ sage: test_pickle(NEWTRUE) # py2
1647
+ 0: \x88 NEWTRUE
1648
+ 1: . STOP
1649
+ highest protocol among opcodes = 2
1650
+ explain_pickle in_current_sage=True/False:
1651
+ True
1652
+ result: True
1653
+ """
1654
+ self.push(self.sib.name('True'))
1655
+
1656
+ def NEWOBJ(self):
1657
+ r"""
1658
+ TESTS::
1659
+
1660
+ sage: from sage.misc.explain_pickle import *
1661
+ sage: test_pickle(EmptyNewstyleClass())
1662
+ 0: \x80 PROTO 2
1663
+ 2: c GLOBAL 'sage.misc.explain_pickle EmptyNewstyleClass'
1664
+ 47: q BINPUT 0
1665
+ 49: ) EMPTY_TUPLE
1666
+ 50: \x81 NEWOBJ
1667
+ 51: q BINPUT 1
1668
+ 53: . STOP
1669
+ highest protocol among opcodes = 2
1670
+ explain_pickle in_current_sage=True:
1671
+ from sage.misc.explain_pickle import EmptyNewstyleClass
1672
+ unpickle_newobj(EmptyNewstyleClass, ())
1673
+ explain_pickle in_current_sage=False:
1674
+ pg_EmptyNewstyleClass = unpickle_global('sage.misc.explain_pickle', 'EmptyNewstyleClass')
1675
+ unpickle_newobj(pg_EmptyNewstyleClass, ())
1676
+ result: EmptyNewstyleClass
1677
+ """
1678
+ args = self.pop()
1679
+ klass = self.pop()
1680
+ obj = self.sib.name('unpickle_newobj')(klass, args)
1681
+ if isinstance(klass, PickleObject):
1682
+ self.push(PickleObject(PickleInstance(klass.value), obj))
1683
+ else:
1684
+ self.push(obj)
1685
+
1686
+ def NONE(self):
1687
+ r"""
1688
+ TESTS::
1689
+
1690
+ sage: from pickle import *
1691
+ sage: from sage.misc.explain_pickle import *
1692
+ sage: test_pickle(NONE) # py2
1693
+ 0: N NONE
1694
+ 1: . STOP
1695
+ highest protocol among opcodes = 0
1696
+ explain_pickle in_current_sage=True/False:
1697
+ None
1698
+ result: None
1699
+ """
1700
+ self.push(PickleObject(None, self.sib.name('None')))
1701
+
1702
+ def OBJ(self):
1703
+ r"""
1704
+ TESTS::
1705
+
1706
+ sage: from sage.misc.explain_pickle import *
1707
+ sage: test_pickle(EmptyOldstyleClass())
1708
+ 0: \x80 PROTO 2
1709
+ 2: c GLOBAL 'sage.misc.explain_pickle EmptyOldstyleClass'
1710
+ 47: q BINPUT 0
1711
+ 49: ) EMPTY_TUPLE
1712
+ 50: \x81 NEWOBJ
1713
+ 51: q BINPUT 1
1714
+ 53: . STOP
1715
+ highest protocol among opcodes = 2
1716
+ explain_pickle in_current_sage=True:
1717
+ from sage.misc.explain_pickle import EmptyOldstyleClass
1718
+ unpickle_newobj(EmptyOldstyleClass, ())
1719
+ explain_pickle in_current_sage=False:
1720
+ pg_EmptyOldstyleClass = unpickle_global('sage.misc.explain_pickle', 'EmptyOldstyleClass')
1721
+ unpickle_newobj(pg_EmptyOldstyleClass, ())
1722
+ result: EmptyOldstyleClass
1723
+ """
1724
+ klass_args = self.pop_to_mark()
1725
+ klass = klass_args[0]
1726
+ args = klass_args[1:]
1727
+ self.push(klass)
1728
+ self.push(PickleObject(tuple(args), self.sib(tuple(args))))
1729
+ self.REDUCE()
1730
+
1731
+ def PERSID(self, id):
1732
+ r"""
1733
+ TESTS::
1734
+
1735
+ sage: from pickle import *
1736
+ sage: from sage.misc.explain_pickle import *
1737
+ sage: test_pickle(PERSID + "0\n" + '.', args=('Yo!',)) # py2
1738
+ 0: P PERSID '0'
1739
+ 3: . STOP
1740
+ highest protocol among opcodes = 0
1741
+ explain_pickle in_current_sage=True/False:
1742
+ unpickle_persistent('0')
1743
+ result: 'Yo!'
1744
+ """
1745
+ self.push(self.sib.name('unpickle_persistent')(id))
1746
+
1747
+ def BINPERSID(self):
1748
+ r"""
1749
+ TESTS::
1750
+
1751
+ sage: from pickle import *
1752
+ sage: from sage.misc.explain_pickle import *
1753
+ sage: test_pickle(INT + "0\n" + BINPERSID + '.', args=('Yo!',)) # py2
1754
+ 0: I INT 0
1755
+ 3: Q BINPERSID
1756
+ 4: . STOP
1757
+ highest protocol among opcodes = 1
1758
+ explain_pickle in_current_sage=True/False:
1759
+ unpickle_persistent(0)
1760
+ result: 'Yo!'
1761
+ """
1762
+ id = self.pop()
1763
+ self.push(self.sib.name('unpickle_persistent')(id))
1764
+
1765
+ def POP(self):
1766
+ r"""
1767
+ TESTS::
1768
+
1769
+ sage: from pickle import *
1770
+ sage: from sage.misc.explain_pickle import *
1771
+ sage: test_pickle(INT + "0\n" + POP + INT + "42\n") # py2
1772
+ 0: I INT 0
1773
+ 3: 0 POP
1774
+ 4: I INT 42
1775
+ 8: . STOP
1776
+ highest protocol among opcodes = 0
1777
+ explain_pickle in_current_sage=True/False:
1778
+ 42
1779
+ result: 42
1780
+ """
1781
+ v = self.stack.pop()
1782
+ if v is not the_mark:
1783
+ self.check_value(v)
1784
+
1785
+ def POP_MARK(self):
1786
+ r"""
1787
+ TESTS::
1788
+
1789
+ sage: from pickle import *
1790
+ sage: from sage.misc.explain_pickle import *
1791
+ sage: test_pickle(MARK + NONE + NEWFALSE + POP_MARK + NEWTRUE) # py2
1792
+ 0: ( MARK
1793
+ 1: N NONE
1794
+ 2: \x89 NEWFALSE
1795
+ 3: 1 POP_MARK (MARK at 0)
1796
+ 4: \x88 NEWTRUE
1797
+ 5: . STOP
1798
+ highest protocol among opcodes = 2
1799
+ explain_pickle in_current_sage=True/False:
1800
+ True
1801
+ result: True
1802
+ """
1803
+ self.pop_to_mark()
1804
+
1805
+ def PROTO(self, proto):
1806
+ r"""
1807
+ TESTS::
1808
+
1809
+ sage: from sage.misc.explain_pickle import *
1810
+ sage: test_pickle(0r) # py2
1811
+ 0: \x80 PROTO 2
1812
+ 2: K BININT1 0
1813
+ 4: . STOP
1814
+ highest protocol among opcodes = 2
1815
+ explain_pickle in_current_sage=True/False:
1816
+ 0
1817
+ result: 0
1818
+ """
1819
+ if not 0 <= proto <= 2:
1820
+ raise ValueError("unsupported pickle protocol: {}".format(proto))
1821
+
1822
+ def PUT(self, n):
1823
+ r"""
1824
+ TESTS::
1825
+
1826
+ sage: from pickle import *
1827
+ sage: from sage.misc.explain_pickle import *
1828
+ sage: test_pickle(EMPTY_LIST + PUT + '1\n' + POP + GET + '1\n' + '.') # py2
1829
+ 0: ] EMPTY_LIST
1830
+ 1: p PUT 1
1831
+ 4: 0 POP
1832
+ 5: g GET 1
1833
+ 8: . STOP
1834
+ highest protocol among opcodes = 1
1835
+ explain_pickle in_current_sage=True/False:
1836
+ []
1837
+ result: []
1838
+ """
1839
+ v = self.pop()
1840
+ self.memo[n] = v
1841
+ self.push(v)
1842
+
1843
+ def REDUCE(self):
1844
+ r"""
1845
+ TESTS::
1846
+
1847
+ sage: import pickle
1848
+ sage: from sage.misc.explain_pickle import *
1849
+ sage: test_pickle(pickle.dumps(EmptyNewstyleClass(), protocol=1)) # py2
1850
+ 0: c GLOBAL 'copy_reg _reconstructor'
1851
+ 25: q BINPUT 0
1852
+ 27: ( MARK
1853
+ 28: c GLOBAL 'sage.misc.explain_pickle EmptyNewstyleClass'
1854
+ 73: q BINPUT 1
1855
+ 75: c GLOBAL '__builtin__ object'
1856
+ 95: q BINPUT 2
1857
+ 97: N NONE
1858
+ 98: t TUPLE (MARK at 27)
1859
+ 99: q BINPUT 3
1860
+ 101: R REDUCE
1861
+ 102: q BINPUT 4
1862
+ 104: . STOP
1863
+ highest protocol among opcodes = 1
1864
+ explain_pickle in_current_sage=True:
1865
+ from copy_reg import _reconstructor
1866
+ from sage.misc.explain_pickle import EmptyNewstyleClass
1867
+ from __builtin__ import object
1868
+ _reconstructor(EmptyNewstyleClass, object, None)
1869
+ explain_pickle in_current_sage=False:
1870
+ pg__reconstructor = unpickle_global('copy_reg', '_reconstructor')
1871
+ pg_EmptyNewstyleClass = unpickle_global('sage.misc.explain_pickle', 'EmptyNewstyleClass')
1872
+ pg_object = unpickle_global('__builtin__', 'object')
1873
+ pg__reconstructor(pg_EmptyNewstyleClass, pg_object, None)
1874
+ result: EmptyNewstyleClass
1875
+
1876
+ ::
1877
+
1878
+ sage: test_pickle(TestReduceGetinitargs(), verbose_eval=True) # py2
1879
+ Running __init__ for TestReduceGetinitargs
1880
+ 0: \x80 PROTO 2
1881
+ 2: ( MARK
1882
+ 3: c GLOBAL 'sage.misc.explain_pickle TestReduceGetinitargs'
1883
+ 51: q BINPUT 1
1884
+ 53: o OBJ (MARK at 2)
1885
+ 54: q BINPUT 2
1886
+ 56: } EMPTY_DICT
1887
+ 57: q BINPUT 3
1888
+ 59: b BUILD
1889
+ 60: . STOP
1890
+ highest protocol among opcodes = 2
1891
+ explain_pickle in_current_sage=True:
1892
+ from sage.misc.explain_pickle import TestReduceGetinitargs
1893
+ TestReduceGetinitargs()
1894
+ explain_pickle in_current_sage=False:
1895
+ pg_TestReduceGetinitargs = unpickle_global('sage.misc.explain_pickle', 'TestReduceGetinitargs')
1896
+ pg = unpickle_instantiate(pg_TestReduceGetinitargs, ())
1897
+ unpickle_build(pg, {})
1898
+ pg
1899
+ evaluating explain_pickle in_current_sage=True:
1900
+ Running __init__ for TestReduceGetinitargs
1901
+ evaluating explain_pickle in_current_sage=False:
1902
+ Running __init__ for TestReduceGetinitargs
1903
+ loading pickle with cPickle:
1904
+ Running __init__ for TestReduceGetinitargs
1905
+ result: TestReduceGetinitargs
1906
+
1907
+ ::
1908
+
1909
+ sage: test_pickle(TestReduceNoGetinitargs(), verbose_eval=True) # py2
1910
+ Running __init__ for TestReduceNoGetinitargs
1911
+ 0: \x80 PROTO 2
1912
+ 2: ( MARK
1913
+ 3: c GLOBAL 'sage.misc.explain_pickle TestReduceNoGetinitargs'
1914
+ 53: q BINPUT 1
1915
+ 55: o OBJ (MARK at 2)
1916
+ 56: q BINPUT 2
1917
+ 58: } EMPTY_DICT
1918
+ 59: q BINPUT 3
1919
+ 61: b BUILD
1920
+ 62: . STOP
1921
+ highest protocol among opcodes = 2
1922
+ explain_pickle in_current_sage=True:
1923
+ from types import InstanceType
1924
+ from sage.misc.explain_pickle import TestReduceNoGetinitargs
1925
+ InstanceType(TestReduceNoGetinitargs)
1926
+ explain_pickle in_current_sage=False:
1927
+ pg_TestReduceNoGetinitargs = unpickle_global('sage.misc.explain_pickle', 'TestReduceNoGetinitargs')
1928
+ pg = unpickle_instantiate(pg_TestReduceNoGetinitargs, ())
1929
+ unpickle_build(pg, {})
1930
+ pg
1931
+ evaluating explain_pickle in_current_sage=True:
1932
+ evaluating explain_pickle in_current_sage=False:
1933
+ loading pickle with cPickle:
1934
+ result: TestReduceNoGetinitargs
1935
+ """
1936
+
1937
+ # Reading cPickle.c (in the Instance_New function),
1938
+ # I think that REDUCE is equivalent to a function call unless
1939
+ # all three of the following conditions are met:
1940
+ # obj is an old-style class
1941
+ # obj defines __getinitargs__
1942
+ # args is an empty tuple
1943
+ # in which case it is equivalent to PyInstance_NewRaw(obj)
1944
+ args = self.pop()
1945
+ obj = self.pop()
1946
+ simple_call = False
1947
+ new_inst = False
1948
+ if isinstance(args, PickleObject) and isinstance(args.value, tuple) \
1949
+ and len(args.value) > 0:
1950
+ simple_call = True
1951
+ if self.default_assumptions:
1952
+ simple_call = True
1953
+ if self.in_current_sage:
1954
+ if isinstance(obj, PickleObject):
1955
+ if isinstance(obj.value, type):
1956
+ simple_call = True
1957
+ elif isinstance(obj.value, ClassType):
1958
+ if hasattr(obj.value, '__getinitargs__'):
1959
+ simple_call = True
1960
+ else:
1961
+ new_inst = True
1962
+
1963
+ if simple_call:
1964
+ v = self.sib(obj)(*args.value)
1965
+ elif new_inst:
1966
+ v = self.new_instance(obj)
1967
+ else:
1968
+ v = self.sib.name('unpickle_instantiate')(obj, args)
1969
+ self.sib.use_variable(v, 'pg')
1970
+ if isinstance(obj, PickleObject):
1971
+ self.push(PickleObject(PickleInstance(obj.value), v))
1972
+ else:
1973
+ self.push(v)
1974
+
1975
+ def SETITEM(self):
1976
+ r"""
1977
+ TESTS::
1978
+
1979
+ sage: import pickle
1980
+ sage: from sage.misc.explain_pickle import *
1981
+ sage: test_pickle(pickle.dumps({'a': 'b'})) # py2
1982
+ 0: ( MARK
1983
+ 1: d DICT (MARK at 0)
1984
+ 2: p PUT 0
1985
+ 5: S STRING 'a'
1986
+ 10: p PUT 1
1987
+ 13: S STRING 'b'
1988
+ 18: p PUT 2
1989
+ 21: s SETITEM
1990
+ 22: . STOP
1991
+ highest protocol among opcodes = 0
1992
+ explain_pickle in_current_sage=True/False:
1993
+ {'a':'b'}
1994
+ result: {'a': 'b'}
1995
+
1996
+ We see above that we output the result as a dictionary literal, when
1997
+ possible. This is impossible when a key or value is recursive. First
1998
+ we test recursive values::
1999
+
2000
+ sage: value_rec = dict()
2001
+ sage: value_rec['circular'] = value_rec
2002
+ sage: test_pickle(pickle.dumps(value_rec)) # py2
2003
+ 0: ( MARK
2004
+ 1: d DICT (MARK at 0)
2005
+ 2: p PUT 0
2006
+ 5: S STRING 'circular'
2007
+ 17: p PUT 1
2008
+ 20: g GET 0
2009
+ 23: s SETITEM
2010
+ 24: . STOP
2011
+ highest protocol among opcodes = 0
2012
+ explain_pickle in_current_sage=True/False:
2013
+ si = {}
2014
+ si['circular'] = si
2015
+ si
2016
+ result: {'circular': {...}}
2017
+
2018
+ Then we test recursive keys::
2019
+
2020
+ sage: key_rec = dict()
2021
+ sage: key = EmptyNewstyleClass()
2022
+ sage: key.circular = key_rec
2023
+ sage: key_rec[key] = 'circular'
2024
+ sage: test_pickle(pickle.dumps(key_rec)) # py2
2025
+ 0: ( MARK
2026
+ 1: d DICT (MARK at 0)
2027
+ 2: p PUT 0
2028
+ 5: c GLOBAL 'copy_reg _reconstructor'
2029
+ 30: p PUT 1
2030
+ 33: ( MARK
2031
+ 34: c GLOBAL 'sage.misc.explain_pickle EmptyNewstyleClass'
2032
+ 79: p PUT 2
2033
+ 82: c GLOBAL '__builtin__ object'
2034
+ 102: p PUT 3
2035
+ 105: N NONE
2036
+ 106: t TUPLE (MARK at 33)
2037
+ 107: p PUT 4
2038
+ 110: R REDUCE
2039
+ 111: p PUT 5
2040
+ 114: ( MARK
2041
+ 115: d DICT (MARK at 114)
2042
+ 116: p PUT 6
2043
+ 119: S STRING 'circular'
2044
+ 131: p PUT 7
2045
+ 134: g GET 0
2046
+ 137: s SETITEM
2047
+ 138: b BUILD
2048
+ 139: g GET 7
2049
+ 142: s SETITEM
2050
+ 143: . STOP
2051
+ highest protocol among opcodes = 0
2052
+ explain_pickle in_current_sage=True:
2053
+ si1 = {}
2054
+ from copy_reg import _reconstructor
2055
+ from sage.misc.explain_pickle import EmptyNewstyleClass
2056
+ from __builtin__ import object
2057
+ si2 = _reconstructor(EmptyNewstyleClass, object, None)
2058
+ si2.__dict__['circular'] = si1
2059
+ si1[si2] = 'circular'
2060
+ si1
2061
+ explain_pickle in_current_sage=False:
2062
+ si1 = {}
2063
+ pg__reconstructor = unpickle_global('copy_reg', '_reconstructor')
2064
+ pg_EmptyNewstyleClass = unpickle_global('sage.misc.explain_pickle', 'EmptyNewstyleClass')
2065
+ pg_object = unpickle_global('__builtin__', 'object')
2066
+ si2 = pg__reconstructor(pg_EmptyNewstyleClass, pg_object, None)
2067
+ unpickle_build(si2, {'circular':si1})
2068
+ si1[si2] = 'circular'
2069
+ si1
2070
+ result: {EmptyNewstyleClass: 'circular'}
2071
+ """
2072
+ v = self.pop()
2073
+ k = self.pop()
2074
+ self._SETITEMS_helper([k, v])
2075
+
2076
+ def SETITEMS(self):
2077
+ r"""
2078
+ TESTS::
2079
+
2080
+ sage: import pickle
2081
+ sage: from sage.misc.explain_pickle import *
2082
+ sage: test_pickle(pickle.dumps({'a': 'b', 1r : 2r}, protocol=2)) # py2
2083
+ 0: \x80 PROTO 2
2084
+ 2: } EMPTY_DICT
2085
+ 3: q BINPUT 0
2086
+ 5: ( MARK
2087
+ 6: U SHORT_BINSTRING 'a'
2088
+ 9: q BINPUT 1
2089
+ 11: U SHORT_BINSTRING 'b'
2090
+ 14: q BINPUT 2
2091
+ 16: K BININT1 1
2092
+ 18: K BININT1 2
2093
+ 20: u SETITEMS (MARK at 5)
2094
+ 21: . STOP
2095
+ highest protocol among opcodes = 2
2096
+ explain_pickle in_current_sage=True/False:
2097
+ {'a':'b', 1:2}
2098
+ result: {'a': 'b', 1: 2}
2099
+
2100
+ Similar to the tests for SETITEM, we test recursive keys and values::
2101
+
2102
+ sage: recdict = {}
2103
+ sage: recdict['Circular value'] = recdict
2104
+ sage: key = EmptyOldstyleClass()
2105
+ sage: key.recdict = recdict
2106
+ sage: recdict[key] = 'circular_key'
2107
+ sage: test_pickle(pickle.dumps(recdict, protocol=2)) # py2
2108
+ 0: \x80 PROTO 2
2109
+ 2: } EMPTY_DICT
2110
+ 3: q BINPUT 0
2111
+ 5: ( MARK
2112
+ 6: ( MARK
2113
+ 7: c GLOBAL 'sage.misc.explain_pickle EmptyOldstyleClass'
2114
+ 52: q BINPUT 1
2115
+ 54: o OBJ (MARK at 6)
2116
+ 55: q BINPUT 2
2117
+ 57: } EMPTY_DICT
2118
+ 58: q BINPUT 3
2119
+ 60: U SHORT_BINSTRING 'recdict'
2120
+ 69: q BINPUT 4
2121
+ 71: h BINGET 0
2122
+ 73: s SETITEM
2123
+ 74: b BUILD
2124
+ 75: U SHORT_BINSTRING 'circular_key'
2125
+ 89: q BINPUT 5
2126
+ 91: U SHORT_BINSTRING 'Circular value'
2127
+ 107: q BINPUT 6
2128
+ 109: h BINGET 0
2129
+ 111: u SETITEMS (MARK at 5)
2130
+ 112: . STOP
2131
+ highest protocol among opcodes = 2
2132
+ explain_pickle in_current_sage=True:
2133
+ si1 = {}
2134
+ from types import InstanceType
2135
+ from sage.misc.explain_pickle import EmptyOldstyleClass
2136
+ si2 = InstanceType(EmptyOldstyleClass)
2137
+ si2.__dict__['recdict'] = si1
2138
+ si1[si2] = 'circular_key'
2139
+ si1['Circular value'] = si1
2140
+ si1
2141
+ explain_pickle in_current_sage=False:
2142
+ si = {}
2143
+ pg_EmptyOldstyleClass = unpickle_global('sage.misc.explain_pickle', 'EmptyOldstyleClass')
2144
+ pg = unpickle_instantiate(pg_EmptyOldstyleClass, ())
2145
+ unpickle_build(pg, {'recdict':si})
2146
+ si[pg] = 'circular_key'
2147
+ si['Circular value'] = si
2148
+ si
2149
+ result: {EmptyOldstyleClass: 'circular_key', 'Circular value': {...}}
2150
+ """
2151
+ slice = self.pop_to_mark()
2152
+ self._SETITEMS_helper(slice)
2153
+
2154
+ def _SETITEMS_helper(self, slice):
2155
+ r"""
2156
+ TESTS::
2157
+
2158
+ sage: import pickle
2159
+ sage: from sage.misc.explain_pickle import *
2160
+ sage: test_pickle(pickle.dumps({'a': 'b'})) # indirect doctest # py2
2161
+ 0: ( MARK
2162
+ 1: d DICT (MARK at 0)
2163
+ 2: p PUT 0
2164
+ 5: S STRING 'a'
2165
+ 10: p PUT 1
2166
+ 13: S STRING 'b'
2167
+ 18: p PUT 2
2168
+ 21: s SETITEM
2169
+ 22: . STOP
2170
+ highest protocol among opcodes = 0
2171
+ explain_pickle in_current_sage=True/False:
2172
+ {'a':'b'}
2173
+ result: {'a': 'b'}
2174
+ """
2175
+ updates = []
2176
+ i = 0
2177
+ while i < len(slice):
2178
+ k = slice[i]
2179
+ v = slice[i+1]
2180
+ # This marks d as immutable, if k or v happens to include d.
2181
+ self.sib(k)
2182
+ self.sib(v)
2183
+ updates.append((k, v))
2184
+ i += 2
2185
+ d = self.pop()
2186
+ if self.is_mutable_pickle_object(d) and isinstance(d.value, PickleDict):
2187
+ d.value = PickleDict(d.value.items + updates)
2188
+ d.expression = self.sib.dict(d.value.items)
2189
+ else:
2190
+ d = self.sib(d)
2191
+ for k, v in updates:
2192
+ self.sib.command(d, self.sib.assign(d[k], v))
2193
+ self.push(d)
2194
+
2195
+ def SHORT_BINSTRING(self, s):
2196
+ r"""
2197
+ TESTS::
2198
+
2199
+ sage: from sage.misc.explain_pickle import *
2200
+ sage: test_pickle(dumps('hello', compress=False)) # py2
2201
+ 0: \x80 PROTO 2
2202
+ 2: U SHORT_BINSTRING 'hello'
2203
+ 9: q BINPUT 1
2204
+ 11: . STOP
2205
+ highest protocol among opcodes = 2
2206
+ explain_pickle in_current_sage=True/False:
2207
+ 'hello'
2208
+ result: 'hello'
2209
+ """
2210
+ self.push(PickleObject(s, self.share(self.sib(s))))
2211
+
2212
+ def STOP(self):
2213
+ r"""
2214
+ TESTS::
2215
+
2216
+ sage: from pickle import *
2217
+ sage: from sage.misc.explain_pickle import *
2218
+ sage: test_pickle(EMPTY_TUPLE) # py2
2219
+ 0: ) EMPTY_TUPLE
2220
+ 1: . STOP
2221
+ highest protocol among opcodes = 1
2222
+ explain_pickle in_current_sage=True/False:
2223
+ ()
2224
+ result: ()
2225
+ """
2226
+ self.stopped = True
2227
+
2228
+ def STRING(self, s):
2229
+ r"""
2230
+ TESTS::
2231
+
2232
+ sage: from sage.misc.explain_pickle import *
2233
+ sage: test_pickle("S'Testing...'\n.") # py2
2234
+ 0: S STRING 'Testing...'
2235
+ 14: . STOP
2236
+ highest protocol among opcodes = 0
2237
+ explain_pickle in_current_sage=True/False:
2238
+ 'Testing...'
2239
+ result: 'Testing...'
2240
+ """
2241
+ self.push(PickleObject(s, self.share(self.sib(s))))
2242
+
2243
+ def TUPLE(self):
2244
+ r"""
2245
+ TESTS::
2246
+
2247
+ sage: import pickle
2248
+ sage: from sage.misc.explain_pickle import *
2249
+ sage: test_pickle(pickle.dumps(('a',))) # py2
2250
+ 0: ( MARK
2251
+ 1: S STRING 'a'
2252
+ 6: p PUT 0
2253
+ 9: t TUPLE (MARK at 0)
2254
+ 10: p PUT 1
2255
+ 13: . STOP
2256
+ highest protocol among opcodes = 0
2257
+ explain_pickle in_current_sage=True/False:
2258
+ ('a',)
2259
+ result: ('a',)
2260
+
2261
+ We prefer to produce tuple literals, as above; but if the
2262
+ tuple is recursive, we need a more complicated
2263
+ construction. It used to be the case that the cPickle
2264
+ unpickler couldn't handle this case, but that's no longer true
2265
+ (see http://bugs.python.org/issue5794)::
2266
+
2267
+ sage: v = ([],)
2268
+ sage: v[0].append(v)
2269
+ sage: test_pickle(pickle.dumps(v)) # py2
2270
+ 0: ( MARK
2271
+ 1: ( MARK
2272
+ 2: l LIST (MARK at 1)
2273
+ 3: p PUT 0
2274
+ 6: ( MARK
2275
+ 7: g GET 0
2276
+ 10: t TUPLE (MARK at 6)
2277
+ 11: p PUT 1
2278
+ 14: a APPEND
2279
+ 15: 0 POP
2280
+ 16: 0 POP (MARK at 0)
2281
+ 17: g GET 1
2282
+ 20: . STOP
2283
+ highest protocol among opcodes = 0
2284
+ explain_pickle in_current_sage=True/False:
2285
+ si1 = []
2286
+ si2 = (si1,)
2287
+ list.append(si1, si2)
2288
+ si2
2289
+ result: ([(...)],)
2290
+ """
2291
+ v = self.pop_to_mark()
2292
+ self.push(PickleObject(tuple(v), self.sib(tuple(v))))
2293
+
2294
+ def TUPLE1(self):
2295
+ r"""
2296
+ TESTS::
2297
+
2298
+ sage: from sage.misc.explain_pickle import *
2299
+ sage: test_pickle(('a',))
2300
+ 0: \x80 PROTO 2
2301
+ 2: X BINUNICODE 'a'
2302
+ 8: q BINPUT 0
2303
+ 10: \x85 TUPLE1
2304
+ 11: q BINPUT 1
2305
+ 13: . STOP
2306
+ highest protocol among opcodes = 2
2307
+ explain_pickle in_current_sage=True/False:
2308
+ ('a',)
2309
+ result: ('a',)
2310
+ """
2311
+ v1 = self.pop()
2312
+ self.push(PickleObject((v1,), self.sib((v1,))))
2313
+
2314
+ def TUPLE2(self):
2315
+ r"""
2316
+ TESTS::
2317
+
2318
+ sage: from sage.misc.explain_pickle import *
2319
+ sage: test_pickle(('a','b'))
2320
+ 0: \x80 PROTO 2
2321
+ 2: X BINUNICODE 'a'
2322
+ 8: q BINPUT 0
2323
+ 10: X BINUNICODE 'b'
2324
+ 16: q BINPUT 1
2325
+ 18: \x86 TUPLE2
2326
+ 19: q BINPUT 2
2327
+ 21: . STOP
2328
+ highest protocol among opcodes = 2
2329
+ explain_pickle in_current_sage=True/False:
2330
+ ('a', 'b')
2331
+ result: ('a', 'b')
2332
+ """
2333
+ v2 = self.pop()
2334
+ v1 = self.pop()
2335
+ self.push(PickleObject((v1, v2), self.sib((v1, v2))))
2336
+
2337
+ def TUPLE3(self):
2338
+ r"""
2339
+ TESTS::
2340
+
2341
+ sage: from sage.misc.explain_pickle import *
2342
+ sage: test_pickle(('a','b','c'))
2343
+ 0: \x80 PROTO 2
2344
+ 2: X BINUNICODE 'a'
2345
+ 8: q BINPUT 0
2346
+ 10: X BINUNICODE 'b'
2347
+ 16: q BINPUT 1
2348
+ 18: X BINUNICODE 'c'
2349
+ 24: q BINPUT 2
2350
+ 26: \x87 TUPLE3
2351
+ 27: q BINPUT 3
2352
+ 29: . STOP
2353
+ highest protocol among opcodes = 2
2354
+ explain_pickle in_current_sage=True/False:
2355
+ ('a', 'b', 'c')
2356
+ result: ('a', 'b', 'c')
2357
+ """
2358
+ v3 = self.pop()
2359
+ v2 = self.pop()
2360
+ v1 = self.pop()
2361
+ self.push(PickleObject((v1, v2, v3), self.sib((v1, v2, v3))))
2362
+
2363
+ def UNICODE(self, s):
2364
+ r"""
2365
+ TESTS::
2366
+
2367
+ sage: import pickle
2368
+ sage: from sage.misc.explain_pickle import *
2369
+ sage: test_pickle(pickle.dumps(u'hi\u1234\U00012345')) # py2
2370
+ 0: V UNICODE u'hi\u1234\U00012345'
2371
+ 20: p PUT 0
2372
+ 23: . STOP
2373
+ highest protocol among opcodes = 0
2374
+ explain_pickle in_current_sage=True/False:
2375
+ u'hi\u1234\U00012345'
2376
+ result: u'hi\u1234\U00012345'
2377
+ """
2378
+ self.push_and_share(self.sib(s))
2379
+
2380
+
2381
+ # Helper routines for explain_pickle
2382
+
2383
+ def unpickle_newobj(klass, args):
2384
+ r"""
2385
+ Create a new object; this corresponds to the C code
2386
+ ``klass->tp_new(klass, args, NULL)``. Used by :func:`explain_pickle`.
2387
+
2388
+ EXAMPLES::
2389
+
2390
+ sage: unpickle_newobj(tuple, ([1, 2, 3],))
2391
+ (1, 2, 3)
2392
+
2393
+ TESTS:
2394
+
2395
+ We can create a :class:`Sequence_generic` which would not work with
2396
+ a pure Python implementation. We just test that this does not raise
2397
+ an exception, we cannot do anything with ``s`` since ``s.__init__``
2398
+ was never called::
2399
+
2400
+ sage: from sage.structure.sequence import Sequence_generic
2401
+ sage: s = unpickle_newobj(Sequence_generic, ([1, 2, 3],))
2402
+ """
2403
+ # We need to call klass->tp_new(klass, args, NULL).
2404
+ # This is almost but not quite the same as klass.__new__(klass, *args).
2405
+ #
2406
+ # The reason is that the __new__ method does additional checking:
2407
+ # When you try to unpickle a Sequence, cPickle -- which uses the
2408
+ # former -- works, and pickle.py -- which uses the latter -- fails,
2409
+ # with
2410
+ # TypeError: sage.structure.sage_object.SageObject.__new__(Sequence) is not safe, use list.__new__()
2411
+ #
2412
+ # It seems unlikely that you can implement this from pure-Python
2413
+ # code. As a hack, we use cPickle itself to make it work.
2414
+ # (Using Cython would also work, of course; but this is cooler, and
2415
+ # probably simpler.)
2416
+
2417
+ # This pickle is: load persistent object 0, load persistent object 1,
2418
+ # NEWOBJ, STOP.
2419
+ pickle = b"P0\nP1\n\x81."
2420
+
2421
+ pers = [klass, args]
2422
+
2423
+ def pers_load(id):
2424
+ return pers[int(id)]
2425
+
2426
+ return SageUnpickler.loads(pickle, persistent_load=pers_load)
2427
+
2428
+
2429
+ def unpickle_build(obj, state):
2430
+ r"""
2431
+ Set the state of an object. Used by :func:`explain_pickle`.
2432
+
2433
+ EXAMPLES::
2434
+
2435
+ sage: from sage.misc.explain_pickle import *
2436
+ sage: v = EmptyNewstyleClass()
2437
+ sage: unpickle_build(v, {'hello': 42})
2438
+ sage: v.hello
2439
+ 42
2440
+ """
2441
+ setstate = getattr(obj, '__setstate__', None)
2442
+ if setstate is not None:
2443
+ setstate(state)
2444
+ return
2445
+
2446
+ if isinstance(state, tuple) and len(state) == 2:
2447
+ state, slots = state
2448
+ else:
2449
+ slots = None
2450
+
2451
+ if state is not None:
2452
+ assert isinstance(state, dict)
2453
+ d = obj.__dict__
2454
+ for k, v in state.items():
2455
+ d[k] = v
2456
+
2457
+ if slots is not None:
2458
+ assert isinstance(slots, dict)
2459
+ for k, v in slots.items():
2460
+ setattr(obj, k, v)
2461
+
2462
+
2463
+ def unpickle_instantiate(fn, args):
2464
+ r"""
2465
+ Instantiate a new object of class ``fn`` with arguments ``args``. Almost always
2466
+ equivalent to ``fn(*args)``. Used by :func:`explain_pickle`.
2467
+
2468
+ EXAMPLES::
2469
+
2470
+ sage: unpickle_instantiate(Integer, ('42',))
2471
+ 42
2472
+ """
2473
+ if isinstance(fn, ClassType) and not args and not hasattr(fn, '__getinitargs__'):
2474
+ # types.InstanceType doesn't exist on Python 3, but that's not
2475
+ # a problem since the above condition is always False.
2476
+ return types.InstanceType(fn)
2477
+
2478
+ return fn(*args)
2479
+
2480
+
2481
+ unpickle_persistent_loader = None
2482
+
2483
+
2484
+ def unpickle_persistent(s):
2485
+ r"""
2486
+ Take an integer index and return the persistent object with that
2487
+ index; works by calling whatever callable is stored in
2488
+ ``unpickle_persistent_loader``. Used by :func:`explain_pickle`.
2489
+
2490
+ EXAMPLES::
2491
+
2492
+ sage: import sage.misc.explain_pickle
2493
+ sage: sage.misc.explain_pickle.unpickle_persistent_loader = lambda n: n+7
2494
+ sage: unpickle_persistent(35)
2495
+ 42
2496
+ """
2497
+ return unpickle_persistent_loader(s)
2498
+
2499
+
2500
+ def unpickle_extension(code):
2501
+ r"""
2502
+ Take an integer index and return the extension object with that
2503
+ index. Used by :func:`explain_pickle`.
2504
+
2505
+ EXAMPLES::
2506
+
2507
+ sage: from copyreg import *
2508
+ sage: add_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 42)
2509
+ sage: unpickle_extension(42)
2510
+ <class 'sage.misc.explain_pickle.EmptyNewstyleClass'>
2511
+ sage: remove_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 42)
2512
+ """
2513
+ from copyreg import _inverted_registry, _extension_cache
2514
+ # copied from .get_extension() in pickle.py
2515
+ nil = []
2516
+ obj = _extension_cache.get(code, nil)
2517
+ if obj is not nil:
2518
+ return obj
2519
+ key = _inverted_registry.get(code)
2520
+ if not key:
2521
+ raise ValueError("unregistered extension code %d" % code)
2522
+ obj = unpickle_global(*key)
2523
+ _extension_cache[code] = obj
2524
+ return obj
2525
+
2526
+
2527
+ def unpickle_appends(lst, vals):
2528
+ r"""
2529
+ Given a list (or list-like object) and a sequence of values, appends the
2530
+ values to the end of the list. This is careful to do so using the
2531
+ exact same technique that cPickle would use. Used by :func:`explain_pickle`.
2532
+
2533
+ EXAMPLES::
2534
+
2535
+ sage: v = []
2536
+ sage: unpickle_appends(v, (1, 2, 3))
2537
+ sage: v
2538
+ [1, 2, 3]
2539
+ """
2540
+ if isinstance(lst, list):
2541
+ # If lst is a list (or a subtype of list)
2542
+ list.extend(lst, vals)
2543
+ else:
2544
+ append = lst.append
2545
+ for v in vals:
2546
+ append(v)
2547
+
2548
+
2549
+ def test_pickle(p, verbose_eval=False, pedantic=False, args=()):
2550
+ r"""
2551
+ Test :func:`explain_pickle` on a given pickle ``p``.
2552
+
2553
+ ``p`` can be:
2554
+
2555
+ - a string containing an uncompressed pickle (which will always end
2556
+ with a '.')
2557
+
2558
+ - a string containing a pickle fragment (not ending with '.')
2559
+ test_pickle will synthesize a pickle that will push args onto
2560
+ the stack (using persistent IDs), run the pickle fragment, and then
2561
+ STOP (if the string 'mark' occurs in args, then a mark will be pushed)
2562
+
2563
+ - an arbitrary object; :func:`test_pickle` will pickle the object
2564
+
2565
+ Once it has a pickle, :func:`test_pickle` will print the pickle's
2566
+ disassembly, run :func:`explain_pickle` with ``in_current_sage=True`` and
2567
+ ``False``, print the results, evaluate the results, unpickle the
2568
+ object with cPickle, and compare all three results.
2569
+
2570
+ If ``verbose_eval`` is ``True``, then :func:`test_pickle` will print messages
2571
+ before evaluating the pickles; this is to allow for tests where
2572
+ the unpickling prints messages (to verify that the same operations
2573
+ occur in all cases).
2574
+
2575
+ EXAMPLES::
2576
+
2577
+ sage: from sage.misc.explain_pickle import *
2578
+ sage: test_pickle(['a'])
2579
+ 0: \x80 PROTO 2
2580
+ 2: ] EMPTY_LIST
2581
+ 3: q BINPUT 0
2582
+ 5: X BINUNICODE 'a'
2583
+ 11: q BINPUT 1
2584
+ 13: a APPEND
2585
+ 14: . STOP
2586
+ highest protocol among opcodes = 2
2587
+ explain_pickle in_current_sage=True/False:
2588
+ ['a']
2589
+ result: ['a']
2590
+ """
2591
+ start = ''
2592
+ for n in range(len(args)):
2593
+ a = args[n]
2594
+ if a == 'mark':
2595
+ start += '('
2596
+ else:
2597
+ start += "P%d\n" % n
2598
+
2599
+ if isinstance(p, str):
2600
+ if p[-1] != '.':
2601
+ p = start + p + '.'
2602
+ else:
2603
+ p = dumps(p, compress=False)
2604
+
2605
+ pickletools.dis(p)
2606
+
2607
+ current = explain_pickle(p, compress=False, in_current_sage=True, pedantic=pedantic, preparse=False)
2608
+ generic = explain_pickle(p, compress=False, pedantic=pedantic, preparse=False)
2609
+
2610
+ if current == generic:
2611
+ print("explain_pickle in_current_sage=True/False:")
2612
+ print(current)
2613
+ else:
2614
+ print("explain_pickle in_current_sage=True:")
2615
+ print(current)
2616
+ print("explain_pickle in_current_sage=False:")
2617
+ print(generic)
2618
+
2619
+ def pers_load(s):
2620
+ return args[int(s)]
2621
+
2622
+ global unpickle_persistent_loader
2623
+ unpickle_persistent_loader = pers_load
2624
+
2625
+ if verbose_eval:
2626
+ print("evaluating explain_pickle in_current_sage=True:")
2627
+ current_res = sage_eval(current, preparse=False)
2628
+ if verbose_eval:
2629
+ print("evaluating explain_pickle in_current_sage=False:")
2630
+ generic_res = sage_eval(generic, preparse=False)
2631
+ if verbose_eval:
2632
+ print("loading pickle with cPickle:")
2633
+
2634
+ try:
2635
+ cpickle_res = SageUnpickler.loads(p, persistent_load=pers_load)
2636
+ cpickle_ok = True
2637
+ except Exception:
2638
+ cpickle_ok = False
2639
+
2640
+ current_repr = repr(current_res)
2641
+ generic_repr = repr(generic_res)
2642
+
2643
+ if cpickle_ok:
2644
+ cpickle_repr = repr(cpickle_res)
2645
+
2646
+ assert current_repr == generic_repr == cpickle_repr
2647
+
2648
+ print("result: " + current_repr)
2649
+ else:
2650
+ assert current_repr == generic_repr
2651
+ print("result: " + current_repr + " (cPickle raised an exception!)")
2652
+
2653
+
2654
+ class EmptyOldstyleClass:
2655
+ r"""
2656
+ A featureless old-style class (does not inherit from object); used for
2657
+ testing :func:`explain_pickle`.
2658
+ """
2659
+ def __repr__(self):
2660
+ r"""
2661
+ Print an EmptyOldstyleClass.
2662
+
2663
+ EXAMPLES::
2664
+
2665
+ sage: from sage.misc.explain_pickle import *
2666
+ sage: v = EmptyOldstyleClass()
2667
+ sage: v
2668
+ EmptyOldstyleClass
2669
+ sage: repr(v)
2670
+ 'EmptyOldstyleClass'
2671
+ sage: v.__repr__()
2672
+ 'EmptyOldstyleClass'
2673
+ """
2674
+ return "EmptyOldstyleClass"
2675
+
2676
+ def __hash__(self):
2677
+ r"""
2678
+ Produce a predictable hash value for EmptyOldstyleClass.
2679
+
2680
+ EXAMPLES::
2681
+
2682
+ sage: from sage.misc.explain_pickle import *
2683
+ sage: v = EmptyOldstyleClass()
2684
+ sage: hash(v)
2685
+ 0
2686
+ sage: v.__hash__()
2687
+ 0
2688
+ """
2689
+ return 0
2690
+
2691
+
2692
+ class EmptyNewstyleClass:
2693
+ r"""
2694
+ A featureless new-style class (inherits from object); used for
2695
+ testing :func:`explain_pickle`.
2696
+ """
2697
+ def __repr__(self):
2698
+ r"""
2699
+ Print an EmptyNewstyleClass.
2700
+
2701
+ EXAMPLES::
2702
+
2703
+ sage: from sage.misc.explain_pickle import *
2704
+ sage: v = EmptyNewstyleClass()
2705
+ sage: v
2706
+ EmptyNewstyleClass
2707
+ sage: repr(v)
2708
+ 'EmptyNewstyleClass'
2709
+ sage: v.__repr__()
2710
+ 'EmptyNewstyleClass'
2711
+ """
2712
+ return "EmptyNewstyleClass"
2713
+
2714
+
2715
+ class TestReduceGetinitargs:
2716
+ r"""
2717
+ An old-style class with a :func:`__getinitargs__` method. Used for testing
2718
+ :func:`explain_pickle`.
2719
+ """
2720
+ def __init__(self):
2721
+ r"""
2722
+ Initialize a TestReduceGetinitargs object. Note that the
2723
+ constructor prints out a message.
2724
+
2725
+ EXAMPLES::
2726
+
2727
+ sage: from sage.misc.explain_pickle import *
2728
+ sage: TestReduceGetinitargs()
2729
+ Running __init__ for TestReduceGetinitargs
2730
+ TestReduceGetinitargs
2731
+ """
2732
+ print("Running __init__ for TestReduceGetinitargs")
2733
+
2734
+ def __getinitargs__(self):
2735
+ r"""
2736
+ A simple __getinitargs__ method, used for testing explain_pickle.
2737
+
2738
+ EXAMPLES::
2739
+
2740
+ sage: from sage.misc.explain_pickle import *
2741
+ sage: v = TestReduceGetinitargs()
2742
+ Running __init__ for TestReduceGetinitargs
2743
+ sage: v.__getinitargs__()
2744
+ ()
2745
+ """
2746
+ return ()
2747
+
2748
+ def __repr__(self):
2749
+ r"""
2750
+ Print a TestReduceGetinitargs.
2751
+
2752
+ EXAMPLES::
2753
+
2754
+ sage: from sage.misc.explain_pickle import *
2755
+ sage: v = TestReduceGetinitargs()
2756
+ Running __init__ for TestReduceGetinitargs
2757
+ sage: v
2758
+ TestReduceGetinitargs
2759
+ sage: repr(v)
2760
+ 'TestReduceGetinitargs'
2761
+ sage: v.__repr__()
2762
+ 'TestReduceGetinitargs'
2763
+ """
2764
+ return "TestReduceGetinitargs"
2765
+
2766
+
2767
+ class TestReduceNoGetinitargs:
2768
+ r"""
2769
+ An old-style class with no :meth:`__getinitargs__` method. Used for testing
2770
+ :func:`explain_pickle`.
2771
+ """
2772
+ def __init__(self):
2773
+ r"""
2774
+ Initialize a TestReduceNoGetinitargs object. Note that the
2775
+ constructor prints out a message.
2776
+
2777
+ EXAMPLES::
2778
+
2779
+ sage: from sage.misc.explain_pickle import *
2780
+ sage: TestReduceNoGetinitargs()
2781
+ Running __init__ for TestReduceNoGetinitargs
2782
+ TestReduceNoGetinitargs
2783
+ """
2784
+ print("Running __init__ for TestReduceNoGetinitargs")
2785
+
2786
+ def __repr__(self):
2787
+ r"""
2788
+ Print a TestReduceNoGetinitargs.
2789
+
2790
+ EXAMPLES::
2791
+
2792
+ sage: from sage.misc.explain_pickle import *
2793
+ sage: v = TestReduceNoGetinitargs()
2794
+ Running __init__ for TestReduceNoGetinitargs
2795
+ sage: v
2796
+ TestReduceNoGetinitargs
2797
+ sage: repr(v)
2798
+ 'TestReduceNoGetinitargs'
2799
+ sage: v.__repr__()
2800
+ 'TestReduceNoGetinitargs'
2801
+ """
2802
+ return "TestReduceNoGetinitargs"
2803
+
2804
+
2805
+ class TestAppendList(list):
2806
+ r"""
2807
+ A subclass of :class:`list`, with deliberately-broken append and extend methods.
2808
+ Used for testing :func:`explain_pickle`.
2809
+ """
2810
+ def append(self):
2811
+ r"""
2812
+ A deliberately broken append method.
2813
+
2814
+ EXAMPLES::
2815
+
2816
+ sage: from sage.misc.explain_pickle import *
2817
+ sage: v = TestAppendList()
2818
+ sage: v.append(7)
2819
+ Traceback (most recent call last):
2820
+ ...
2821
+ TypeError: ...append() takes 1 positional argument but 2 were given
2822
+
2823
+ We can still append by directly using the list method::
2824
+
2825
+ sage: list.append(v, 7)
2826
+ sage: v
2827
+ [7]
2828
+ """
2829
+ raise NotImplementedError
2830
+
2831
+ def extend(self):
2832
+ r"""
2833
+ A deliberately broken extend method.
2834
+
2835
+ EXAMPLES::
2836
+
2837
+ sage: from sage.misc.explain_pickle import *
2838
+ sage: v = TestAppendList()
2839
+ sage: v.extend([3,1,4,1,5,9])
2840
+ Traceback (most recent call last):
2841
+ ...
2842
+ TypeError: ...extend() takes 1 positional argument but 2 were given
2843
+
2844
+ We can still extend by directly using the list method::
2845
+
2846
+ sage: list.extend(v, (3,1,4,1,5,9))
2847
+ sage: v
2848
+ [3, 1, 4, 1, 5, 9]
2849
+ """
2850
+ raise NotImplementedError
2851
+
2852
+
2853
+ class TestAppendNonlist:
2854
+ r"""
2855
+ A list-like class, carefully designed to test exact unpickling
2856
+ behavior. Used for testing :func:`explain_pickle`.
2857
+ """
2858
+ def __init__(self):
2859
+ r"""
2860
+ Construct a TestAppendNonlist.
2861
+
2862
+ EXAMPLES::
2863
+
2864
+ sage: from sage.misc.explain_pickle import *
2865
+ sage: v = TestAppendNonlist()
2866
+ sage: v
2867
+ []
2868
+ """
2869
+ self.list = []
2870
+
2871
+ def __getattr__(self, a):
2872
+ r"""
2873
+ Get an 'append' method from a TestAppendNonlist. We have this
2874
+ method so that we can distinguish how many times the append method
2875
+ is fetched.
2876
+
2877
+ EXAMPLES::
2878
+
2879
+ sage: from sage.misc.explain_pickle import *
2880
+ sage: v = TestAppendNonlist()
2881
+ sage: v.append(1)
2882
+ Fetching append attribute
2883
+ sage: v.append(2)
2884
+ Fetching append attribute
2885
+ sage: app = v.append
2886
+ Fetching append attribute
2887
+ sage: app(3)
2888
+ sage: app(4)
2889
+ sage: v
2890
+ [1, 2, 3, 4]
2891
+ """
2892
+ if a == 'append':
2893
+ print("Fetching append attribute")
2894
+ return self.list.append
2895
+
2896
+ raise AttributeError
2897
+
2898
+ def __reduce__(self):
2899
+ r"""
2900
+ Implement __reduce__ for TestAppendNonlist. Note that the
2901
+ loads(dumps(...)) test only fetches the append method once.
2902
+
2903
+ EXAMPLES::
2904
+
2905
+ sage: from sage.misc.explain_pickle import *
2906
+ sage: v = TestAppendNonlist()
2907
+ sage: v.list = [1,2,3,4]
2908
+ sage: v.__reduce__()
2909
+ (<class 'sage.misc.explain_pickle.TestAppendNonlist'>, (), None, <...iterator object at 0x...>)
2910
+ sage: list(v.__reduce__()[3])
2911
+ [1, 2, 3, 4]
2912
+ sage: loads(dumps(v))
2913
+ Fetching append attribute
2914
+ [1, 2, 3, 4]
2915
+ """
2916
+ return (TestAppendNonlist, (), None, iter(self.list))
2917
+
2918
+ def __repr__(self):
2919
+ r"""
2920
+ Print a TestAppendNonlist. Just prints as its underlying list.
2921
+
2922
+ EXAMPLES::
2923
+
2924
+ sage: from sage.misc.explain_pickle import *
2925
+ sage: v = TestAppendNonlist()
2926
+ sage: v.list = ['hello', 'world']
2927
+ sage: v
2928
+ ['hello', 'world']
2929
+ sage: repr(v)
2930
+ "['hello', 'world']"
2931
+ sage: v.__repr__()
2932
+ "['hello', 'world']"
2933
+ """
2934
+ return repr(self.list)
2935
+
2936
+
2937
+ class TestBuild:
2938
+ r"""
2939
+ A simple class with a :meth:`__getstate__` but no :meth:`__setstate__`. Used for testing
2940
+ :func:`explain_pickle`.
2941
+ """
2942
+ def __getstate__(self):
2943
+ r"""
2944
+ A __getstate__ method for testing pickling.
2945
+
2946
+ EXAMPLES::
2947
+
2948
+ sage: from sage.misc.explain_pickle import *
2949
+ sage: TestBuild().__getstate__()
2950
+ ({'x': 3}, {'y': 4})
2951
+ sage: loads(dumps(TestBuild()))
2952
+ TestBuild: x=3; y=4
2953
+ """
2954
+ return ({'x': 3}, {'y': 4})
2955
+
2956
+ def __repr__(self):
2957
+ r"""
2958
+ Print a TestBuild.
2959
+
2960
+ EXAMPLES::
2961
+
2962
+ sage: from sage.misc.explain_pickle import *
2963
+ sage: v = TestBuild()
2964
+ sage: v
2965
+ TestBuild: x=None; y=None
2966
+ sage: repr(v)
2967
+ 'TestBuild: x=None; y=None'
2968
+ sage: v.__repr__()
2969
+ 'TestBuild: x=None; y=None'
2970
+ """
2971
+ return "TestBuild: x=%s; y=%s" % (getattr(self, 'x', None), getattr(self, 'y', None))
2972
+
2973
+
2974
+ class TestBuildSetstate(TestBuild):
2975
+ r"""
2976
+ A simple class with a :meth:`__getstate__` and a :meth:`__setstate__`. Used for testing
2977
+ :func:`explain_pickle`.
2978
+ """
2979
+ def __setstate__(self, state):
2980
+ r"""
2981
+ Set the state of a TestBuildSetstate. Both prints a message, and
2982
+ swaps x and y, to verify that it is being called.
2983
+
2984
+ EXAMPLES::
2985
+
2986
+ sage: from sage.misc.explain_pickle import *
2987
+ sage: loads(dumps(TestBuildSetstate())) # indirect doctest
2988
+ setting state from ({'x': 3}, {'y': 4})
2989
+ TestBuild: x=4; y=3
2990
+ """
2991
+ print("setting state from {}".format(state))
2992
+ # Swap x and y, just for fun
2993
+ self.x = state[1]['y']
2994
+ self.y = state[0]['x']
2995
+
2996
+
2997
+ class TestGlobalOldName:
2998
+ r"""
2999
+ A featureless new-style class. When you try to unpickle an instance
3000
+ of this class, it is redirected to create a :class:`TestGlobalNewName` instead.
3001
+ Used for testing :func:`explain_pickle`.
3002
+
3003
+ EXAMPLES::
3004
+
3005
+ sage: from sage.misc.explain_pickle import *
3006
+ sage: loads(dumps(TestGlobalOldName()))
3007
+ TestGlobalNewName
3008
+ """
3009
+ pass
3010
+
3011
+
3012
+ class TestGlobalNewName:
3013
+ r"""
3014
+ A featureless new-style class. When you try to unpickle an instance
3015
+ of :class:`TestGlobalOldName`, it is redirected to create an instance of this
3016
+ class instead. Used for testing :func:`explain_pickle`.
3017
+
3018
+ EXAMPLES::
3019
+
3020
+ sage: from sage.misc.explain_pickle import *
3021
+ sage: loads(dumps(TestGlobalOldName()))
3022
+ TestGlobalNewName
3023
+ """
3024
+ def __repr__(self):
3025
+ r"""
3026
+ Print a TestGlobalNewName.
3027
+
3028
+ EXAMPLES::
3029
+
3030
+ sage: from sage.misc.explain_pickle import *
3031
+ sage: v = TestGlobalNewName()
3032
+ sage: v
3033
+ TestGlobalNewName
3034
+ sage: repr(v)
3035
+ 'TestGlobalNewName'
3036
+ sage: v.__repr__()
3037
+ 'TestGlobalNewName'
3038
+ """
3039
+ return "TestGlobalNewName"
3040
+
3041
+
3042
+ register_unpickle_override('sage.misc.explain_pickle', 'TestGlobalOldName', TestGlobalNewName, call_name=('sage.misc.explain_pickle', 'TestGlobalNewName'))
3043
+
3044
+
3045
+ class TestGlobalFunnyName:
3046
+ r"""
3047
+ A featureless new-style class which has a name that's not a legal
3048
+ Python identifier.
3049
+
3050
+ EXAMPLES::
3051
+
3052
+ sage: from sage.misc.explain_pickle import *
3053
+ sage: globals()['funny$name'] = TestGlobalFunnyName # see comment at end of file
3054
+ sage: TestGlobalFunnyName.__name__
3055
+ 'funny$name'
3056
+ sage: globals()['funny$name'] is TestGlobalFunnyName
3057
+ True
3058
+ """
3059
+ def __repr__(self):
3060
+ r"""
3061
+ Print a TestGlobalFunnyName.
3062
+
3063
+ EXAMPLES::
3064
+
3065
+ sage: from sage.misc.explain_pickle import *
3066
+ sage: v = TestGlobalFunnyName()
3067
+ sage: v
3068
+ TestGlobalFunnyName
3069
+ sage: repr(v)
3070
+ 'TestGlobalFunnyName'
3071
+ sage: v.__repr__()
3072
+ 'TestGlobalFunnyName'
3073
+ """
3074
+ return "TestGlobalFunnyName"
3075
+
3076
+
3077
+ TestGlobalFunnyName.__name__ = "funny$name"
3078
+ # This crashed Sphinx. Instead, we manually execute this just before the test.
3079
+ # globals()['funny$name'] = TestGlobalFunnyName