python-pickle 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +17 -0
  3. data/README.md +4 -1
  4. data/lib/python/pickle/deserializer.rb +142 -80
  5. data/lib/python/pickle/instructions/bin_persid.rb +31 -0
  6. data/lib/python/pickle/instructions/global.rb +11 -41
  7. data/lib/python/pickle/instructions/has_namespace_and_name.rb +61 -0
  8. data/lib/python/pickle/instructions/inst.rb +34 -0
  9. data/lib/python/pickle/instructions/next_buffer.rb +5 -1
  10. data/lib/python/pickle/instructions/obj.rb +30 -0
  11. data/lib/python/pickle/instructions/persid.rb +31 -0
  12. data/lib/python/pickle/instructions/readonly_buffer.rb +4 -0
  13. data/lib/python/pickle/instructions.rb +64 -0
  14. data/lib/python/pickle/protocol0.rb +313 -68
  15. data/lib/python/pickle/protocol1.rb +225 -93
  16. data/lib/python/pickle/protocol2.rb +205 -124
  17. data/lib/python/pickle/protocol3.rb +92 -123
  18. data/lib/python/pickle/protocol4.rb +188 -165
  19. data/lib/python/pickle/protocol5.rb +98 -166
  20. data/lib/python/pickle/version.rb +1 -1
  21. data/lib/python/pickle.rb +71 -39
  22. data/spec/deserializer_spec.rb +359 -0
  23. data/spec/fixtures/set_v0.pkl +11 -0
  24. data/spec/fixtures/set_v1.pkl +0 -0
  25. data/spec/fixtures/set_v2.pkl +0 -0
  26. data/spec/fixtures/set_v3.pkl +0 -0
  27. data/spec/fixtures/set_v4.pkl +0 -0
  28. data/spec/fixtures/set_v5.pkl +0 -0
  29. data/spec/generate_pickles2.py +1 -0
  30. data/spec/generate_pickles3.py +1 -0
  31. data/spec/integration/load/protocol0_spec.rb +10 -0
  32. data/spec/integration/load/protocol1_spec.rb +10 -0
  33. data/spec/integration/load/protocol2_spec.rb +10 -0
  34. data/spec/integration/load/protocol3_spec.rb +10 -0
  35. data/spec/integration/load/protocol4_spec.rb +10 -0
  36. data/spec/integration/load/protocol5_spec.rb +10 -0
  37. data/spec/pickle_spec.rb +61 -0
  38. data/spec/protocol0_read_instruction_examples.rb +44 -0
  39. metadata +14 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea86f43e4b83bacac94635b88e2c9deeb6eb4aaa553f1770e4943554389422fc
4
- data.tar.gz: 973327ecbd8f2c1df7d0ac10f37d76628745e00da9317ab655a9f12644fef441
3
+ metadata.gz: c8fe6820a4b047c2e2eb027c3dbe88b5b8d7e51d201864e9e7b726cb566d687d
4
+ data.tar.gz: b1b66aa3811a277b63f643eb4c2968bab268ab7c22aa061713c1555f8d66162b
5
5
  SHA512:
6
- metadata.gz: 8b95a73ff2ebfba7c9ca97648df7c7b3b6be14df61e0e6f4943e3e263a5f300696e79d8cf57aacc7bd9d572bcf3c00a5ec88162e1dd8cc627617afe01414499d
7
- data.tar.gz: 73a9a106cfa346d3d74835cf9369732f041fdb2faafdb8a030f1e9ec6b58831e8b7c8aee3a05bec687d11d2d4ea9d48a00d4fcf164f0c686eb84c1248b15f056
6
+ metadata.gz: b44f4bddc1cfcbdfc4d7fda78a30b9982c268701109bbb92da050c1c226a006859f3a9dacd872c9362bb8c237723b7d8401dcb28626ad9a2e49b83af3c8c32d1
7
+ data.tar.gz: 8301c1d66a60a6cb7468f32a6f801d3b0ed699d771af7625eba034aafef762815201cb12b9484976248abe84cc32278647991e1cbb76745ebea84994e5ff2f2a
data/ChangeLog.md CHANGED
@@ -1,3 +1,20 @@
1
+ ### 0.2.0 / 2023-02-19
2
+
3
+ * Added missing support for deserializing Python `set` objects.
4
+ * Added missing support for out-of-band buffers.
5
+ * Added partial support for parsing the `PERSID` and `BINPERSID` instructions.
6
+ * Added missing support for deserializing the `INST` and `OBJ` instructions.
7
+ * Added missing support for deserializing the `EMPTY_SET`, `FROZENSET`, and
8
+ `ADDITEMS` Pickle instructions.
9
+ * Added missing support for deserializing the `NEXT_BUFFER` and
10
+ `READONLY_BUFFER` Pickle instructions.
11
+ * Map `__builtin__.set` and `builtins.set` to Ruby's `Set` class.
12
+
13
+ ### 0.1.0 / 2023-02-18
14
+
15
+ * Changed {Python::Pickle.dump} to raise a `NotImplementedError` exception.
16
+ * Fixed a typo in the method signature of {Python::Pickle.dump}.
17
+
1
18
  ### 0.1.0 / 2023-02-18
