python-pickle 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ChangeLog.md +12 -0
- data/README.md +2 -1
- data/lib/python/pickle/deserializer.rb +142 -80
- data/lib/python/pickle/instructions/bin_persid.rb +31 -0
- data/lib/python/pickle/instructions/global.rb +11 -41
- data/lib/python/pickle/instructions/has_namespace_and_name.rb +61 -0
- data/lib/python/pickle/instructions/inst.rb +34 -0
- data/lib/python/pickle/instructions/next_buffer.rb +5 -1
- data/lib/python/pickle/instructions/obj.rb +30 -0
- data/lib/python/pickle/instructions/persid.rb +31 -0
- data/lib/python/pickle/instructions/readonly_buffer.rb +4 -0
- data/lib/python/pickle/instructions.rb +64 -0
- data/lib/python/pickle/protocol0.rb +313 -68
- data/lib/python/pickle/protocol1.rb +225 -93
- data/lib/python/pickle/protocol2.rb +205 -124
- data/lib/python/pickle/protocol3.rb +92 -123
- data/lib/python/pickle/protocol4.rb +188 -165
- data/lib/python/pickle/protocol5.rb +98 -166
- data/lib/python/pickle/version.rb +1 -1
- data/lib/python/pickle.rb +38 -32
- data/spec/deserializer_spec.rb +308 -0
- data/spec/fixtures/set_v0.pkl +11 -0
- data/spec/fixtures/set_v1.pkl +0 -0
- data/spec/fixtures/set_v2.pkl +0 -0
- data/spec/fixtures/set_v3.pkl +0 -0
- data/spec/fixtures/set_v4.pkl +0 -0
- data/spec/fixtures/set_v5.pkl +0 -0
- data/spec/generate_pickles2.py +1 -0
- data/spec/generate_pickles3.py +1 -0
- data/spec/integration/load/protocol0_spec.rb +10 -0
- data/spec/integration/load/protocol1_spec.rb +10 -0
- data/spec/integration/load/protocol2_spec.rb +10 -0
- data/spec/integration/load/protocol3_spec.rb +10 -0
- data/spec/integration/load/protocol4_spec.rb +10 -0
- data/spec/integration/load/protocol5_spec.rb +10 -0
- data/spec/protocol0_read_instruction_examples.rb +44 -0
- metadata +14 -2
data/spec/deserializer_spec.rb
CHANGED
@@ -31,6 +31,10 @@ describe Python::Pickle::Deserializer do
|
|
31
31
|
expect(subject.constants['__builtin__']['object']).to be(described_class::OBJECT_CLASS)
|
32
32
|
end
|
33
33
|
|
34
|
+
it "must contain '__builtin__.set' for Python 2.x support" do
|
35
|
+
expect(subject.constants['__builtin__']['set']).to be(Set)
|
36
|
+
end
|
37
|
+
|
34
38
|
it "must contain '__builtin__.bytearray' for Python 2.x support" do
|
35
39
|
expect(subject.constants['__builtin__']['bytearray']).to be(Python::Pickle::ByteArray)
|
36
40
|
end
|
@@ -39,6 +43,10 @@ describe Python::Pickle::Deserializer do
|
|
39
43
|
expect(subject.constants['builtins']['object']).to be(described_class::OBJECT_CLASS)
|
40
44
|
end
|
41
45
|
|
46
|
+
it "must contain 'builtins.set' for Python 2.x support" do
|
47
|
+
expect(subject.constants['builtins']['set']).to be(Set)
|
48
|
+
end
|
49
|
+
|
42
50
|
it "must contain 'builtins.bytearray' for Python 2.x support" do
|
43
51
|
expect(subject.constants['builtins']['bytearray']).to be(Python::Pickle::ByteArray)
|
44
52
|
end
|
@@ -84,11 +92,13 @@ describe Python::Pickle::Deserializer do
|
|
84
92
|
|
85
93
|
'__builtin__' => {
|
86
94
|
'object' => described_class::OBJECT_CLASS,
|
95
|
+
'set' => Set,
|
87
96
|
'bytearray' => Python::Pickle::ByteArray
|
88
97
|
},
|
89
98
|
|
90
99
|
'builtins' => {
|
91
100
|
'object' => described_class::OBJECT_CLASS,
|
101
|
+
'set' => Set,
|
92
102
|
'bytearray' => Python::Pickle::ByteArray
|
93
103
|
},
|
94
104
|
|
@@ -99,6 +109,24 @@ describe Python::Pickle::Deserializer do
|
|
99
109
|
)
|
100
110
|
end
|
101
111
|
end
|
112
|
+
|
113
|
+
context "when initialized with the `buffers:` keyword argument" do
|
114
|
+
let(:buffer1) { "hello world" }
|
115
|
+
let(:buffer2) { "foo bar" }
|
116
|
+
let(:buffers) do
|
117
|
+
[
|
118
|
+
buffer1,
|
119
|
+
buffer2
|
120
|
+
]
|
121
|
+
end
|
122
|
+
|
123
|
+
subject { described_class.new(buffers: buffers) }
|
124
|
+
|
125
|
+
it "must set #buffers to an Enumerator of the buffers" do
|
126
|
+
expect(subject.buffers).to be_kind_of(Enumerator)
|
127
|
+
expect(subject.buffers.to_a).to eq(buffers)
|
128
|
+
end
|
129
|
+
end
|
102
130
|
end
|
103
131
|
|
104
132
|
describe "#push_meta_stack" do
|
@@ -415,6 +443,37 @@ describe Python::Pickle::Deserializer do
|
|
415
443
|
end
|
416
444
|
end
|
417
445
|
|
446
|
+
context "when given a Python::Pickle::Instructions::EMPTY_SET" do
|
447
|
+
let(:instruction) { Python::Pickle::Instructions::EMPTY_SET }
|
448
|
+
|
449
|
+
before do
|
450
|
+
subject.execute(instruction)
|
451
|
+
end
|
452
|
+
|
453
|
+
it "must push an empty Set object onto the #stack" do
|
454
|
+
expect(subject.stack).to eq([ Set.new ])
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
context "when given a Python::Pickle::Instructions::FROZENSET" do
|
459
|
+
let(:instruction) { Python::Pickle::Instructions::FROZENSET }
|
460
|
+
|
461
|
+
before do
|
462
|
+
subject.meta_stack << []
|
463
|
+
subject.stack << 1 << 2 << 3
|
464
|
+
subject.execute(instruction)
|
465
|
+
end
|
466
|
+
|
467
|
+
it "must pop the #meta_stack and create a frozen Set from the previous #stack and push the frozen Set onto the new #stack" do
|
468
|
+
expect(subject.stack.length).to eq(1)
|
469
|
+
|
470
|
+
set = subject.stack[-1]
|
471
|
+
|
472
|
+
expect(set).to be_frozen
|
473
|
+
expect(set).to eq(Set[1,2,3])
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
418
477
|
context "when given a Python::Pickle::Instructions::APPEND" do
|
419
478
|
context "and when the previous element on the stack is an Array" do
|
420
479
|
let(:instruction) { Python::Pickle::Instructions::APPEND }
|
@@ -429,6 +488,19 @@ describe Python::Pickle::Deserializer do
|
|
429
488
|
end
|
430
489
|
end
|
431
490
|
|
491
|
+
context "and when the previous element on the stack is a Set" do
|
492
|
+
let(:instruction) { Python::Pickle::Instructions::APPEND }
|
493
|
+
|
494
|
+
before do
|
495
|
+
subject.stack << Set.new << 2
|
496
|
+
subject.execute(instruction)
|
497
|
+
end
|
498
|
+
|
499
|
+
it "must pop the last element from the #stack and push it onto the next list element" do
|
500
|
+
expect(subject.stack).to eq([ Set[2] ])
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
432
504
|
context "but when the previous element on the stack is not an Array" do
|
433
505
|
let(:instruction) { Python::Pickle::Instructions::APPEND }
|
434
506
|
let(:item) { 2 }
|
@@ -461,6 +533,20 @@ describe Python::Pickle::Deserializer do
|
|
461
533
|
end
|
462
534
|
end
|
463
535
|
|
536
|
+
context "and when the previous element on the stack is a Set" do
|
537
|
+
let(:instruction) { Python::Pickle::Instructions::APPENDS }
|
538
|
+
|
539
|
+
before do
|
540
|
+
subject.meta_stack << [ Set[1,2,3] ]
|
541
|
+
subject.stack << 4 << 5 << 6
|
542
|
+
subject.execute(instruction)
|
543
|
+
end
|
544
|
+
|
545
|
+
it "must pop the #meta_stack, store the #stack, and concat the previous #stack onto the last element of the new #stack" do
|
546
|
+
expect(subject.stack).to eq([ Set[1,2,3,4,5,6] ])
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
464
550
|
context "but when the previous element on the stack is not an Array" do
|
465
551
|
let(:instruction) { Python::Pickle::Instructions::APPENDS }
|
466
552
|
let(:items) { [3,4,5] }
|
@@ -479,6 +565,39 @@ describe Python::Pickle::Deserializer do
|
|
479
565
|
end
|
480
566
|
end
|
481
567
|
|
568
|
+
context "when given a Python::Pickle::Instructions::ADDITEMS" do
|
569
|
+
context "and when the previous element on the stack is a Set" do
|
570
|
+
let(:instruction) { Python::Pickle::Instructions::ADDITEMS }
|
571
|
+
|
572
|
+
before do
|
573
|
+
subject.meta_stack << [ Set[1,2,3] ]
|
574
|
+
subject.stack << 4 << 5 << 6
|
575
|
+
subject.execute(instruction)
|
576
|
+
end
|
577
|
+
|
578
|
+
it "must pop the #meta_stack, store the #stack, and concat the previous #stack onto the last element of the new #stack" do
|
579
|
+
expect(subject.stack).to eq([ Set[1,2,3,4,5,6] ])
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
context "but when the previous element on the stack is not a Set" do
|
584
|
+
let(:instruction) { Python::Pickle::Instructions::ADDITEMS }
|
585
|
+
let(:items) { [3,4,5] }
|
586
|
+
let(:set) { [] }
|
587
|
+
|
588
|
+
before do
|
589
|
+
subject.meta_stack << [ set ]
|
590
|
+
subject.stack << items[0] << items[1] << items[2]
|
591
|
+
end
|
592
|
+
|
593
|
+
it do
|
594
|
+
expect {
|
595
|
+
subject.execute(instruction)
|
596
|
+
}.to raise_error(Python::Pickle::DeserializationError,"cannot add items #{items.inspect} to a non-Set object: #{set.inspect}")
|
597
|
+
end
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
482
601
|
context "when given a Python::Pickle::Instructions::LIST" do
|
483
602
|
let(:instruction) { Python::Pickle::Instructions::LIST }
|
484
603
|
|
@@ -629,6 +748,142 @@ describe Python::Pickle::Deserializer do
|
|
629
748
|
end
|
630
749
|
end
|
631
750
|
|
751
|
+
context "when given a Python::Pickle::Instructions::Inst object" do
|
752
|
+
let(:namespace) { '__main__' }
|
753
|
+
let(:name) { 'MyClass' }
|
754
|
+
let(:instruction) { Python::Pickle::Instructions::Inst.new(namespace,name) }
|
755
|
+
|
756
|
+
before do
|
757
|
+
subject.meta_stack << []
|
758
|
+
subject.stack << 1 << 2
|
759
|
+
subject.execute(instruction)
|
760
|
+
end
|
761
|
+
|
762
|
+
context "when the constant can be resolved" do
|
763
|
+
module TestInstInstruction
|
764
|
+
class MyClass
|
765
|
+
attr_reader :x, :y
|
766
|
+
|
767
|
+
def initialize(x,y)
|
768
|
+
@x = x
|
769
|
+
@y = y
|
770
|
+
end
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
subject do
|
775
|
+
described_class.new(
|
776
|
+
constants: {
|
777
|
+
'__main__' => {
|
778
|
+
'MyClass' => TestInstInstruction::MyClass
|
779
|
+
}
|
780
|
+
}
|
781
|
+
)
|
782
|
+
end
|
783
|
+
|
784
|
+
it "must resolve the class from the INST instruction's #namespace and #name, pop the meta stack, use the previous sstack as the initialization arguments, initialize a new instance of the class, and push it onto the new #stack" do
|
785
|
+
expect(subject.stack.length).to eq(1)
|
786
|
+
|
787
|
+
object = subject.stack[-1]
|
788
|
+
|
789
|
+
expect(object).to be_kind_of(TestInstInstruction::MyClass)
|
790
|
+
expect(object.x).to eq(1)
|
791
|
+
expect(object.y).to eq(2)
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
context "but the constant cannot be resolved" do
|
796
|
+
it "must push a new Python::Pickle::PyClass object onto the #stack" do
|
797
|
+
py_object = subject.stack[-1]
|
798
|
+
|
799
|
+
expect(py_object).to be_kind_of(Python::Pickle::PyObject)
|
800
|
+
expect(py_object.py_class).to be_kind_of(Python::Pickle::PyClass)
|
801
|
+
expect(py_object.py_class.namespace).to eq(namespace)
|
802
|
+
expect(py_object.py_class.name).to eq(name)
|
803
|
+
expect(py_object.init_args).to eq([1,2])
|
804
|
+
end
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
context "when given a Python::Pickle::Instructions::OBJ" do
|
809
|
+
let(:instruction) { Python::Pickle::Instructions::OBJ }
|
810
|
+
|
811
|
+
context "and when the constant on the #stack is a Ruby class" do
|
812
|
+
module TestObjInstruction
|
813
|
+
class MyClass
|
814
|
+
end
|
815
|
+
end
|
816
|
+
|
817
|
+
context "but there are no additional arguments on the #stack after the class" do
|
818
|
+
before do
|
819
|
+
subject.stack << TestObjInstruction::MyClass
|
820
|
+
subject.execute(instruction)
|
821
|
+
end
|
822
|
+
|
823
|
+
it "must pop off first element, and initialize a new instance of the class, and push the new instance onto the #stack" do
|
824
|
+
expect(subject.stack.length).to eq(1)
|
825
|
+
expect(subject.stack[-1]).to be_kind_of(TestObjInstruction::MyClass)
|
826
|
+
end
|
827
|
+
end
|
828
|
+
|
829
|
+
context "but there are additional arguments on the #stack after the class" do
|
830
|
+
module TestObjInstruction
|
831
|
+
class MyClassWithArgs
|
832
|
+
attr_reader :x, :y
|
833
|
+
|
834
|
+
def initialize(x,y)
|
835
|
+
@x = x
|
836
|
+
@y = y
|
837
|
+
end
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
before do
|
842
|
+
subject.stack << TestObjInstruction::MyClassWithArgs << 1 << 2
|
843
|
+
subject.execute(instruction)
|
844
|
+
end
|
845
|
+
|
846
|
+
it "must call #initialize with the splatted tuple's arguments" do
|
847
|
+
object = subject.stack[-1]
|
848
|
+
|
849
|
+
expect(object.x).to eq(1)
|
850
|
+
expect(object.y).to eq(2)
|
851
|
+
end
|
852
|
+
end
|
853
|
+
end
|
854
|
+
|
855
|
+
context "and when the constant on the #stack is a PyClass" do
|
856
|
+
let(:namespace) { '__main__' }
|
857
|
+
let(:name) { 'MyClass' }
|
858
|
+
let(:py_class) { Python::Pickle::PyClass.new(namespace,name) }
|
859
|
+
|
860
|
+
context "but there are no additional arguments on the #stack after the class" do
|
861
|
+
before do
|
862
|
+
subject.stack << py_class
|
863
|
+
subject.execute(instruction)
|
864
|
+
end
|
865
|
+
|
866
|
+
it "must pop off the two last elements and push the new Python::Pickle::PyObject onto the #stack" do
|
867
|
+
expect(subject.stack.length).to eq(1)
|
868
|
+
expect(subject.stack[-1]).to be_kind_of(Python::Pickle::PyObject)
|
869
|
+
end
|
870
|
+
end
|
871
|
+
|
872
|
+
context "but there are additional arguments on the #stack after the class" do
|
873
|
+
before do
|
874
|
+
subject.stack << py_class << 1 << 2
|
875
|
+
subject.execute(instruction)
|
876
|
+
end
|
877
|
+
|
878
|
+
it "must set the object's #init_args to the tuple's elements" do
|
879
|
+
object = subject.stack[-1]
|
880
|
+
|
881
|
+
expect(object.init_args).to eq([1,2])
|
882
|
+
end
|
883
|
+
end
|
884
|
+
end
|
885
|
+
end
|
886
|
+
|
632
887
|
context "when given a Python::Pickle::Instructions::NEWOBJ" do
|
633
888
|
let(:instruction) { Python::Pickle::Instructions::NEWOBJ }
|
634
889
|
|
@@ -1201,6 +1456,59 @@ describe Python::Pickle::Deserializer do
|
|
1201
1456
|
end
|
1202
1457
|
end
|
1203
1458
|
end
|
1459
|
+
|
1460
|
+
context "when given a Python::Pickle::Instructions::NEXT_BUFFER" do
|
1461
|
+
let(:instruction) { Python::Pickle::Instructions::NEXT_BUFFER }
|
1462
|
+
|
1463
|
+
context "and the #{described_class} was initialized with the buffers: keyword argument" do
|
1464
|
+
let(:buffer1) { String.new("hello world") }
|
1465
|
+
let(:buffer2) { String.new("foo bar") }
|
1466
|
+
let(:buffers) do
|
1467
|
+
[
|
1468
|
+
buffer1,
|
1469
|
+
buffer2
|
1470
|
+
]
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
subject { described_class.new(buffers: buffers) }
|
1474
|
+
|
1475
|
+
before do
|
1476
|
+
subject.execute(instruction)
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
it "must take the next element from #buffers and push it onto the #stack" do
|
1480
|
+
expect(subject.stack).to eq([buffer1])
|
1481
|
+
end
|
1482
|
+
|
1483
|
+
it "must not modify the underlying buffers Array" do
|
1484
|
+
expect(buffers).to eq([buffer1, buffer2])
|
1485
|
+
end
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
context "but the #{described_class} was not initialized with the buffers: keyword argument" do
|
1489
|
+
it do
|
1490
|
+
expect {
|
1491
|
+
subject.execute(instruction)
|
1492
|
+
}.to raise_error(Python::Pickle::DeserializationError,"pickle stream includes a NEXT_BUFFER instruction, but no buffers were provided")
|
1493
|
+
end
|
1494
|
+
end
|
1495
|
+
end
|
1496
|
+
|
1497
|
+
context "when given a Python::Pickle::Instructions::READONLY_BUFFER" do
|
1498
|
+
let(:instruction) { Python::Pickle::Instructions::READONLY_BUFFER }
|
1499
|
+
|
1500
|
+
let(:buffer1) { String.new("hello world") }
|
1501
|
+
let(:buffer2) { String.new("foo bar") }
|
1502
|
+
|
1503
|
+
before do
|
1504
|
+
subject.stack << buffer1 << buffer2
|
1505
|
+
subject.execute(instruction)
|
1506
|
+
end
|
1507
|
+
|
1508
|
+
it "must freeze the buffer at the top of the #stack" do
|
1509
|
+
expect(subject.stack[-1]).to be_frozen
|
1510
|
+
end
|
1511
|
+
end
|
1204
1512
|
end
|
1205
1513
|
|
1206
1514
|
describe "#copyreg_reconstructor" do
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/generate_pickles2.py
CHANGED
@@ -26,6 +26,7 @@ objects = {
|
|
26
26
|
"bin_str": b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
|
27
27
|
"list": [None, True, False, 42, 'ABC'],
|
28
28
|
"nested_list": [1, [2, [3, [4]]]],
|
29
|
+
"set": set([1,2,3,4]),
|
29
30
|
"dict": {"foo": "bar"},
|
30
31
|
"nested_dict": {"a": {"b": {"c": "d"}}},
|
31
32
|
"function": func,
|
data/spec/generate_pickles3.py
CHANGED
@@ -25,6 +25,7 @@ objects = {
|
|
25
25
|
"bin_str": b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
|
26
26
|
"list": [None, True, False, 42, 'ABC'],
|
27
27
|
"nested_list": [1, [2, [3, [4]]]],
|
28
|
+
"set": set([1,2,3,4]),
|
28
29
|
"dict": {"foo": "bar"},
|
29
30
|
"nested_dict": {"a": {"b": {"c": "d"}}},
|
30
31
|
"function": func,
|
@@ -104,6 +104,16 @@ describe Python::Pickle do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
context "and it contains a set type" do
|
108
|
+
let(:file) { File.join(fixtures_dir,'set_v0.pkl') }
|
109
|
+
|
110
|
+
it "must return a Set object" do
|
111
|
+
expect(subject.load(io)).to eq(
|
112
|
+
Set[1, 2, 3, 4]
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
107
117
|
context "and it contains a dict type" do
|
108
118
|
let(:file) { File.join(fixtures_dir,'dict_v0.pkl') }
|
109
119
|
|
@@ -104,6 +104,16 @@ describe Python::Pickle do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
context "and it contains a set type" do
|
108
|
+
let(:file) { File.join(fixtures_dir,'set_v1.pkl') }
|
109
|
+
|
110
|
+
it "must return a Set object" do
|
111
|
+
expect(subject.load(io)).to eq(
|
112
|
+
Set[1, 2, 3, 4]
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
107
117
|
context "and it contains a dict type" do
|
108
118
|
let(:file) { File.join(fixtures_dir,'dict_v1.pkl') }
|
109
119
|
|
@@ -104,6 +104,16 @@ describe Python::Pickle do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
context "and it contains a set type" do
|
108
|
+
let(:file) { File.join(fixtures_dir,'set_v2.pkl') }
|
109
|
+
|
110
|
+
it "must return a Set object" do
|
111
|
+
expect(subject.load(io)).to eq(
|
112
|
+
Set[1, 2, 3, 4]
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
107
117
|
context "and it contains a dict type" do
|
108
118
|
let(:file) { File.join(fixtures_dir,'dict_v2.pkl') }
|
109
119
|
|
@@ -104,6 +104,16 @@ describe Python::Pickle do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
context "and it contains a set type" do
|
108
|
+
let(:file) { File.join(fixtures_dir,'set_v3.pkl') }
|
109
|
+
|
110
|
+
it "must return a Set object" do
|
111
|
+
expect(subject.load(io)).to eq(
|
112
|
+
Set[1, 2, 3, 4]
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
107
117
|
context "and it contains a dict type" do
|
108
118
|
let(:file) { File.join(fixtures_dir,'dict_v3.pkl') }
|
109
119
|
|
@@ -104,6 +104,16 @@ describe Python::Pickle do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
context "and it contains a set type" do
|
108
|
+
let(:file) { File.join(fixtures_dir,'set_v4.pkl') }
|
109
|
+
|
110
|
+
it "must return a Set object" do
|
111
|
+
expect(subject.load(io)).to eq(
|
112
|
+
Set[1, 2, 3, 4]
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
107
117
|
context "and it contains a dict type" do
|
108
118
|
let(:file) { File.join(fixtures_dir,'dict_v4.pkl') }
|
109
119
|
|
@@ -104,6 +104,16 @@ describe Python::Pickle do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
context "and it contains a set type" do
|
108
|
+
let(:file) { File.join(fixtures_dir,'set_v5.pkl') }
|
109
|
+
|
110
|
+
it "must return a Set object" do
|
111
|
+
expect(subject.load(io)).to eq(
|
112
|
+
Set[1, 2, 3, 4]
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
107
117
|
context "and it contains a dict type" do
|
108
118
|
let(:file) { File.join(fixtures_dir,'dict_v5.pkl') }
|
109
119
|
|
@@ -93,6 +93,27 @@ shared_examples_for "Protocol0#read_instruction examples" do
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
context "when the opcode is 80" do
|
97
|
+
let(:id) { "12345" }
|
98
|
+
let(:io) { StringIO.new("#{80.chr}#{id}\n") }
|
99
|
+
|
100
|
+
it "must return a Python::Pickle::Instructions::PersID object" do
|
101
|
+
expect(subject.read_instruction).to eq(
|
102
|
+
Python::Pickle::Instructions::PersID.new(id)
|
103
|
+
)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "when the opcode is 81" do
|
108
|
+
let(:io) { StringIO.new(81.chr) }
|
109
|
+
|
110
|
+
it "must return Python::Pickle::Instructions::BINPERSID" do
|
111
|
+
expect(subject.read_instruction).to be(
|
112
|
+
Python::Pickle::Instructions::BINPERSID
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
96
117
|
context "when the opcode is 82" do
|
97
118
|
let(:io) { StringIO.new(82.chr) }
|
98
119
|
|
@@ -168,6 +189,19 @@ shared_examples_for "Protocol0#read_instruction examples" do
|
|
168
189
|
end
|
169
190
|
end
|
170
191
|
|
192
|
+
context "when the opcode is 105" do
|
193
|
+
let(:namespace) { "foo" }
|
194
|
+
let(:name) { "bar" }
|
195
|
+
|
196
|
+
let(:io) { StringIO.new("#{105.chr}#{namespace}\n#{name}\n") }
|
197
|
+
|
198
|
+
it "must return Python::Pickle::Instructions::Inst" do
|
199
|
+
expect(subject.read_instruction).to eq(
|
200
|
+
Python::Pickle::Instructions::Inst.new(namespace,name)
|
201
|
+
)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
171
205
|
context "when the opcode is 108" do
|
172
206
|
let(:io) { StringIO.new(108.chr) }
|
173
207
|
|
@@ -178,6 +212,16 @@ shared_examples_for "Protocol0#read_instruction examples" do
|
|
178
212
|
end
|
179
213
|
end
|
180
214
|
|
215
|
+
context "when the opcode is 111" do
|
216
|
+
let(:io) { StringIO.new(111.chr) }
|
217
|
+
|
218
|
+
it "must return Python::Pickle::Instructions::OBJ" do
|
219
|
+
expect(subject.read_instruction).to be(
|
220
|
+
Python::Pickle::Instructions::OBJ
|
221
|
+
)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
181
225
|
context "when the opcode is 112" do
|
182
226
|
let(:index) { 1 }
|
183
227
|
let(:io) { StringIO.new("#{112.chr}#{index}\n") }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: python-pickle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -53,6 +53,7 @@ files:
|
|
53
53
|
- lib/python/pickle/deserializer.rb
|
54
54
|
- lib/python/pickle/exceptions.rb
|
55
55
|
- lib/python/pickle/instruction.rb
|
56
|
+
- lib/python/pickle/instructions.rb
|
56
57
|
- lib/python/pickle/instructions/add_items.rb
|
57
58
|
- lib/python/pickle/instructions/append.rb
|
58
59
|
- lib/python/pickle/instructions/appends.rb
|
@@ -61,6 +62,7 @@ files:
|
|
61
62
|
- lib/python/pickle/instructions/bin_float.rb
|
62
63
|
- lib/python/pickle/instructions/bin_get.rb
|
63
64
|
- lib/python/pickle/instructions/bin_int1.rb
|
65
|
+
- lib/python/pickle/instructions/bin_persid.rb
|
64
66
|
- lib/python/pickle/instructions/bin_put.rb
|
65
67
|
- lib/python/pickle/instructions/bin_string.rb
|
66
68
|
- lib/python/pickle/instructions/bin_unicode.rb
|
@@ -82,7 +84,9 @@ files:
|
|
82
84
|
- lib/python/pickle/instructions/get.rb
|
83
85
|
- lib/python/pickle/instructions/global.rb
|
84
86
|
- lib/python/pickle/instructions/has_length_and_value.rb
|
87
|
+
- lib/python/pickle/instructions/has_namespace_and_name.rb
|
85
88
|
- lib/python/pickle/instructions/has_value.rb
|
89
|
+
- lib/python/pickle/instructions/inst.rb
|
86
90
|
- lib/python/pickle/instructions/int.rb
|
87
91
|
- lib/python/pickle/instructions/list.rb
|
88
92
|
- lib/python/pickle/instructions/long.rb
|
@@ -97,6 +101,8 @@ files:
|
|
97
101
|
- lib/python/pickle/instructions/new_true.rb
|
98
102
|
- lib/python/pickle/instructions/next_buffer.rb
|
99
103
|
- lib/python/pickle/instructions/none.rb
|
104
|
+
- lib/python/pickle/instructions/obj.rb
|
105
|
+
- lib/python/pickle/instructions/persid.rb
|
100
106
|
- lib/python/pickle/instructions/pop.rb
|
101
107
|
- lib/python/pickle/instructions/pop_mark.rb
|
102
108
|
- lib/python/pickle/instructions/proto.rb
|
@@ -222,6 +228,12 @@ files:
|
|
222
228
|
- spec/fixtures/object_v3.pkl
|
223
229
|
- spec/fixtures/object_v4.pkl
|
224
230
|
- spec/fixtures/object_v5.pkl
|
231
|
+
- spec/fixtures/set_v0.pkl
|
232
|
+
- spec/fixtures/set_v1.pkl
|
233
|
+
- spec/fixtures/set_v2.pkl
|
234
|
+
- spec/fixtures/set_v3.pkl
|
235
|
+
- spec/fixtures/set_v4.pkl
|
236
|
+
- spec/fixtures/set_v5.pkl
|
225
237
|
- spec/fixtures/str_v0.pkl
|
226
238
|
- spec/fixtures/str_v1.pkl
|
227
239
|
- spec/fixtures/str_v2.pkl
|