Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/misc/explain_pickle.py
4045 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
# def explain_picklejar(dir, catch_exceptions=True):
2383
# r"""
2384
# Given a directory or a .tar.bz2 of pickles, we unpickle each of
2385
# them three times: once with cPickle, once with explain_pickle
2386
# with in_current_sage=True, and once with explain_pickle
2387
# with in_current_sage=False.
2388
2389
# We verify that each of these gives the same answer (where we check
2390
# using repr(a)==repr(b), in case equality is not defined on all
2391
# of these objects).
2392
2393
# INPUT::
2394
2395
# dir -- string; a directory or name of a .tar.bz2 file that
2396
# decompresses to give a directory full of pickles.
2397
# catch_exceptions -- boolean; default True: if True, then
2398
# unpickling exceptions will be caught (and if all three
2399
# unpicklers raise an exception, then that will be counted
2400
# as a match). If False, then exceptions will not be caught,
2401
# and will terminate this function.
2402
2403
# EXAMPLES:
2404
# sage: std = os.environ['SAGE_DATA'] + '/extcode/pickle_jar/pickle_jar.tar.bz2'
2405
# sage: from sage.misc.explain_pickle import *
2406
# sage: explain_picklejar(std) # long time (~45s on my computer)
2407
# doctest:...: DeprecationWarning: Your data is stored in an old format. Please use the save() function to store your data in a more recent format.
2408
# doctest:...: DeprecationWarning: Your data is stored in an old format. Please use the save() function to store your data in a more recent format.
2409
# 4... matches; 0 mismatches
2410
# """
2411
# # Largely copied from unpickle_all in sage_object.pyx
2412
2413
# from sage.structure.sage_object import load
2414
2415
# obj_at = re.compile('object at 0x[0-9a-f]+')
2416
2417
# n_success = 0
2418
# failed = []
2419
# if dir.endswith('.tar.bz2'):
2420
# # create a temporary directory
2421
# from sage.misc.all import tmp_dir
2422
# T = tmp_dir()
2423
# # extract tarball to it
2424
# os.system('cd "%s"; bunzip2 -c "%s" | tar fx - '%(T, os.path.abspath(dir)))
2425
# # Now use the directory in the tarball instead of dir
2426
# dir = T + "/" + os.listdir(T)[0]
2427
2428
# for A in os.listdir(dir):
2429
# if A.endswith('.sobj'):
2430
# fn = dir + '/' + A
2431
# try:
2432
# v1 = load(fn)
2433
# v1r = repr(v1)
2434
# except Exception, msg:
2435
# # if not catch_exceptions: raise
2436
# v1r = 'error'
2437
2438
# try:
2439
# exp_current = explain_pickle(file=fn, in_current_sage=True)
2440
# import sys
2441
# sys.stderr.write(exp_current)
2442
# v2 = sage_eval(exp_current)
2443
# v2r = repr(v2)
2444
# except Exception, msg:
2445
# if not catch_exceptions: raise
2446
# v2r = 'error'
2447
2448
# try:
2449
# exp_generic = explain_pickle(file=fn)
2450
# import sys
2451
# sys.stderr.write(exp_generic)
2452
# v3 = sage_eval(exp_generic)
2453
# v3r = repr(v3)
2454
# except Exception, msg:
2455
# if not catch_exceptions: raise
2456
# v3r = 'error'
2457
2458
# v1r = obj_at.sub('object at 0x...', v1r)
2459
# v2r = obj_at.sub('object at 0x...', v2r)
2460
# v3r = obj_at.sub('object at 0x...', v3r)
2461
2462
# if v1r == v2r == v3r:
2463
# n_success += 1
2464
# else:
2465
# print "Mismatch on %s" % fn
2466
# print v1r, v2r, v3r
2467
# failed.append(A)
2468
2469
# print "%d matches; %d mismatches" % (n_success, len(failed))
2470
# print '\n'.join(failed)
2471
2472
# Helper routines for explain_pickle
2473
2474
def unpickle_newobj(klass, args):
2475
r"""
2476
Create a new object; this corresponds to the C code
2477
klass->tp_new(klass, args, NULL). Used by ``explain_pickle``.
2478
2479
EXAMPLES:
2480
sage: unpickle_newobj(tuple, ([1, 2, 3],))
2481
(1, 2, 3)
2482
"""
2483
# We need to call klass->tp_new(klass, args, NULL).
2484
# This is almost but not quite the same as klass.__new__(klass, *args).
2485
# (I don't know exactly what the difference is, but when you try
2486
# to unpickle a Sequence, cPickle -- which uses the former -- works,
2487
# and pickle.py -- which uses the latter -- fails, with
2488
# TypeError: sage.structure.sage_object.SageObject.__new__(Sequence) is not safe, use list.__new__()
2489
# )
2490
2491
# It seems unlikely that you can implement this from pure-Python code --
2492
# somewhat disturbingly, it actually is possible. This shows how.
2493
# (Using Cython would also work, of course; but this is cooler, and
2494
# probably simpler.)
2495
2496
# This pickle is: load persistent object 0, load persistent object 1,
2497
# NEWOBJ, STOP.
2498
pickle = "P0\nP1\n\x81."
2499
2500
pers = [klass, args]
2501
2502
pers_load = lambda id: pers[int(id)]
2503
2504
from cStringIO import StringIO
2505
import cPickle
2506
unp = cPickle.Unpickler(StringIO(pickle))
2507
unp.persistent_load = pers_load
2508
return unp.load()
2509
2510
def unpickle_build(obj, state):
2511
r"""
2512
Set the state of an object. Used by ``explain_pickle``.
2513
2514
EXAMPLES::
2515
2516
sage: from sage.misc.explain_pickle import *
2517
sage: v = EmptyNewstyleClass()
2518
sage: unpickle_build(v, {'hello': 42})
2519
sage: v.hello
2520
42
2521
"""
2522
setstate = getattr(obj, '__setstate__', None)
2523
if setstate is not None:
2524
setstate(state)
2525
return
2526
2527
if isinstance(state, tuple) and len(state) == 2:
2528
state, slots = state
2529
else:
2530
slots = None
2531
2532
if state is not None:
2533
assert(isinstance(state, dict))
2534
d = obj.__dict__
2535
for k,v in state.iteritems():
2536
d[k] = v
2537
2538
if slots is not None:
2539
assert(isinstance(slots, dict))
2540
for k,v in slots.iteritems():
2541
setattr(obj, k, v)
2542
2543
def unpickle_instantiate(fn, args):
2544
r"""
2545
Instantiate a new object of class fn with arguments args. Almost always
2546
equivalent to ``fn(*args)``. Used by ``explain_pickle``.
2547
2548
EXAMPLES::
2549
2550
sage: unpickle_instantiate(Integer, ('42',))
2551
42
2552
"""
2553
if isinstance(fn, types.ClassType) and len(args) == 0 and not hasattr(fn, '__getinitargs__'):
2554
return types.InstanceType(fn)
2555
2556
return fn(*args)
2557
2558
unpickle_persistent_loader = None
2559
2560
def unpickle_persistent(s):
2561
r"""
2562
Takes an integer index and returns the persistent object with that
2563
index; works by calling whatever callable is stored in
2564
unpickle_persistent_loader. Used by ``explain_pickle``.
2565
2566
EXAMPLES::
2567
2568
sage: import sage.misc.explain_pickle
2569
sage: sage.misc.explain_pickle.unpickle_persistent_loader = lambda n: n+7
2570
sage: unpickle_persistent(35)
2571
42
2572
"""
2573
return unpickle_persistent_loader(s)
2574
2575
def unpickle_extension(code):
2576
r"""
2577
Takes an integer index and returns the extension object with that
2578
index. Used by ``explain_pickle``.
2579
2580
EXAMPLES::
2581
2582
sage: from copy_reg import *
2583
sage: add_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 42)
2584
sage: unpickle_extension(42)
2585
<class 'sage.misc.explain_pickle.EmptyNewstyleClass'>
2586
sage: remove_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 42)
2587
"""
2588
from copy_reg import _inverted_registry, _extension_cache
2589
# copied from .get_extension() in pickle.py
2590
nil = []
2591
obj = _extension_cache.get(code, nil)
2592
if obj is not nil:
2593
return obj
2594
key = _inverted_registry.get(code)
2595
if not key:
2596
raise ValueError("unregistered extension code %d" % code)
2597
obj = unpickle_global(*key)
2598
_extension_cache[code] = obj
2599
return obj
2600
2601
def unpickle_appends(lst, vals):
2602
r"""
2603
Given a list (or list-like object) and a sequence of values, appends the
2604
values to the end of the list. This is careful to do so using the
2605
exact same technique that cPickle would use. Used by ``explain_pickle``.
2606
2607
EXAMPLES::
2608
2609
sage: v = []
2610
sage: unpickle_appends(v, (1, 2, 3))
2611
sage: v
2612
[1, 2, 3]
2613
"""
2614
if isinstance(lst, list):
2615
# If lst is a list (or a subtype of list)
2616
list.extend(lst, vals)
2617
else:
2618
append = lst.append
2619
for v in vals:
2620
append(v)
2621
2622
def test_pickle(p, verbose_eval=False, pedantic=False, args=()):
2623
r"""
2624
Tests explain_pickle on a given pickle p. p can be:
2625
2626
- a string containing an uncompressed pickle (which will always end
2627
with a '.')
2628
2629
- a string containing a pickle fragment (not ending with '.')
2630
test_pickle will synthesize a pickle that will push args onto
2631
the stack (using persistent IDs), run the pickle fragment, and then
2632
STOP (if the string 'mark' occurs in args, then a mark will be pushed)
2633
2634
- an arbitrary object; test_pickle will pickle the object
2635
2636
Once it has a pickle, test_pickle will print the pickle's
2637
disassembly, run explain_pickle with in_current_sage=True and
2638
False, print the results, evaluate the results, unpickle the
2639
object with cPickle, and compare all three results.
2640
2641
If verbose_eval is True, then test_pickle will print messages
2642
before evaluating the pickles; this is to allow for tests where
2643
the unpickling prints messages (to verify that the same operations
2644
occur in all cases).
2645
2646
EXAMPLES::
2647
2648
sage: from sage.misc.explain_pickle import *
2649
sage: test_pickle(['a'])
2650
0: \x80 PROTO 2
2651
2: ] EMPTY_LIST
2652
3: q BINPUT 1
2653
5: U SHORT_BINSTRING 'a'
2654
8: a APPEND
2655
9: . STOP
2656
highest protocol among opcodes = 2
2657
explain_pickle in_current_sage=True/False:
2658
['a']
2659
result: ['a']
2660
"""
2661
start = ''
2662
for n in range(len(args)):
2663
a = args[n]
2664
if a == 'mark':
2665
start += '('
2666
else:
2667
start += "P%d\n" % n
2668
2669
if isinstance(p, str):
2670
if p[-1] != '.':
2671
p = start + p + '.'
2672
else:
2673
p = dumps(p, compress=False)
2674
2675
pickletools.dis(p)
2676
2677
current = explain_pickle(p, compress=False, in_current_sage=True, pedantic=pedantic, preparse=False)
2678
generic = explain_pickle(p, compress=False, pedantic=pedantic, preparse=False)
2679
2680
if current == generic:
2681
print "explain_pickle in_current_sage=True/False:"
2682
print current
2683
else:
2684
print "explain_pickle in_current_sage=True:"
2685
print current
2686
print "explain_pickle in_current_sage=False:"
2687
print generic
2688
2689
pers_load = lambda s: args[int(s)]
2690
2691
global unpickle_persistent_loader
2692
unpickle_persistent_loader = pers_load
2693
2694
if verbose_eval: print "evaluating explain_pickle in_current_sage=True:"
2695
current_res = sage_eval(current, preparse=False)
2696
if verbose_eval: print "evaluating explain_pickle in_current_sage=False:"
2697
generic_res = sage_eval(generic, preparse=False)
2698
if verbose_eval: print "loading pickle with cPickle:"
2699
from cStringIO import StringIO
2700
import cPickle
2701
unp = cPickle.Unpickler(StringIO(p))
2702
unp.persistent_load = pers_load
2703
unp.find_global = unpickle_global
2704
try:
2705
cpickle_res = unp.load()
2706
cpickle_ok = True
2707
except:
2708
cpickle_ok = False
2709
2710
current_repr = repr(current_res)
2711
generic_repr = repr(generic_res)
2712
2713
if cpickle_ok:
2714
cpickle_repr = repr(cpickle_res)
2715
2716
assert(current_repr == generic_repr == cpickle_repr)
2717
2718
print "result: " + current_repr
2719
else:
2720
assert(current_repr == generic_repr)
2721
print "result: " + current_repr + " (cPickle raised an exception!)"
2722
2723
class EmptyOldstyleClass:
2724
r"""
2725
A featureless old-style class (does not inherit from object); used for
2726
testing explain_pickle.
2727
"""
2728
def __repr__(self):
2729
r"""
2730
Print an EmptyOldstyleClass.
2731
2732
EXAMPLES:
2733
sage: from sage.misc.explain_pickle import *
2734
sage: v = EmptyOldstyleClass()
2735
sage: v
2736
EmptyOldstyleClass
2737
sage: repr(v)
2738
'EmptyOldstyleClass'
2739
sage: v.__repr__()
2740
'EmptyOldstyleClass'
2741
"""
2742
return "EmptyOldstyleClass"
2743
2744
def __hash__(self):
2745
r"""
2746
Produce a predictable hash value for EmptyOldstyleClass.
2747
2748
EXAMPLES:
2749
sage: from sage.misc.explain_pickle import *
2750
sage: v = EmptyOldstyleClass()
2751
sage: hash(v)
2752
0
2753
sage: v.__hash__()
2754
0
2755
"""
2756
return 0
2757
2758
class EmptyNewstyleClass(object):
2759
r"""
2760
A featureless new-style class (inherits from object); used for
2761
testing explain_pickle.
2762
"""
2763
def __repr__(self):
2764
r"""
2765
Print an EmptyNewstyleClass.
2766
2767
EXAMPLES::
2768
2769
sage: from sage.misc.explain_pickle import *
2770
sage: v = EmptyNewstyleClass()
2771
sage: v
2772
EmptyNewstyleClass
2773
sage: repr(v)
2774
'EmptyNewstyleClass'
2775
sage: v.__repr__()
2776
'EmptyNewstyleClass'
2777
"""
2778
return "EmptyNewstyleClass"
2779
2780
class TestReduceGetinitargs:
2781
r"""
2782
An old-style class with a __getinitargs__ method. Used for testing
2783
explain_pickle.
2784
"""
2785
def __init__(self):
2786
r"""
2787
Initialize a TestReduceGetinitargs object. Note that the
2788
constructor prints out a message.
2789
2790
EXAMPLES::
2791
2792
sage: from sage.misc.explain_pickle import *
2793
sage: TestReduceGetinitargs()
2794
Running __init__ for TestReduceGetinitargs
2795
TestReduceGetinitargs
2796
"""
2797
print "Running __init__ for TestReduceGetinitargs"
2798
2799
def __getinitargs__(self):
2800
r"""
2801
A simple __getinitargs__ method, used for testing explain_pickle.
2802
2803
EXAMPLES::
2804
2805
sage: from sage.misc.explain_pickle import *
2806
sage: v = TestReduceGetinitargs()
2807
Running __init__ for TestReduceGetinitargs
2808
sage: v.__getinitargs__()
2809
()
2810
"""
2811
return ()
2812
2813
def __repr__(self):
2814
r"""
2815
Print a TestReduceGetinitargs.
2816
2817
EXAMPLES::
2818
2819
sage: from sage.misc.explain_pickle import *
2820
sage: v = TestReduceGetinitargs()
2821
Running __init__ for TestReduceGetinitargs
2822
sage: v
2823
TestReduceGetinitargs
2824
sage: repr(v)
2825
'TestReduceGetinitargs'
2826
sage: v.__repr__()
2827
'TestReduceGetinitargs'
2828
"""
2829
return "TestReduceGetinitargs"
2830
2831
class TestReduceNoGetinitargs:
2832
r"""
2833
An old-style class with no __getinitargs__ method. Used for testing
2834
explain_pickle.
2835
"""
2836
def __init__(self):
2837
r"""
2838
Initialize a TestReduceNoGetinitargs object. Note that the
2839
constructor prints out a message.
2840
2841
EXAMPLES::
2842
2843
sage: from sage.misc.explain_pickle import *
2844
sage: TestReduceNoGetinitargs()
2845
Running __init__ for TestReduceNoGetinitargs
2846
TestReduceNoGetinitargs
2847
"""
2848
print "Running __init__ for TestReduceNoGetinitargs"
2849
2850
def __repr__(self):
2851
r"""
2852
Print a TestReduceNoGetinitargs.
2853
2854
EXAMPLES::
2855
2856
sage: from sage.misc.explain_pickle import *
2857
sage: v = TestReduceNoGetinitargs()
2858
Running __init__ for TestReduceNoGetinitargs
2859
sage: v
2860
TestReduceNoGetinitargs
2861
sage: repr(v)
2862
'TestReduceNoGetinitargs'
2863
sage: v.__repr__()
2864
'TestReduceNoGetinitargs'
2865
"""
2866
return "TestReduceNoGetinitargs"
2867
2868
class TestAppendList(list):
2869
r"""
2870
A subclass of list, with deliberately-broken append and extend methods.
2871
Used for testing explain_pickle.
2872
"""
2873
def append(self):
2874
r"""
2875
A deliberately broken append method.
2876
2877
EXAMPLES::
2878
2879
sage: from sage.misc.explain_pickle import *
2880
sage: v = TestAppendList()
2881
sage: v.append(7)
2882
Traceback (most recent call last):
2883
...
2884
TypeError: append() takes exactly 1 argument (2 given)
2885
2886
We can still append by directly using the list method:
2887
sage: list.append(v, 7)
2888
sage: v
2889
[7]
2890
"""
2891
raise NotImplementedError
2892
2893
def extend(self):
2894
r"""
2895
A deliberately broken extend method.
2896
2897
EXAMPLES::
2898
2899
sage: from sage.misc.explain_pickle import *
2900
sage: v = TestAppendList()
2901
sage: v.extend([3,1,4,1,5,9])
2902
Traceback (most recent call last):
2903
...
2904
TypeError: extend() takes exactly 1 argument (2 given)
2905
2906
We can still extend by directly using the list method:
2907
sage: list.extend(v, (3,1,4,1,5,9))
2908
sage: v
2909
[3, 1, 4, 1, 5, 9]
2910
"""
2911
raise NotImplementedError
2912
2913
class TestAppendNonlist(object):
2914
r"""
2915
A list-like class, carefully designed to test exact unpickling
2916
behavior. Used for testing explain_pickle.
2917
"""
2918
def __init__(self):
2919
r"""
2920
Construct a TestAppendNonlist.
2921
2922
EXAMPLES::
2923
2924
sage: from sage.misc.explain_pickle import *
2925
sage: v = TestAppendNonlist()
2926
sage: v
2927
[]
2928
"""
2929
self.list = []
2930
2931
def __getattr__(self, a):
2932
r"""
2933
Get an 'append' method from a TestAppendNonlist. We have this
2934
method so that we can distinguish how many times the append method
2935
is fetched.
2936
2937
EXAMPLES::
2938
2939
sage: from sage.misc.explain_pickle import *
2940
sage: v = TestAppendNonlist()
2941
sage: v.append(1)
2942
Fetching append attribute
2943
sage: v.append(2)
2944
Fetching append attribute
2945
sage: app = v.append
2946
Fetching append attribute
2947
sage: app(3)
2948
sage: app(4)
2949
sage: v
2950
[1, 2, 3, 4]
2951
"""
2952
if a == 'append':
2953
print "Fetching append attribute"
2954
return self.list.append
2955
2956
raise AttributeError
2957
2958
def __reduce__(self):
2959
r"""
2960
Implement __reduce__ for TestAppendNonlist. Note that the
2961
loads(dumps(...)) test only fetches the append method once.
2962
2963
EXAMPLES::
2964
2965
sage: from sage.misc.explain_pickle import *
2966
sage: v = TestAppendNonlist()
2967
sage: v.list = [1,2,3,4]
2968
sage: v.__reduce__()
2969
(<class 'sage.misc.explain_pickle.TestAppendNonlist'>, (), None, <listiterator object at 0x...>)
2970
sage: list(v.__reduce__()[3])
2971
[1, 2, 3, 4]
2972
sage: loads(dumps(v))
2973
Fetching append attribute
2974
[1, 2, 3, 4]
2975
"""
2976
return (TestAppendNonlist, (), None, iter(self.list))
2977
2978
def __repr__(self):
2979
r"""
2980
Print a TestAppendNonlist. Just prints as its underlying list.
2981
2982
EXAMPLES::
2983
2984
sage: from sage.misc.explain_pickle import *
2985
sage: v = TestAppendNonlist()
2986
sage: v.list = ['hello', 'world']
2987
sage: v
2988
['hello', 'world']
2989
sage: repr(v)
2990
"['hello', 'world']"
2991
sage: v.__repr__()
2992
"['hello', 'world']"
2993
"""
2994
return repr(self.list)
2995
2996
class TestBuild(object):
2997
r"""
2998
A simple class with a __getstate__ but no __setstate__. Used for testing
2999
explain_pickle.
3000
"""
3001
def __getstate__(self):
3002
r"""
3003
A __getstate__ method for testing pickling.
3004
3005
EXAMPLES::
3006
3007
sage: from sage.misc.explain_pickle import *
3008
sage: TestBuild().__getstate__()
3009
({'x': 3}, {'y': 4})
3010
sage: loads(dumps(TestBuild()))
3011
TestBuild: x=3; y=4
3012
"""
3013
return ({'x': 3}, {'y': 4})
3014
3015
def __repr__(self):
3016
r"""
3017
Print a TestBuild.
3018
3019
EXAMPLES::
3020
3021
sage: from sage.misc.explain_pickle import *
3022
sage: v = TestBuild()
3023
sage: v
3024
TestBuild: x=None; y=None
3025
sage: repr(v)
3026
'TestBuild: x=None; y=None'
3027
sage: v.__repr__()
3028
'TestBuild: x=None; y=None'
3029
"""
3030
return "TestBuild: x=%s; y=%s" % (getattr(self, 'x', None), getattr(self, 'y', None))
3031
3032
class TestBuildSetstate(TestBuild):
3033
r"""
3034
A simple class with a __getstate__ and a __setstate__. Used for testing
3035
explain_pickle.
3036
"""
3037
def __setstate__(self, state):
3038
r"""
3039
Set the state of a TestBuildSetstate. Both prints a message, and
3040
swaps x and y, to verify that it is being called.
3041
3042
EXAMPLES::
3043
3044
sage: from sage.misc.explain_pickle import *
3045
sage: loads(dumps(TestBuildSetstate())) # indirect doctest
3046
setting state from ({'x': 3}, {'y': 4})
3047
TestBuild: x=4; y=3
3048
"""
3049
print "setting state from %r" % (state,)
3050
# Swap x and y, just for fun
3051
self.x = state[1]['y']
3052
self.y = state[0]['x']
3053
3054
class TestGlobalOldName(object):
3055
r"""
3056
A featureless new-style class. When you try to unpickle an instance
3057
of this class, it is redirected to create a TestGlobalNewName instead.
3058
Used for testing explain_pickle.
3059
3060
EXAMPLES::
3061
3062
sage: from sage.misc.explain_pickle import *
3063
sage: loads(dumps(TestGlobalOldName()))
3064
TestGlobalNewName
3065
"""
3066
pass
3067
3068
class TestGlobalNewName(object):
3069
r"""
3070
A featureless new-style class. When you try to unpickle an instance
3071
of TestGlobalOldName, it is redirected to create an instance of this
3072
class instead. Used for testing explain_pickle.
3073
3074
EXAMPLES:
3075
sage: from sage.misc.explain_pickle import *
3076
sage: loads(dumps(TestGlobalOldName()))
3077
TestGlobalNewName
3078
"""
3079
def __repr__(self):
3080
r"""
3081
Print a TestGlobalNewName.
3082
3083
EXAMPLES::
3084
3085
sage: from sage.misc.explain_pickle import *
3086
sage: v = TestGlobalNewName()
3087
sage: v
3088
TestGlobalNewName
3089
sage: repr(v)
3090
'TestGlobalNewName'
3091
sage: v.__repr__()
3092
'TestGlobalNewName'
3093
"""
3094
return "TestGlobalNewName"
3095
3096
register_unpickle_override('sage.misc.explain_pickle', 'TestGlobalOldName', TestGlobalNewName, call_name=('sage.misc.explain_pickle', 'TestGlobalNewName'))
3097
3098
class TestGlobalFunnyName(object):
3099
r"""
3100
A featureless new-style class which has a name that's not a legal
3101
Python identifier.
3102
3103
EXAMPLES::
3104
3105
sage: from sage.misc.explain_pickle import *
3106
sage: globals()['funny$name'] = TestGlobalFunnyName # see comment at end of file
3107
sage: TestGlobalFunnyName.__name__
3108
'funny$name'
3109
sage: globals()['funny$name'] is TestGlobalFunnyName
3110
True
3111
"""
3112
def __repr__(self):
3113
r"""
3114
Print a TestGlobalFunnyName.
3115
3116
EXAMPLE::
3117
3118
sage: from sage.misc.explain_pickle import *
3119
sage: v = TestGlobalFunnyName()
3120
sage: v
3121
TestGlobalFunnyName
3122
sage: repr(v)
3123
'TestGlobalFunnyName'
3124
sage: v.__repr__()
3125
'TestGlobalFunnyName'
3126
"""
3127
return "TestGlobalFunnyName"
3128
3129
TestGlobalFunnyName.__name__ = "funny$name"
3130
#This crashed Sphinx. Instead, we manually execute this just before the test.
3131
#globals()['funny$name'] = TestGlobalFunnyName
3132
3133