2
19
 
3
20
  * Initial release:
data/README.md CHANGED
@@ -20,9 +20,12 @@ format.
20
20
  * Supports Pickle protocol 0, protocol 1, protocol 2, protocol 3, protocol 4,
21
21
  and protocol 5.
22
22
  * Can parse both Python 2 and Python 3 Pickled data.
23
- * Supports deserializing Python `tuple` and `bytearray` objects.
23
+ * Supports deserializing Python `None`, `True`, `False`, `int`, `str`, `tuple`,
24
+ `set`, `list`, `bytearray`, and other objects.
25
+ * Supports mapping Python extension codes to Ruby classes.
24
26
  * Supports mapping Python functions to Ruby methods.
25
27
  * Supports mapping Python classes to Ruby classes.
28
+ * Supports out-of-band buffers.
26
29
 
27
30
  ## TODO
28
31
 
@@ -2,63 +2,10 @@ require 'python/pickle/py_class'
2
2
  require 'python/pickle/py_object'
3
3
  require 'python/pickle/tuple'
4
4
  require 'python/pickle/byte_array'
5
+ require 'python/pickle/instructions'
5
6
  require 'python/pickle/exceptions'
6
7
 
7
- require 'python/pickle/instructions/proto'
8
- require 'python/pickle/instructions/frame'
9
- require 'python/pickle/instructions/get'
10
- require 'python/pickle/instructions/bin_get'
11
- require 'python/pickle/instructions/long_bin_get'
12
- require 'python/pickle/instructions/mark'
13
- require 'python/pickle/instructions/pop_mark'
14
- require 'python/pickle/instructions/dup'
15
- require 'python/pickle/instructions/put'
16
- require 'python/pickle/instructions/bin_put'
17
- require 'python/pickle/instructions/pop'
18
- require 'python/pickle/instructions/memoize'
19
- require 'python/pickle/instructions/ext1'
20
- require 'python/pickle/instructions/ext2'
21
- require 'python/pickle/instructions/ext4'
22
- require 'python/pickle/instructions/none'
23
- require 'python/pickle/instructions/new_true'
24
- require 'python/pickle/instructions/new_false'
25
- require 'python/pickle/instructions/float'
26
- require 'python/pickle/instructions/bin_float'
27
- require 'python/pickle/instructions/int'
28
- require 'python/pickle/instructions/bin_int1'
29
- require 'python/pickle/instructions/long'
30
- require 'python/pickle/instructions/long1'
31
- require 'python/pickle/instructions/long4'
32
- require 'python/pickle/instructions/bin_bytes'
33
- require 'python/pickle/instructions/short_bin_bytes'
34
- require 'python/pickle/instructions/bin_bytes8'
35
- require 'python/pickle/instructions/string'
36
- require 'python/pickle/instructions/bin_string'
37
- require 'python/pickle/instructions/short_bin_string'
38
- require 'python/pickle/instructions/bin_unicode'
39
- require 'python/pickle/instructions/short_bin_unicode'
40
- require 'python/pickle/instructions/bin_unicode8'
41
- require 'python/pickle/instructions/byte_array8'
42
- require 'python/pickle/instructions/empty_list'
43
- require 'python/pickle/instructions/empty_tuple'
44
- require 'python/pickle/instructions/tuple'
45
- require 'python/pickle/instructions/empty_dict'
46
- require 'python/pickle/instructions/append'
47
- require 'python/pickle/instructions/appends'
48
- require 'python/pickle/instructions/list'
49
- require 'python/pickle/instructions/tuple1'
50
- require 'python/pickle/instructions/tuple2'
51
- require 'python/pickle/instructions/tuple3'
52
- require 'python/pickle/instructions/dict'
53
- require 'python/pickle/instructions/global'
54
- require 'python/pickle/instructions/stack_global'
55
- require 'python/pickle/instructions/new_obj'
56
- require 'python/pickle/instructions/new_obj_ex'
57
- require 'python/pickle/instructions/reduce'
58
- require 'python/pickle/instructions/build'
59
- require 'python/pickle/instructions/set_item'
60
- require 'python/pickle/instructions/set_items'
61
- require 'python/pickle/instructions/stop'
8
+ require 'set'
62
9
 
