python-pickle 0.1.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.
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