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