63
10
  module Python
64
11
  module Pickle
@@ -94,6 +41,11 @@ module Python
94
41
  # @return [Hash{Integer => Object}]
95
42
  attr_reader :extensions
96
43
 
44
+ # An enumerable list of out-of-band buffers.
45
+ #
46
+ # @return [Enumerator, nil]
47
+ attr_reader :buffers
48
+
97
49
  # The Python `object` class.
98
50
  OBJECT_CLASS = PyClass.new('__builtins__','object')
99
51
 
@@ -107,7 +59,10 @@ module Python
107
59
  # An optional mapping of custom Python constant names to Ruby classes
108
60
  # or methods.
109
61
  #
110
- def initialize(constants: nil, extensions: nil)
62
+ # @param [Enumerable, nil] buffers
63
+ # An enumerable list of out-of-band buffers.
64
+ #
65
+ def initialize(constants: nil, extensions: nil, buffers: nil)
111
66
  @meta_stack = []
112
67
  @stack = []
113
68
  @memo = []
@@ -120,12 +75,14 @@ module Python
120
75
 
121
76
  '__builtin__' => {
122
77
  'object' => OBJECT_CLASS,
78
+ 'set' => Set,
123
79
  'bytearray' => ByteArray
124
80
  },
125
81
 
126
82
  # Python 3.x
127
83
  'builtins' => {
128
84
  'object' => OBJECT_CLASS,
85
+ 'set' => Set,
129
86
  'bytearray' => ByteArray
130
87
  }
131
88
  }
@@ -133,6 +90,8 @@ module Python
133
90
 
134
91
  @extensions = {}
135
92
  @extensions.merge!(extensions) if extensions
93
+
94
+ @buffers = buffers.each if buffers
136
95
  end
137
96
 
138
97
  #
@@ -199,26 +158,33 @@ module Python
199
158
  Instructions::ShortBinUnicode,
200
159
  Instructions::BinUnicode8
201
160
  @stack.push(instruction.value)
202
- when Instructions::ByteArray8 then execute_byte_array8(instruction)
203
- when Instructions::EMPTY_LIST then execute_empty_list
204
- when Instructions::EMPTY_TUPLE then execute_empty_tuple
205
- when Instructions::TUPLE then execute_tuple
206
- when Instructions::EMPTY_DICT then execute_empty_dict
207
- when Instructions::APPEND then execute_append
208
- when Instructions::APPENDS then execute_appends
209
- when Instructions::LIST then execute_list
210
- when Instructions::TUPLE1 then execute_tuple1
211
- when Instructions::TUPLE2 then execute_tuple2
212
- when Instructions::TUPLE3 then execute_tuple3
213
- when Instructions::DICT then execute_dict
214
- when Instructions::Global then execute_global(instruction)
215
- when Instructions::STACK_GLOBAL then execute_stack_global
216
- when Instructions::NEWOBJ then execute_newobj
217
- when Instructions::NEWOBJ_EX then execute_newobj_ex
218
- when Instructions::REDUCE then execute_reduce
219
- when Instructions::BUILD then execute_build
220
- when Instructions::SETITEM then execute_setitem
221
- when Instructions::SETITEMS then execute_setitems
161
+ when Instructions::ByteArray8 then execute_byte_array8(instruction)
162
+ when Instructions::EMPTY_LIST then execute_empty_list
163
+ when Instructions::EMPTY_TUPLE then execute_empty_tuple
164
+ when Instructions::TUPLE then execute_tuple
165
+ when Instructions::EMPTY_DICT then execute_empty_dict
166
+ when Instructions::EMPTY_SET then execute_empty_set
167
+ when Instructions::FROZENSET then execute_frozenset
168
+ when Instructions::APPEND then execute_append
169
+ when Instructions::APPENDS then execute_appends
170
+ when Instructions::ADDITEMS then execute_additems
171
+ when Instructions::LIST then execute_list
172
+ when Instructions::TUPLE1 then execute_tuple1
173
+ when Instructions::TUPLE2 then execute_tuple2
174
+ when Instructions::TUPLE3 then execute_tuple3
175
+ when Instructions::DICT then execute_dict
176
+ when Instructions::Global then execute_global(instruction)
177
+ when Instructions::STACK_GLOBAL then execute_stack_global
178
+ when Instructions::Inst then execute_inst(instruction)
179
+ when Instructions::OBJ then execute_obj
180
+ when Instructions::NEWOBJ then execute_newobj
181
+ when Instructions::NEWOBJ_EX then execute_newobj_ex
182
+ when Instructions::REDUCE then execute_reduce
183
+ when Instructions::BUILD then execute_build
184
+ when Instructions::SETITEM then execute_setitem
185
+ when Instructions::SETITEMS then execute_setitems
186
+ when Instructions::NEXT_BUFFER then execute_next_buffer
187
+ when Instructions::READONLY_BUFFER then execute_readonly_buffer
222
188
  when Instructions::STOP
