python-pickle 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.github/workflows/ruby.yml +27 -0
  4. data/.gitignore +5 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/ChangeLog.md +14 -0
  8. data/Gemfile +15 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +149 -0
  11. data/Rakefile +13 -0
  12. data/gemspec.yml +25 -0
  13. data/lib/python/pickle/byte_array.rb +40 -0
  14. data/lib/python/pickle/deserializer.rb +595 -0
  15. data/lib/python/pickle/exceptions.rb +12 -0
  16. data/lib/python/pickle/instruction.rb +52 -0
  17. data/lib/python/pickle/instructions/add_items.rb +26 -0
  18. data/lib/python/pickle/instructions/append.rb +24 -0
  19. data/lib/python/pickle/instructions/appends.rb +26 -0
  20. data/lib/python/pickle/instructions/bin_bytes.rb +32 -0
  21. data/lib/python/pickle/instructions/bin_bytes8.rb +32 -0
  22. data/lib/python/pickle/instructions/bin_float.rb +29 -0
  23. data/lib/python/pickle/instructions/bin_get.rb +27 -0
  24. data/lib/python/pickle/instructions/bin_int1.rb +29 -0
  25. data/lib/python/pickle/instructions/bin_put.rb +29 -0
  26. data/lib/python/pickle/instructions/bin_string.rb +32 -0
  27. data/lib/python/pickle/instructions/bin_unicode.rb +32 -0
  28. data/lib/python/pickle/instructions/bin_unicode8.rb +32 -0
  29. data/lib/python/pickle/instructions/build.rb +24 -0
  30. data/lib/python/pickle/instructions/byte_array8.rb +32 -0
  31. data/lib/python/pickle/instructions/dict.rb +17 -0
  32. data/lib/python/pickle/instructions/dup.rb +24 -0
  33. data/lib/python/pickle/instructions/empty_dict.rb +26 -0
  34. data/lib/python/pickle/instructions/empty_list.rb +26 -0
  35. data/lib/python/pickle/instructions/empty_set.rb +26 -0
  36. data/lib/python/pickle/instructions/empty_tuple.rb +26 -0
  37. data/lib/python/pickle/instructions/ext1.rb +29 -0
  38. data/lib/python/pickle/instructions/ext2.rb +29 -0
  39. data/lib/python/pickle/instructions/ext4.rb +29 -0
  40. data/lib/python/pickle/instructions/float.rb +24 -0
  41. data/lib/python/pickle/instructions/frame.rb +29 -0
  42. data/lib/python/pickle/instructions/frozen_set.rb +26 -0
  43. data/lib/python/pickle/instructions/get.rb +27 -0
  44. data/lib/python/pickle/instructions/global.rb +62 -0
  45. data/lib/python/pickle/instructions/has_length_and_value.rb +58 -0
  46. data/lib/python/pickle/instructions/has_value.rb +50 -0
  47. data/lib/python/pickle/instructions/int.rb +24 -0
  48. data/lib/python/pickle/instructions/list.rb +24 -0
  49. data/lib/python/pickle/instructions/long.rb +24 -0
  50. data/lib/python/pickle/instructions/long1.rb +32 -0
  51. data/lib/python/pickle/instructions/long4.rb +32 -0
  52. data/lib/python/pickle/instructions/long_bin_get.rb +27 -0
  53. data/lib/python/pickle/instructions/mark.rb +24 -0
  54. data/lib/python/pickle/instructions/memoize.rb +26 -0
  55. data/lib/python/pickle/instructions/new_false.rb +24 -0
  56. data/lib/python/pickle/instructions/new_obj.rb +26 -0
  57. data/lib/python/pickle/instructions/new_obj_ex.rb +26 -0
  58. data/lib/python/pickle/instructions/new_true.rb +24 -0
  59. data/lib/python/pickle/instructions/next_buffer.rb +26 -0
  60. data/lib/python/pickle/instructions/none.rb +24 -0
  61. data/lib/python/pickle/instructions/pop.rb +24 -0
  62. data/lib/python/pickle/instructions/pop_mark.rb +24 -0
  63. data/lib/python/pickle/instructions/proto.rb +29 -0
  64. data/lib/python/pickle/instructions/put.rb +24 -0
  65. data/lib/python/pickle/instructions/readonly_buffer.rb +26 -0
  66. data/lib/python/pickle/instructions/reduce.rb +24 -0
  67. data/lib/python/pickle/instructions/set_item.rb +24 -0
  68. data/lib/python/pickle/instructions/set_items.rb +26 -0
  69. data/lib/python/pickle/instructions/short_bin_bytes.rb +32 -0
  70. data/lib/python/pickle/instructions/short_bin_string.rb +32 -0
  71. data/lib/python/pickle/instructions/short_bin_unicode.rb +32 -0
  72. data/lib/python/pickle/instructions/stack_global.rb +26 -0
  73. data/lib/python/pickle/instructions/stop.rb +24 -0
  74. data/lib/python/pickle/instructions/string.rb +24 -0
  75. data/lib/python/pickle/instructions/tuple.rb +24 -0
  76. data/lib/python/pickle/instructions/tuple1.rb +24 -0
  77. data/lib/python/pickle/instructions/tuple2.rb +24 -0
  78. data/lib/python/pickle/instructions/tuple3.rb +24 -0
  79. data/lib/python/pickle/protocol.rb +56 -0
  80. data/lib/python/pickle/protocol0.rb +399 -0
  81. data/lib/python/pickle/protocol1.rb +183 -0
  82. data/lib/python/pickle/protocol2.rb +229 -0
  83. data/lib/python/pickle/protocol3.rb +163 -0
  84. data/lib/python/pickle/protocol4.rb +285 -0
  85. data/lib/python/pickle/protocol5.rb +218 -0
  86. data/lib/python/pickle/py_class.rb +75 -0
  87. data/lib/python/pickle/py_object.rb +141 -0
  88. data/lib/python/pickle/tuple.rb +19 -0
  89. data/lib/python/pickle/version.rb +6 -0
  90. data/lib/python/pickle.rb +226 -0
  91. data/python-pickle.gemspec +62 -0
  92. data/spec/byte_array_spec.rb +54 -0
  93. data/spec/deserializer_spec.rb +1201 -0
  94. data/spec/fixtures/ascii_str_v3.pkl +0 -0
  95. data/spec/fixtures/ascii_str_v4.pkl +0 -0
  96. data/spec/fixtures/ascii_str_v5.pkl +0 -0
  97. data/spec/fixtures/bin_str_v0.pkl +3 -0
  98. data/spec/fixtures/bin_str_v1.pkl +0 -0
  99. data/spec/fixtures/bin_str_v2.pkl +0 -0
  100. data/spec/fixtures/bin_str_v3.pkl +0 -0
  101. data/spec/fixtures/bin_str_v4.pkl +0 -0
  102. data/spec/fixtures/bin_str_v5.pkl +0 -0
  103. data/spec/fixtures/bytearray_v0.pkl +10 -0
  104. data/spec/fixtures/bytearray_v1.pkl +0 -0
  105. data/spec/fixtures/bytearray_v2.pkl +0 -0
  106. data/spec/fixtures/bytearray_v3.pkl +0 -0
  107. data/spec/fixtures/bytearray_v4.pkl +0 -0
  108. data/spec/fixtures/bytearray_v5.pkl +0 -0
  109. data/spec/fixtures/class_v0.pkl +4 -0
  110. data/spec/fixtures/class_v1.pkl +0 -0
  111. data/spec/fixtures/class_v2.pkl +0 -0
  112. data/spec/fixtures/class_v3.pkl +0 -0
  113. data/spec/fixtures/class_v4.pkl +0 -0
  114. data/spec/fixtures/class_v5.pkl +0 -0
  115. data/spec/fixtures/dict_v0.pkl +6 -0
  116. data/spec/fixtures/dict_v1.pkl +0 -0
  117. data/spec/fixtures/dict_v2.pkl +0 -0
  118. data/spec/fixtures/dict_v3.pkl +0 -0
  119. data/spec/fixtures/dict_v4.pkl +0 -0
  120. data/spec/fixtures/dict_v5.pkl +0 -0
  121. data/spec/fixtures/escaped_str_v0.pkl +3 -0
  122. data/spec/fixtures/escaped_str_v1.pkl +0 -0
  123. data/spec/fixtures/escaped_str_v2.pkl +0 -0
  124. data/spec/fixtures/false_v0.pkl +2 -0
  125. data/spec/fixtures/false_v1.pkl +2 -0
  126. data/spec/fixtures/false_v2.pkl +1 -0
  127. data/spec/fixtures/false_v3.pkl +1 -0
  128. data/spec/fixtures/false_v4.pkl +1 -0
  129. data/spec/fixtures/false_v5.pkl +1 -0
  130. data/spec/fixtures/float_v0.pkl +2 -0
  131. data/spec/fixtures/float_v1.pkl +1 -0
  132. data/spec/fixtures/float_v2.pkl +1 -0
  133. data/spec/fixtures/float_v3.pkl +1 -0
  134. data/spec/fixtures/float_v4.pkl +0 -0
  135. data/spec/fixtures/float_v5.pkl +0 -0
  136. data/spec/fixtures/function_v0.pkl +4 -0
  137. data/spec/fixtures/function_v1.pkl +0 -0
  138. data/spec/fixtures/function_v2.pkl +0 -0
  139. data/spec/fixtures/function_v3.pkl +0 -0
  140. data/spec/fixtures/function_v4.pkl +0 -0
  141. data/spec/fixtures/function_v5.pkl +0 -0
  142. data/spec/fixtures/hex_str_v0.pkl +3 -0
  143. data/spec/fixtures/hex_str_v1.pkl +0 -0
  144. data/spec/fixtures/hex_str_v2.pkl +0 -0
  145. data/spec/fixtures/int_v0.pkl +2 -0
  146. data/spec/fixtures/int_v1.pkl +1 -0
  147. data/spec/fixtures/int_v2.pkl +1 -0
  148. data/spec/fixtures/int_v3.pkl +1 -0
  149. data/spec/fixtures/int_v4.pkl +1 -0
  150. data/spec/fixtures/int_v5.pkl +1 -0
  151. data/spec/fixtures/list_v0.pkl +7 -0
  152. data/spec/fixtures/list_v1.pkl +0 -0
  153. data/spec/fixtures/list_v2.pkl +0 -0
  154. data/spec/fixtures/list_v3.pkl +0 -0
  155. data/spec/fixtures/list_v4.pkl +0 -0
  156. data/spec/fixtures/list_v5.pkl +0 -0
  157. data/spec/fixtures/long_v0.pkl +2 -0
  158. data/spec/fixtures/long_v1.pkl +2 -0
  159. data/spec/fixtures/long_v2.pkl +0 -0
  160. data/spec/fixtures/long_v3.pkl +0 -0
  161. data/spec/fixtures/long_v4.pkl +0 -0
  162. data/spec/fixtures/long_v5.pkl +0 -0
  163. data/spec/fixtures/nested_dict_v0.pkl +12 -0
  164. data/spec/fixtures/nested_dict_v1.pkl +0 -0
  165. data/spec/fixtures/nested_dict_v2.pkl +0 -0
  166. data/spec/fixtures/nested_dict_v3.pkl +0 -0
  167. data/spec/fixtures/nested_dict_v4.pkl +0 -0
  168. data/spec/fixtures/nested_dict_v5.pkl +0 -0
  169. data/spec/fixtures/nested_list_v0.pkl +9 -0
  170. data/spec/fixtures/nested_list_v1.pkl +0 -0
  171. data/spec/fixtures/nested_list_v2.pkl +0 -0
  172. data/spec/fixtures/nested_list_v3.pkl +0 -0
  173. data/spec/fixtures/nested_list_v4.pkl +0 -0
  174. data/spec/fixtures/nested_list_v5.pkl +0 -0
  175. data/spec/fixtures/none_v0.pkl +1 -0
  176. data/spec/fixtures/none_v1.pkl +1 -0
  177. data/spec/fixtures/none_v2.pkl +1 -0
  178. data/spec/fixtures/none_v3.pkl +1 -0
  179. data/spec/fixtures/none_v4.pkl +1 -0
  180. data/spec/fixtures/none_v5.pkl +1 -0
  181. data/spec/fixtures/object_v0.pkl +19 -0
  182. data/spec/fixtures/object_v1.pkl +0 -0
  183. data/spec/fixtures/object_v2.pkl +0 -0
  184. data/spec/fixtures/object_v3.pkl +0 -0
  185. data/spec/fixtures/object_v4.pkl +0 -0
  186. data/spec/fixtures/object_v5.pkl +0 -0
  187. data/spec/fixtures/str_v0.pkl +3 -0
  188. data/spec/fixtures/str_v1.pkl +0 -0
  189. data/spec/fixtures/str_v2.pkl +0 -0
  190. data/spec/fixtures/str_v3.pkl +0 -0
  191. data/spec/fixtures/str_v4.pkl +0 -0
  192. data/spec/fixtures/str_v5.pkl +0 -0
  193. data/spec/fixtures/true_v0.pkl +2 -0
  194. data/spec/fixtures/true_v1.pkl +2 -0
  195. data/spec/fixtures/true_v2.pkl +1 -0
  196. data/spec/fixtures/true_v3.pkl +1 -0
  197. data/spec/fixtures/true_v4.pkl +1 -0
  198. data/spec/fixtures/true_v5.pkl +1 -0
  199. data/spec/fixtures/unicode_str_v0.pkl +3 -0
  200. data/spec/fixtures/unicode_str_v1.pkl +0 -0
  201. data/spec/fixtures/unicode_str_v2.pkl +0 -0
  202. data/spec/fixtures/unicode_str_v3.pkl +0 -0
  203. data/spec/fixtures/unicode_str_v4.pkl +0 -0
  204. data/spec/fixtures/unicode_str_v5.pkl +0 -0
  205. data/spec/generate_pickles2.py +41 -0
  206. data/spec/generate_pickles3.py +40 -0
  207. data/spec/integration/load/protocol0_spec.rb +258 -0
  208. data/spec/integration/load/protocol1_spec.rb +258 -0
  209. data/spec/integration/load/protocol2_spec.rb +258 -0
  210. data/spec/integration/load/protocol3_spec.rb +258 -0
  211. data/spec/integration/load/protocol4_spec.rb +258 -0
  212. data/spec/integration/load/protocol5_spec.rb +258 -0
  213. data/spec/integration/parse/protocol0_spec.rb +467 -0
  214. data/spec/integration/parse/protocol1_spec.rb +459 -0
  215. data/spec/integration/parse/protocol2_spec.rb +471 -0
  216. data/spec/integration/parse/protocol3_spec.rb +407 -0
  217. data/spec/integration/parse/protocol4_spec.rb +439 -0
  218. data/spec/integration/parse/protocol5_spec.rb +419 -0
  219. data/spec/pickle_spec.rb +163 -0
  220. data/spec/protocol0_read_instruction_examples.rb +211 -0
  221. data/spec/protocol0_spec.rb +445 -0
  222. data/spec/protocol1_read_instruction_examples.rb +156 -0
  223. data/spec/protocol1_spec.rb +59 -0
  224. data/spec/protocol2_read_instruction_examples.rb +135 -0
  225. data/spec/protocol2_spec.rb +128 -0
  226. data/spec/protocol3_read_instruction_examples.rb +29 -0
  227. data/spec/protocol3_spec.rb +32 -0
  228. data/spec/protocol4_read_instruction_examples.rb +142 -0
  229. data/spec/protocol4_spec.rb +58 -0
  230. data/spec/protocol5_spec.rb +68 -0
  231. data/spec/py_class_spec.rb +62 -0
  232. data/spec/py_object_spec.rb +149 -0
  233. data/spec/spec_helper.rb +3 -0
  234. data/spec/tuple_spec.rb +18 -0
  235. metadata +325 -0
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'python/pickle/protocol4'
3
+
4
+ require 'protocol0_read_instruction_examples'
5
+ require 'protocol1_read_instruction_examples'
6
+ require 'protocol2_read_instruction_examples'
7
+ require 'protocol3_read_instruction_examples'
8
+ require 'protocol4_read_instruction_examples'
9
+
10
+ describe Python::Pickle::Protocol4 do
11
+ let(:pickle) { '' }
12
+ let(:io) { StringIO.new(pickle) }
13
+
14
+ subject { described_class.new(io) }
15
+
16
+ describe "#read_uint64_le" do
17
+ let(:uint16) { 0x0123456789abdef }
18
+ let(:packed) { [uint16].pack('Q<') }
19
+ let(:io) { StringIO.new(packed) }
20
+
21
+ it "must read two bytes and return an unpacked unsigned 64bit integer" do
22
+ expect(subject.read_uint64_le).to eq(uint16)
23
+ end
24
+ end
25
+
26
+ describe "#read_utf8_string" do
27
+ let(:string) { "hello world\u1234" }
28
+ let(:io) { StringIO.new("#{string}XXX".b) }
29
+ let(:length) { string.bytesize }
30
+
31
+ it "must read a UTF-8 String with the desired number of bytes" do
32
+ expect(subject.read_utf8_string(length)).to eq(string)
33
+ end
34
+
35
+ it "must return a UTF-8 encoded String" do
36
+ expect(subject.read_utf8_string(length).encoding).to eq(Encoding::UTF_8)
37
+ end
38
+ end
39
+
40
+ describe "#read_instruction" do
41
+ include_context "Protocol0#read_instruction examples"
42
+ include_context "Protocol1#read_instruction examples"
43
+ include_context "Protocol2#read_instruction examples"
44
+ include_context "Protocol3#read_instruction examples"
45
+ include_context "Protocol4#read_instruction examples"
46
+
47
+ context "when the opcode is not recognized" do
48
+ let(:opcode) { 255 }
49
+ let(:io) { StringIO.new(opcode.chr) }
50
+
51
+ it do
52
+ expect {
53
+ subject.read_instruction
54
+ }.to raise_error(Python::Pickle::InvalidFormat,"invalid opcode (#{opcode.inspect}) for protocol 4")
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'python/pickle/protocol5'
3
+
4
+ require 'protocol0_read_instruction_examples'
5
+ require 'protocol1_read_instruction_examples'
6
+ require 'protocol2_read_instruction_examples'
7
+ require 'protocol3_read_instruction_examples'
8
+ require 'protocol4_read_instruction_examples'
9
+
10
+ describe Python::Pickle::Protocol5 do
11
+ let(:pickle) { '' }
12
+ let(:io) { StringIO.new(pickle) }
13
+
14
+ subject { described_class.new(io) }
15
+
16
+ describe "#read_instruction" do
17
+ include_context "Protocol0#read_instruction examples"
18
+ include_context "Protocol1#read_instruction examples"
19
+ include_context "Protocol2#read_instruction examples"
20
+ include_context "Protocol3#read_instruction examples"
21
+ include_context "Protocol4#read_instruction examples"
22
+
23
+ describe "when the opcode is 150" do
24
+ let(:bytes) { [0x41, 0x42, 0x43] }
25
+ let(:string) { bytes.map(&:chr).join }
26
+ let(:length) { bytes.length }
27
+ let(:packed) { [length, *bytes].pack('Q<C*') }
28
+ let(:io) { StringIO.new("#{150.chr}#{packed}".b) }
29
+
30
+ it "must return a Python::Pickle::Instructions::ByteArray8" do
31
+ expect(subject.read_instruction).to eq(
32
+ Python::Pickle::Instructions::ByteArray8.new(length,string)
33
+ )
34
+ end
35
+ end
36
+
37
+ describe "when the opcode is 151" do
38
+ let(:io) { StringIO.new(151.chr) }
39
+
40
+ it "must return Python::Pickle::Instructions::NEXT_BUFFER" do
41
+ expect(subject.read_instruction).to be(
42
+ Python::Pickle::Instructions::NEXT_BUFFER
43
+ )
44
+ end
45
+ end
46
+
47
+ describe "when the opcode is 152" do
48
+ let(:io) { StringIO.new(152.chr) }
49
+
50
+ it "must return Python::Pickle::Instructions::READONLY_BUFFER" do
51
+ expect(subject.read_instruction).to be(
52
+ Python::Pickle::Instructions::READONLY_BUFFER
53
+ )
54
+ end
55
+ end
56
+
57
+ context "when the opcode is not recognized" do
58
+ let(:opcode) { 255 }
59
+ let(:io) { StringIO.new(opcode.chr) }
60
+
61
+ it do
62
+ expect {
63
+ subject.read_instruction
64
+ }.to raise_error(Python::Pickle::InvalidFormat,"invalid opcode (#{opcode.inspect}) for protocol 5")
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+ require 'python/pickle/py_class'
3
+
4
+ describe Python::Pickle::PyClass do
5
+ let(:namespace) { '__main__' }
6
+ let(:name) { 'MyClass' }
7
+
8
+ subject { described_class.new(namespace,name) }
9
+
10
+ describe "#initialize" do
11
+ it "must set #namespace" do
12
+ expect(subject.namespace).to eq(namespace)
13
+ end
14
+
15
+ it "must set #name" do
16
+ expect(subject.name).to eq(name)
17
+ end
18
+ end
19
+
20
+ describe "#new" do
21
+ let(:args) { [1,2,3] }
22
+
23
+ it "must return a new Python::Pickle::PyObject with the given arguments" do
24
+ py_object = subject.new(*args)
25
+
26
+ expect(py_object).to be_kind_of(Python::Pickle::PyObject)
27
+ expect(py_object.init_args).to eq(args)
28
+ end
29
+
30
+ context "when keyword arguments are given" do
31
+ let(:kwargs) { {x: 1, y: 2} }
32
+
33
+ it "must set #init_kwargs" do
34
+ py_object = subject.new(*args,**kwargs)
35
+
36
+ expect(py_object.init_kwargs).to eq(kwargs)
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#to_s" do
42
+ context "when #namespace is set" do
43
+ it "must return namespace.name" do
44
+ expect(subject.to_s).to eq("#{namespace}.#{name}")
45
+ end
46
+ end
47
+
48
+ context "when #namespace is not set" do
49
+ subject { described_class.new(name) }
50
+
51
+ it "must return #name" do
52
+ expect(subject.to_s).to eq(name)
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#inspect" do
58
+ it "must include the class name and namespace.name" do
59
+ expect(subject.inspect).to eq("#<#{described_class}: #{namespace}.#{name}>")
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,149 @@
1
+ require 'spec_helper'
2
+ require 'python/pickle/py_object'
3
+
4
+ describe Python::Pickle::PyObject do
5
+ let(:namespace) { '__main__' }
6
+ let(:name) { 'MyClass' }
7
+ let(:py_class) { Python::Pickle::PyClass.new(namespace,name) }
8
+
9
+ let(:init_args) { [1,2,3] }
10
+ let(:init_kwargs) { {x: 1, y: 2} }
11
+
12
+ subject { described_class.new(py_class,*init_args,**init_kwargs) }
13
+
14
+ describe "#initialize" do
15
+ it "must set #py_class" do
16
+ expect(subject.py_class).to be(py_class)
17
+ end
18
+
19
+ it "must set #attributes to an empty Hash" do
20
+ expect(subject.attributes).to eq({})
21
+ end
22
+
23
+ context "when called with additional arguments" do
24
+ subject { described_class.new(py_class,*init_args) }
25
+
26
+ it "must set #init_args" do
27
+ expect(subject.init_args).to eq(init_args)
28
+ end
29
+ end
30
+
31
+ context "when called with additional arguments" do
32
+ subject { described_class.new(py_class,*init_args,**init_kwargs) }
33
+
34
+ it "must set #init_kwargs" do
35
+ expect(subject.init_kwargs).to eq(init_kwargs)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#getattr" do
41
+ context "when the object has an attribute with the given name" do
42
+ let(:name) { 'x' }
43
+ let(:value) { 42 }
44
+
45
+ before do
46
+ subject.attributes[name] = value
47
+ end
48
+
49
+ it "must return the attribute's value" do
50
+ expect(subject.getattr(name)).to eq(value)
51
+ end
52
+ end
53
+
54
+ context "when the object does not have the given attribute" do
55
+ let(:name) { 'foo' }
56
+
57
+ it do
58
+ expect {
59
+ subject.getattr(name)
60
+ }.to raise_error(ArgumentError,"Python object has no attribute #{name.inspect}: #{subject.inspect}")
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "#setattr" do
66
+ let(:name) { 'x' }
67
+ let(:value) { 42 }
68
+
69
+ before do
70
+ subject.setattr(name,value)
71
+ end
72
+
73
+ it "must set the value of the attribute in #attributes" do
74
+ expect(subject.attributes[name]).to eq(value)
75
+ end
76
+ end
77
+
78
+ describe "#__setstate__" do
79
+ let(:new_attributes) { {'x' => 1, 'y' => 2} }
80
+
81
+ before do
82
+ subject.__setstate__(new_attributes)
83
+ end
84
+
85
+ it "must set #attributes" do
86
+ expect(subject.attributes).to eq(new_attributes)
87
+ end
88
+ end
89
+
90
+ describe "#to_h" do
91
+ before do
92
+ subject.setattr('x',1)
93
+ subject.setattr('y',2)
94
+ end
95
+
96
+ it "must return #attributes" do
97
+ expect(subject.to_h).to eq({'x' => 1, 'y' => 2})
98
+ end
99
+ end
100
+
101
+ describe "#method_missing" do
102
+ context "when the method name maps to an existing attribute" do
103
+ let(:name) { 'x' }
104
+ let(:value) { 42 }
105
+
106
+ before do
107
+ subject.setattr(name,value)
108
+ end
109
+
110
+ it "must return the attribute's value" do
111
+ expect(subject.send(name)).to eq(value)
112
+ end
113
+ end
114
+
115
+ context "when the method name does not map to an attribute" do
116
+ it "must return the attribute's value" do
117
+ expect {
118
+ subject.foo
119
+ }.to raise_error(NoMethodError)
120
+ end
121
+ end
122
+
123
+ context "when the method name ends with a '='" do
124
+ context "and ther eis one argument" do
125
+ it "must set the attribute's value" do
126
+ subject.foo = 1
127
+
128
+ expect(subject.foo).to eq(1)
129
+ end
130
+ end
131
+
132
+ context "but there are no arguments" do
133
+ it "must return the attribute's value" do
134
+ expect {
135
+ subject.send(:foo=)
136
+ }.to raise_error(NoMethodError)
137
+ end
138
+ end
139
+
140
+ context "but has more than one argument" do
141
+ it "must return the attribute's value" do
142
+ expect {
143
+ subject.send(:foo,1,2,3)
144
+ }.to raise_error(NoMethodError)
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+ require 'simplecov'
3
+ SimpleCov.start
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'python/pickle/tuple'
3
+
4
+ describe Python::Pickle::Tuple do
5
+ let(:elements) { [1,2,3] }
6
+
7
+ subject { described_class.new(elements) }
8
+
9
+ it "must inherit from Array" do
10
+ expect(subject).to be_kind_of(Array)
11
+ end
12
+
13
+ describe "#inspect" do
14
+ it "must include the class name and elements" do
15
+ expect(subject.inspect).to eq("#<#{described_class}: #{elements.inspect}>")
16
+ end
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,325 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: python-pickle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Postmodern
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-02-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ description: |
28
+ python-pickle is a modern Ruby implementation of the Python Pickle
29
+ serialization format. It supports protocol 0, protocol 1, protocol 2,
30
+ protocol 3, protocol 4, and protocol 5, allowing it to parse both Python 2
31
+ and Python 3 pickle data.
32
+ email: postmodern.mod3@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files:
36
+ - ChangeLog.md
37
+ - LICENSE.txt
38
+ - README.md
39
+ files:
40
+ - ".document"
41
+ - ".github/workflows/ruby.yml"
42
+ - ".gitignore"
43
+ - ".rspec"
44
+ - ".yardopts"
45
+ - ChangeLog.md
46
+ - Gemfile
47
+ - LICENSE.txt
48
+ - README.md
49
+ - Rakefile
50
+ - gemspec.yml
51
+ - lib/python/pickle.rb
52
+ - lib/python/pickle/byte_array.rb
53
+ - lib/python/pickle/deserializer.rb
54
+ - lib/python/pickle/exceptions.rb
55
+ - lib/python/pickle/instruction.rb
56
+ - lib/python/pickle/instructions/add_items.rb
57
+ - lib/python/pickle/instructions/append.rb
58
+ - lib/python/pickle/instructions/appends.rb
59
+ - lib/python/pickle/instructions/bin_bytes.rb
60
+ - lib/python/pickle/instructions/bin_bytes8.rb
61
+ - lib/python/pickle/instructions/bin_float.rb
62
+ - lib/python/pickle/instructions/bin_get.rb
63
+ - lib/python/pickle/instructions/bin_int1.rb
64
+ - lib/python/pickle/instructions/bin_put.rb
65
+ - lib/python/pickle/instructions/bin_string.rb
66
+ - lib/python/pickle/instructions/bin_unicode.rb
67
+ - lib/python/pickle/instructions/bin_unicode8.rb
68
+ - lib/python/pickle/instructions/build.rb
69
+ - lib/python/pickle/instructions/byte_array8.rb
70
+ - lib/python/pickle/instructions/dict.rb
71
+ - lib/python/pickle/instructions/dup.rb
72
+ - lib/python/pickle/instructions/empty_dict.rb
73
+ - lib/python/pickle/instructions/empty_list.rb
74
+ - lib/python/pickle/instructions/empty_set.rb
75
+ - lib/python/pickle/instructions/empty_tuple.rb
76
+ - lib/python/pickle/instructions/ext1.rb
77
+ - lib/python/pickle/instructions/ext2.rb
78
+ - lib/python/pickle/instructions/ext4.rb
79
+ - lib/python/pickle/instructions/float.rb
80
+ - lib/python/pickle/instructions/frame.rb
81
+ - lib/python/pickle/instructions/frozen_set.rb
82
+ - lib/python/pickle/instructions/get.rb
83
+ - lib/python/pickle/instructions/global.rb
84
+ - lib/python/pickle/instructions/has_length_and_value.rb
85
+ - lib/python/pickle/instructions/has_value.rb
86
+ - lib/python/pickle/instructions/int.rb
87
+ - lib/python/pickle/instructions/list.rb
88
+ - lib/python/pickle/instructions/long.rb
89
+ - lib/python/pickle/instructions/long1.rb
90
+ - lib/python/pickle/instructions/long4.rb
91
+ - lib/python/pickle/instructions/long_bin_get.rb
92
+ - lib/python/pickle/instructions/mark.rb
93
+ - lib/python/pickle/instructions/memoize.rb
94
+ - lib/python/pickle/instructions/new_false.rb
95
+ - lib/python/pickle/instructions/new_obj.rb
96
+ - lib/python/pickle/instructions/new_obj_ex.rb
97
+ - lib/python/pickle/instructions/new_true.rb
98
+ - lib/python/pickle/instructions/next_buffer.rb
99
+ - lib/python/pickle/instructions/none.rb
100
+ - lib/python/pickle/instructions/pop.rb
101
+ - lib/python/pickle/instructions/pop_mark.rb
102
+ - lib/python/pickle/instructions/proto.rb
103
+ - lib/python/pickle/instructions/put.rb
104
+ - lib/python/pickle/instructions/readonly_buffer.rb
105
+ - lib/python/pickle/instructions/reduce.rb
106
+ - lib/python/pickle/instructions/set_item.rb
107
+ - lib/python/pickle/instructions/set_items.rb
108
+ - lib/python/pickle/instructions/short_bin_bytes.rb
109
+ - lib/python/pickle/instructions/short_bin_string.rb
110
+ - lib/python/pickle/instructions/short_bin_unicode.rb
111
+ - lib/python/pickle/instructions/stack_global.rb
112
+ - lib/python/pickle/instructions/stop.rb
113
+ - lib/python/pickle/instructions/string.rb
114
+ - lib/python/pickle/instructions/tuple.rb
115
+ - lib/python/pickle/instructions/tuple1.rb
116
+ - lib/python/pickle/instructions/tuple2.rb
117
+ - lib/python/pickle/instructions/tuple3.rb
118
+ - lib/python/pickle/protocol.rb
119
+ - lib/python/pickle/protocol0.rb
120
+ - lib/python/pickle/protocol1.rb
121
+ - lib/python/pickle/protocol2.rb
122
+ - lib/python/pickle/protocol3.rb
123
+ - lib/python/pickle/protocol4.rb
124
+ - lib/python/pickle/protocol5.rb
125
+ - lib/python/pickle/py_class.rb
126
+ - lib/python/pickle/py_object.rb
127
+ - lib/python/pickle/tuple.rb
128
+ - lib/python/pickle/version.rb
129
+ - python-pickle.gemspec
130
+ - spec/byte_array_spec.rb
131
+ - spec/deserializer_spec.rb
132
+ - spec/fixtures/ascii_str_v3.pkl
133
+ - spec/fixtures/ascii_str_v4.pkl
134
+ - spec/fixtures/ascii_str_v5.pkl
135
+ - spec/fixtures/bin_str_v0.pkl
136
+ - spec/fixtures/bin_str_v1.pkl
137
+ - spec/fixtures/bin_str_v2.pkl
138
+ - spec/fixtures/bin_str_v3.pkl
139
+ - spec/fixtures/bin_str_v4.pkl
140
+ - spec/fixtures/bin_str_v5.pkl
141
+ - spec/fixtures/bytearray_v0.pkl
142
+ - spec/fixtures/bytearray_v1.pkl
143
+ - spec/fixtures/bytearray_v2.pkl
144
+ - spec/fixtures/bytearray_v3.pkl
145
+ - spec/fixtures/bytearray_v4.pkl
146
+ - spec/fixtures/bytearray_v5.pkl
147
+ - spec/fixtures/class_v0.pkl
148
+ - spec/fixtures/class_v1.pkl
149
+ - spec/fixtures/class_v2.pkl
150
+ - spec/fixtures/class_v3.pkl
151
+ - spec/fixtures/class_v4.pkl
152
+ - spec/fixtures/class_v5.pkl
153
+ - spec/fixtures/dict_v0.pkl
154
+ - spec/fixtures/dict_v1.pkl
155
+ - spec/fixtures/dict_v2.pkl
156
+ - spec/fixtures/dict_v3.pkl
157
+ - spec/fixtures/dict_v4.pkl
158
+ - spec/fixtures/dict_v5.pkl
159
+ - spec/fixtures/escaped_str_v0.pkl
160
+ - spec/fixtures/escaped_str_v1.pkl
161
+ - spec/fixtures/escaped_str_v2.pkl
162
+ - spec/fixtures/false_v0.pkl
163
+ - spec/fixtures/false_v1.pkl
164
+ - spec/fixtures/false_v2.pkl
165
+ - spec/fixtures/false_v3.pkl
166
+ - spec/fixtures/false_v4.pkl
167
+ - spec/fixtures/false_v5.pkl
168
+ - spec/fixtures/float_v0.pkl
169
+ - spec/fixtures/float_v1.pkl
170
+ - spec/fixtures/float_v2.pkl
171
+ - spec/fixtures/float_v3.pkl
172
+ - spec/fixtures/float_v4.pkl
173
+ - spec/fixtures/float_v5.pkl
174
+ - spec/fixtures/function_v0.pkl
175
+ - spec/fixtures/function_v1.pkl
176
+ - spec/fixtures/function_v2.pkl
177
+ - spec/fixtures/function_v3.pkl
178
+ - spec/fixtures/function_v4.pkl
179
+ - spec/fixtures/function_v5.pkl
180
+ - spec/fixtures/hex_str_v0.pkl
181
+ - spec/fixtures/hex_str_v1.pkl
182
+ - spec/fixtures/hex_str_v2.pkl
183
+ - spec/fixtures/int_v0.pkl
184
+ - spec/fixtures/int_v1.pkl
185
+ - spec/fixtures/int_v2.pkl
186
+ - spec/fixtures/int_v3.pkl
187
+ - spec/fixtures/int_v4.pkl
188
+ - spec/fixtures/int_v5.pkl
189
+ - spec/fixtures/list_v0.pkl
190
+ - spec/fixtures/list_v1.pkl
191
+ - spec/fixtures/list_v2.pkl
192
+ - spec/fixtures/list_v3.pkl
193
+ - spec/fixtures/list_v4.pkl
194
+ - spec/fixtures/list_v5.pkl
195
+ - spec/fixtures/long_v0.pkl
196
+ - spec/fixtures/long_v1.pkl
197
+ - spec/fixtures/long_v2.pkl
198
+ - spec/fixtures/long_v3.pkl
199
+ - spec/fixtures/long_v4.pkl
200
+ - spec/fixtures/long_v5.pkl
201
+ - spec/fixtures/nested_dict_v0.pkl
202
+ - spec/fixtures/nested_dict_v1.pkl
203
+ - spec/fixtures/nested_dict_v2.pkl
204
+ - spec/fixtures/nested_dict_v3.pkl
205
+ - spec/fixtures/nested_dict_v4.pkl
206
+ - spec/fixtures/nested_dict_v5.pkl
207
+ - spec/fixtures/nested_list_v0.pkl
208
+ - spec/fixtures/nested_list_v1.pkl
209
+ - spec/fixtures/nested_list_v2.pkl
210
+ - spec/fixtures/nested_list_v3.pkl
211
+ - spec/fixtures/nested_list_v4.pkl
212
+ - spec/fixtures/nested_list_v5.pkl
213
+ - spec/fixtures/none_v0.pkl
214
+ - spec/fixtures/none_v1.pkl
215
+ - spec/fixtures/none_v2.pkl
216
+ - spec/fixtures/none_v3.pkl
217
+ - spec/fixtures/none_v4.pkl
218
+ - spec/fixtures/none_v5.pkl
219
+ - spec/fixtures/object_v0.pkl
220
+ - spec/fixtures/object_v1.pkl
221
+ - spec/fixtures/object_v2.pkl
222
+ - spec/fixtures/object_v3.pkl
223
+ - spec/fixtures/object_v4.pkl
224
+ - spec/fixtures/object_v5.pkl
225
+ - spec/fixtures/str_v0.pkl
226
+ - spec/fixtures/str_v1.pkl
227
+ - spec/fixtures/str_v2.pkl
228
+ - spec/fixtures/str_v3.pkl
229
+ - spec/fixtures/str_v4.pkl
230
+ - spec/fixtures/str_v5.pkl
231
+ - spec/fixtures/true_v0.pkl
232
+ - spec/fixtures/true_v1.pkl
233
+ - spec/fixtures/true_v2.pkl
234
+ - spec/fixtures/true_v3.pkl
235
+ - spec/fixtures/true_v4.pkl
236
+ - spec/fixtures/true_v5.pkl
237
+ - spec/fixtures/unicode_str_v0.pkl
238
+ - spec/fixtures/unicode_str_v1.pkl
239
+ - spec/fixtures/unicode_str_v2.pkl
240
+ - spec/fixtures/unicode_str_v3.pkl
241
+ - spec/fixtures/unicode_str_v4.pkl
242
+ - spec/fixtures/unicode_str_v5.pkl
243
+ - spec/generate_pickles2.py
244
+ - spec/generate_pickles3.py
245
+ - spec/integration/load/protocol0_spec.rb
246
+ - spec/integration/load/protocol1_spec.rb
247
+ - spec/integration/load/protocol2_spec.rb
248
+ - spec/integration/load/protocol3_spec.rb
249
+ - spec/integration/load/protocol4_spec.rb
250
+ - spec/integration/load/protocol5_spec.rb
251
+ - spec/integration/parse/protocol0_spec.rb
252
+ - spec/integration/parse/protocol1_spec.rb
253
+ - spec/integration/parse/protocol2_spec.rb
254
+ - spec/integration/parse/protocol3_spec.rb
255
+ - spec/integration/parse/protocol4_spec.rb
256
+ - spec/integration/parse/protocol5_spec.rb
257
+ - spec/pickle_spec.rb
258
+ - spec/protocol0_read_instruction_examples.rb
259
+ - spec/protocol0_spec.rb
260
+ - spec/protocol1_read_instruction_examples.rb
261
+ - spec/protocol1_spec.rb
262
+ - spec/protocol2_read_instruction_examples.rb
263
+ - spec/protocol2_spec.rb
264
+ - spec/protocol3_read_instruction_examples.rb
265
+ - spec/protocol3_spec.rb
266
+ - spec/protocol4_read_instruction_examples.rb
267
+ - spec/protocol4_spec.rb
268
+ - spec/protocol5_spec.rb
269
+ - spec/py_class_spec.rb
270
+ - spec/py_object_spec.rb
271
+ - spec/spec_helper.rb
272
+ - spec/tuple_spec.rb
273
+ homepage: https://github.com/postmodern/python-pickle.rb#readme
274
+ licenses:
275
+ - MIT
276
+ metadata:
277
+ documentation_uri: https://rubydoc.info/gems/python-pickle
278
+ source_code_uri: https://github.com/postmodern/python-pickle.rb
279
+ bug_tracker_uri: https://github.com/postmodern/python-pickle.rb/issues
280
+ changelog_uri: https://github.com/postmodern/python-pickle.rb/blob/master/ChangeLog.md
281
+ rubygems_mfa_required: 'true'
282
+ post_install_message:
283
+ rdoc_options: []
284
+ require_paths:
285
+ - lib
286
+ required_ruby_version: !ruby/object:Gem::Requirement
287
+ requirements:
288
+ - - ">="
289
+ - !ruby/object:Gem::Version
290
+ version: 3.0.0
291
+ required_rubygems_version: !ruby/object:Gem::Requirement
292
+ requirements:
293
+ - - ">="
294
+ - !ruby/object:Gem::Version
295
+ version: '0'
296
+ requirements: []
297
+ rubygems_version: 3.3.26
298
+ signing_key:
299
+ specification_version: 4
300
+ summary: A modern Ruby implementation of the Python Pickle serialization format.
301
+ test_files:
302
+ - spec/byte_array_spec.rb
303
+ - spec/deserializer_spec.rb
304
+ - spec/integration/load/protocol0_spec.rb
305
+ - spec/integration/load/protocol1_spec.rb
306
+ - spec/integration/load/protocol2_spec.rb
307
+ - spec/integration/load/protocol3_spec.rb
308
+ - spec/integration/load/protocol4_spec.rb
309
+ - spec/integration/load/protocol5_spec.rb
310
+ - spec/integration/parse/protocol0_spec.rb
311
+ - spec/integration/parse/protocol1_spec.rb
312
+ - spec/integration/parse/protocol2_spec.rb
313
+ - spec/integration/parse/protocol3_spec.rb
314
+ - spec/integration/parse/protocol4_spec.rb
315
+ - spec/integration/parse/protocol5_spec.rb
316
+ - spec/pickle_spec.rb
317
+ - spec/protocol0_spec.rb
318
+ - spec/protocol1_spec.rb
319
+ - spec/protocol2_spec.rb
320
+ - spec/protocol3_spec.rb
321
+ - spec/protocol4_spec.rb
322
+ - spec/protocol5_spec.rb
323
+ - spec/py_class_spec.rb
324
+ - spec/py_object_spec.rb
325
+ - spec/tuple_spec.rb