223
189
  return :halt, @stack.pop
224
190
  else
@@ -361,6 +327,29 @@ module Python
361
327
  @stack.push({})
362
328
  end
363
329
 
330
+ #
331
+ # Executes an `EMPTY_SET` instruction.
332
+ #
333
+ # @since 0.2.0
334
+ #
335
+ def execute_empty_set
336
+ @stack.push(Set.new)
337
+ end
338
+
339
+ #
340
+ # Executes a `FROZENSET` instruction.
341
+ #
342
+ # @since 0.2.0
343
+ #
344
+ def execute_frozenset
345
+ items = pop_meta_stack
346
+
347
+ set = Set.new(items)
348
+ set.freeze
349
+
350
+ @stack.push(set)
351
+ end
352
+
364
353
  #
365
354
  # Executes an `APPEND` instruction.
366
355
  #
@@ -368,11 +357,11 @@ module Python
368
357
  item = @stack.pop
369
358
  list = @stack.last
370
359
 
371
- unless list.kind_of?(Array)
360
+ unless (list.kind_of?(Array) || list.kind_of?(Set))
372
361
  raise(DeserializationError,"cannot append element #{item.inspect} onto a non-Array: #{list.inspect}")
373
362
  end
374
363
 
375
- list.push(item)
364
+ list << item
376
365
  end
377
366
 
378
367
  #
@@ -382,11 +371,34 @@ module Python
382
371
  items = pop_meta_stack
383
372
  list = @stack.last
384
373
 
385
- unless list.kind_of?(Array)
374
+ case list
375
+ when Array
376
+ list.concat(items)
377
+ when Set
378
+ items.each do |item|
379
+ list << item
380
+ end
381
+ else
386
382
  raise(DeserializationError,"cannot append elements #{items.inspect} onto a non-Array: #{list.inspect}")
387
383
  end
384
+ end
385
+
386
+ #
387
+ # Executes a `ADDITEMS` instruction.
388
+ #
389
+ # @since 0.2.0
390
+ #
391
+ def execute_additems
392
+ items = pop_meta_stack
393
+ set = @stack.last
394
+
395
+ unless set.kind_of?(Set)
396
+ raise(DeserializationError,"cannot add items #{items.inspect} to a non-Set object: #{set.inspect}")
397
+ end
388
398
 
389
- list.concat(items)
399
+ items.each do |item|
400
+ set << item
401
+ end
390
402
  end
391
403
 
392
404
  #
@@ -500,6 +512,33 @@ module Python
500
512
  @stack.push(constant)
501
513
  end
502
514
 
515
+ #
516
+ # Executes an `INST` instruction.
517
+ #
518
+ # @since 0.2.0
519
+ #
520
+ def execute_inst(instruction)
521
+ namespace = instruction.namespace
522
+ name = instruction.name
523
+ py_class = resolve_constant(namespace,name)
524
+ args = pop_meta_stack
525
+ py_object = py_class.new(*args)
526
+
527
+ @stack.push(py_object)
528
+ end
529
+
530
+ #
531
+ # Executes an `OBJ` instruction.
532
+ #
533
+ # @since 0.2.0
534
+ #
535
+ def execute_obj
536
+ py_class, *args = pop_meta_stack
537
+ py_object = py_class.new(*args)
538
+
539
+ @stack.push(py_object)
540
+ end
541
+
503
542
  #
504
543
  # Executes a `NEWOBJ` instruction.
505
544
  #
@@ -590,6 +629,29 @@ module Python
590
629
  end
591
630
  end
592
631
 
632
+ #
633
+ # Executes a `NEXT_BUFFER` instruction.
634
+ #
635
+ # @since 0.2.0
636
+ #
637
+ def execute_next_buffer
638
+ unless @buffers
639
+ raise(DeserializationError,"pickle stream includes a NEXT_BUFFER instruction, but no buffers were provided")
640
+ end
641
+
642
+ @stack.push(@buffers.next)
643
+ end
644
+
645
+ #
646
+ # Executes a `READONLY_BUFFER` instruction.
647
+ #
648
+ # @since 0.2.0
649
+ #
650
+ def execute_readonly_buffer
651
+ buffer = @stack.last
652
+ buffer.freeze
653
+ end
654
+
593
655
  end
594
656
  end
595
657
  end
@@ -0,0 +1,31 @@
1
+ require 'python/pickle/instruction'
2
+ require 'python/pickle/instructions/has_value'
3
+
4
+ module Python
5
+ module Pickle
6
+ module Instructions
7
+ #
8
+ # Represents the `BINPERSID` instruction.
9
+ #
10
+ # @note introduced in protocol 0.
11
+ #
12
+ # @since 0.2.0
13
+ #
14
+ class BinPersID < Instruction
15
+
16
+ #
17
+ # Initializes the `BINPERSID` instruction.
18
+ #
19
+ def initialize
20
+ super(:BINPERSID)
21
+ end
22
+
23
+ end
24
+
25
+ # Represents the `BINPERSID` instruction.
26
+ #
27
+ # @since 0.2.0
28
+ BINPERSID = BinPersID.new
29
+ end
30
+ end
31
+ end
@@ -1,59 +1,29 @@
1
1
  require 'python/pickle/instruction'
2
- require 'python/pickle/instructions/has_value'
2
+ require 'python/pickle/instructions/has_namespace_and_name'
3
3
 
4
4
  module Python
5
5
  module Pickle
6
6
  module Instructions
7
+ #
8
+ # Represents the `GLOBAL` instruction.
9
+ #
10
+ # @note introduced in protocol 0.
11
+ #
7
12
  class Global < Instruction
8
13
 
9
- # The global object namespace.
10
- #
11
- # @return [String]
12
- attr_reader :namespace
13
-
14
- # The global object name.
15
- #
16
- # @return [String]
17
- attr_reader :name
14
+ include HasNamespaceAndName
18
15
 
19
16
  #
20
- # Initializes the `GLOBAL` instruction.
17
+ # Initializes a `GLOBAL` instruction.
21
18
  #
22
19
  # @param [String] namespace
23
- # The namespace name for the global object.
20
+ # The namespace name for the constant.
24
21
  #
25
22
  # @param [String] name
26
- # The name of the global object.
23
+ # The name of the constant.
27
24
  #
28
25
  def initialize(namespace,name)
29
- super(:GLOBAL)
30
-
31
- @namespace = namespace
32
- @name = name
33
- end
34
-
35
- #
36
- # Compares the `GLOBAL` instruction to another instruction.
37
- #
38
- # @param [Instruction] other
39
- # The other instruction to compare against.
40
- #
41
- # @return [Boolean]
42
- # Indicates whether the other instruction matches this one.
43
- #
44
- def ==(other)
45
- super(other) && \
46
- (@namespace == other.namespace) && \
47
- (@name == other.name)
48
- end
49
-
50
- #
51
- # Converts the `GLOBAL` instructions to a String.
52
- #
53
- # @return [String]
54
- #
55
- def to_s
56
- "#{super} #{@namespace}.#{@name}"
26
+ super(:GLOBAL,namespace,name)
57
27
  end
58
28
 
59
29
  end
@@ -0,0 +1,61 @@
1
+ module Python
2
+ module Pickle
3
+ module Instructions
4
+ module HasNamespaceAndName
5
+ # The constant's namespace.
6
+ #
7
+ # @return [String]
8
+ attr_reader :namespace
9
+
10
+ # The constant name.
11
+ #
12
+ # @return [String]
13
+ attr_reader :name
14
+
15
+ #
16
+ # Initializes the instruction.
17
+ #
18
+ # @param [Symbol] opcode
19
+ # The instruction's opcode.
20
+ #
21
+ # @param [String] namespace
22
+ # The namespace name for the constant.
23
+ #
24
+ # @param [String] name
25
+ # The name of the constant.
26
+ #
27
+ def initialize(opcode,namespace,name)
28
+ super(opcode)
29
+
30
+ @namespace = namespace
31
+ @name = name
32
+ end
33
+
34
+ #
35
+ # Compares the instruction to another instruction.
36
+ #
37
+ # @param [Instruction] other
38
+ # The other instruction to compare against.
39
+ #
40
+ # @return [Boolean]
41
+ # Indicates whether the other instruction matches this one.
42
+ #
43
+ def ==(other)
44
+ super(other) && \
45
+ (@namespace == other.namespace) && \
46
+ (@name == other.name)
47
+ end
48
+
49
+ #
50
+ # Converts the instructions to a String.
51
+ #
52
+ # @return [String]
53
+ #
54
+ def to_s
55
+ "#{super} #{@namespace}.#{@name}"
56
+ end
57
+
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,34 @@
1
+ require 'python/pickle/instruction'
2
+ require 'python/pickle/instructions/has_namespace_and_name'
3
+
4
+ module Python
5
+ module Pickle
6
+ module Instructions
7
+ #
8
+ # Represents the `INST` instruction.
9
+ #
10
+ # @note introduced in protocol 0.
11
+ #
12
+ # @since 0.2.0
13
+ #
14
+ class Inst < Instruction
15
+
16
+ include HasNamespaceAndName
17
+
18
+ #
19
+ # Initializes a `INST` instruction.
20
+ #
21
+ # @param [String] namespace
22
+ # The namespace name for the constant.
23
+ #
24
+ # @param [String] name
25
+ # The name of the constant.
26
+ #
27
+ def initialize(namespace,name)
28
+ super(:INST,namespace,name)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -6,7 +6,9 @@ module Python
6
6
  #
7
7
  # Represents a pickle `NEXT_BUFFER` instruction.
8
8
  #
9
- # @note introduced in protocol 4.
9
+ # @note introduced in protocol 5.
10
+ #
11
+ # @since 0.2.0
10
12
  #
11
13
  class NextBuffer < Instruction
12
14
 
@@ -20,6 +22,8 @@ module Python
20
22
  end
21
23
 
22
24
  # The `NEXT_BUFFER` instruction.
25
+ #
26
+ # @since 0.2.0
23
27
  NEXT_BUFFER = NextBuffer.new
24
28
  end
25
29
  end
@@ -0,0 +1,30 @@
1
+ require 'python/pickle/instruction'
2
+
3
+ module Python
4
+ module Pickle
5
+ module Instructions
6
+ #
7
+ # Represents a pickle `OBJ` instruction.
8
+ #
9
+ # @note introduced in protocol 0.
10
+ #
11
+ # @since 0.2.0
12
+ #
13
+ class Obj < Instruction
14
+
15
+ #
16
+ # Initializes the `OBJ` instruction.
17
+ #
18
+ def initialize
19
+ super(:OBJ)
20
+ end
21
+
22
+ end
23
+
24
+ # The `OBJ` instruction.
25
+ #
26
+ # @since 0.2.0
27
+ OBJ = Obj.new
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ require 'python/pickle/instruction'
2
+ require 'python/pickle/instructions/has_value'
3
+
4
+ module Python
5
+ module Pickle
6
+ module Instructions
7
+ #
8
+ # Represents the `PERSID` instruction.
9
+ #
10
+ # @note introduced in protocol 0.
11
+ #
12
+ # @since 0.2.0
13
+ #
14
+ class PersID < Instruction
15
+
16
+ include HasValue
17
+
18
+ #
19
+ # Initializes the `PERSID` instruction.
20
+ #
21
+ # @param [String] value
22
+ # The `PERSID` instruction's value.
23
+ #
24
+ def initialize(value)
25
+ super(:PERSID,value)
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -8,6 +8,8 @@ module Python
8
8
  #
9
9
  # @note introduced in protocol 5.
10
10
  #
11
+ # @since 0.2.0
12
+ #
11
13
  class ReadonlyBuffer < Instruction
12
14
 
13
15
  #
@@ -20,6 +22,8 @@ module Python
20
22
  end
21
23
 
22
24
  # The `READONLY_BUFFER` instruction.
25
+ #
26
+ # @since 0.2.0
23
27
  READONLY_BUFFER = ReadonlyBuffer.new
24
28
  end
25
29
  end