python-pickle 0.1.0 → 0.1.1
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 +5 -0
- data/README.md +3 -1
- data/lib/python/pickle/version.rb +1 -1
- data/lib/python/pickle.rb +33 -7
- data/spec/deserializer_spec.rb +51 -0
- data/spec/pickle_spec.rb +61 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c18d8d36ae1a85dd7dbdbe13bf136de10bd2d30ddaab523bace2042f1ab3c784
|
4
|
+
data.tar.gz: ad04252dfd4cbcb7e8d80b61e92a1d7439ce256ccfda97b9b3a202e8b3225415
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f64f303012885b2acb6b3ee56527a10a109cac5a9b5f938fea2817552b43bbefad6b5d460f299bb5909388b4eeff722d69b2cba9342e1e8a1c460e3c070a08b
|
7
|
+
data.tar.gz: cc598296cf863810512869805f53b17d2a16bffc9bc09afcb8e35e21fcf1d50b53026151bbd28b687820523618e5dc66a52b42e416281d79ab95a0d6fd636d2a
|
data/ChangeLog.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
### 0.1.0 / 2023-02-18
|
2
2
|
|
3
|
+
* Changed {Python::Pickle.dump} to raise a `NotImplementedError` exception.
|
4
|
+
* Fixed a typo in the method signature of {Python::Pickle.dump}.
|
5
|
+
|
6
|
+
### 0.1.0 / 2023-02-18
|
7
|
+
|
3
8
|
* Initial release:
|
4
9
|
* Supports deserializing Python Pickle data into Ruby objects.
|
5
10
|
* Supports serializing Ruby objects into Python Pickle data.
|
data/README.md
CHANGED
@@ -20,7 +20,9 @@ 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 `
|
23
|
+
* Supports deserializing Python `None`, `True`, `False`, `int`, `str`, `tuple`,
|
24
|
+
`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.
|
26
28
|
|
data/lib/python/pickle.rb
CHANGED
@@ -28,7 +28,7 @@ module Python
|
|
28
28
|
# The default protocol version to use.
|
29
29
|
#
|
30
30
|
# @api public
|
31
|
-
|
31
|
+
DEFAULT_PROTOCOL = 4
|
32
32
|
|
33
33
|
# The highest protocol version supported.
|
34
34
|
#
|
@@ -88,12 +88,22 @@ module Python
|
|
88
88
|
# The explicit protocol version to use. If `nil` the protocol version will
|
89
89
|
# be inferred by inspecting the first two bytes of the stream.
|
90
90
|
#
|
91
|
+
# @param [Hash{Symbol => Object}] kwargs
|
92
|
+
# Additional keyword arguments.
|
93
|
+
#
|
94
|
+
# @option kwargs [Hash{Integer => Object}] :extensions
|
95
|
+
# A Hash of registered extension IDs and their Objects.
|
96
|
+
#
|
97
|
+
# @option kwargs [Hash{String => Hash{String => Class,Method}}] :constants
|
98
|
+
# An optional mapping of custom Python constant names to Ruby classes
|
99
|
+
# or methods.
|
100
|
+
#
|
91
101
|
# @api public
|
92
102
|
#
|
93
|
-
def self.load(data
|
103
|
+
def self.load(data, protocol: nil, **kwargs)
|
94
104
|
deserializer = Deserializer.new(**kwargs)
|
95
105
|
|
96
|
-
parse(data) do |instruction|
|
106
|
+
parse(data, protocol: protocol) do |instruction|
|
97
107
|
status, object = deserializer.execute(instruction)
|
98
108
|
|
99
109
|
if status == :halt
|
@@ -110,11 +120,27 @@ module Python
|
|
110
120
|
# @param [String] path
|
111
121
|
# The path of the file.
|
112
122
|
#
|
123
|
+
# @param [Hash{Symbol => Object}] kwargs
|
124
|
+
# Additional keyword arguments.
|
125
|
+
#
|
126
|
+
# @option kwargs [Hash{Integer => Object}] :extensions
|
127
|
+
# A Hash of registered extension IDs and their Objects.
|
128
|
+
#
|
129
|
+
# @option kwargs [Hash{String => Hash{String => Class,Method}}] :constants
|
130
|
+
# An optional mapping of custom Python constant names to Ruby classes
|
131
|
+
# or methods.
|
132
|
+
#
|
113
133
|
# @return [Object]
|
114
134
|
# The deserialized object.
|
115
135
|
#
|
116
136
|
def self.load_file(path,**kwargs)
|
117
|
-
|
137
|
+
result = nil
|
138
|
+
|
139
|
+
File.open(path,'rb') do |file|
|
140
|
+
result = load(file,**kwargs)
|
141
|
+
end
|
142
|
+
|
143
|
+
return result
|
118
144
|
end
|
119
145
|
|
120
146
|
#
|
@@ -129,12 +155,12 @@ module Python
|
|
129
155
|
# @param [Integer] protocol
|
130
156
|
# The desired Python Pickle protocol to use.
|
131
157
|
#
|
158
|
+
# @note serializing is currently not supported.
|
159
|
+
#
|
132
160
|
# @api public
|
133
161
|
#
|
134
162
|
def self.dump(object,output=nil, protocol: DEFAULT_PROTOCOL)
|
135
|
-
|
136
|
-
raise(ArgumentError,"protocol must be between 0 or #{HIGHEST_PROTOCOL}, but was #{protocol.inspect}")
|
137
|
-
end
|
163
|
+
raise(NotImplementedError,"pickle serializing is currently not supported")
|
138
164
|
end
|
139
165
|
|
140
166
|
#
|
data/spec/deserializer_spec.rb
CHANGED
@@ -2,6 +2,11 @@ require 'spec_helper'
|
|
2
2
|
require 'python/pickle/deserializer'
|
3
3
|
|
4
4
|
describe Python::Pickle::Deserializer do
|
5
|
+
module TestDeserializer
|
6
|
+
class MyClass
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
5
10
|
describe "#initialize" do
|
6
11
|
it "must initialize #meta_stack to an empty Array" do
|
7
12
|
expect(subject.meta_stack).to eq([])
|
@@ -44,9 +49,55 @@ describe Python::Pickle::Deserializer do
|
|
44
49
|
end
|
45
50
|
|
46
51
|
context "when initialized with the `extensions:` keyword argument" do
|
52
|
+
let(:extensions) do
|
53
|
+
{
|
54
|
+
0x41 => Object.new,
|
55
|
+
0x42 => Object.new,
|
56
|
+
0x43 => Object.new
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
subject { described_class.new(extensions: extensions) }
|
61
|
+
|
62
|
+
it "must add the extensions: values to #extensions" do
|
63
|
+
expect(subject.extensions).to eq(extensions)
|
64
|
+
end
|
47
65
|
end
|
48
66
|
|
49
67
|
context "when initialized with the `constants:` keyword argument" do
|
68
|
+
let(:constants) do
|
69
|
+
{
|
70
|
+
'__main__' => {
|
71
|
+
'MyClass' => TestDeserializer::MyClass
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
subject { described_class.new(constants: constants) }
|
77
|
+
|
78
|
+
it "must merge the constants: keyword argument with the default constants" do
|
79
|
+
expect(subject.constants).to eq(
|
80
|
+
{
|
81
|
+
'copy_reg' => {
|
82
|
+
'_reconstructor' => subject.method(:copyreg_reconstructor)
|
83
|
+
},
|
84
|
+
|
85
|
+
'__builtin__' => {
|
86
|
+
'object' => described_class::OBJECT_CLASS,
|
87
|
+
'bytearray' => Python::Pickle::ByteArray
|
88
|
+
},
|
89
|
+
|
90
|
+
'builtins' => {
|
91
|
+
'object' => described_class::OBJECT_CLASS,
|
92
|
+
'bytearray' => Python::Pickle::ByteArray
|
93
|
+
},
|
94
|
+
|
95
|
+
'__main__' => {
|
96
|
+
'MyClass' => TestDeserializer::MyClass
|
97
|
+
}
|
98
|
+
}
|
99
|
+
)
|
100
|
+
end
|
50
101
|
end
|
51
102
|
end
|
52
103
|
|
data/spec/pickle_spec.rb
CHANGED
@@ -52,6 +52,33 @@ describe Python::Pickle do
|
|
52
52
|
it "must deserialize the Python Pickle data in the given file" do
|
53
53
|
expect(subject.load(data)).to eq({"foo" => "bar"})
|
54
54
|
end
|
55
|
+
|
56
|
+
context "when the constants: keyword argument is given" do
|
57
|
+
let(:path) { File.join(fixtures_dir,'object_v4.pkl') }
|
58
|
+
|
59
|
+
module TestLoad
|
60
|
+
class MyClass
|
61
|
+
attr_reader :x, :y
|
62
|
+
|
63
|
+
def __setstate__(attributes)
|
64
|
+
@x = attributes['x']
|
65
|
+
@y = attributes['y']
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:constants) do
|
71
|
+
{
|
72
|
+
'__main__' => {
|
73
|
+
'MyClass' => TestLoad::MyClass
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
it "must map the Python classes to the Ruby classes" do
|
79
|
+
expect(subject.load(data, constants: constants)).to be_kind_of(TestLoad::MyClass)
|
80
|
+
end
|
81
|
+
end
|
55
82
|
end
|
56
83
|
|
57
84
|
describe ".load_file" do
|
@@ -60,9 +87,43 @@ describe Python::Pickle do
|
|
60
87
|
it "must deserialize the Python Pickle data in the given file" do
|
61
88
|
expect(subject.load_file(path)).to eq({"foo" => "bar"})
|
62
89
|
end
|
90
|
+
|
91
|
+
context "when the constants: keyword argument is given" do
|
92
|
+
let(:path) { File.join(fixtures_dir,'object_v4.pkl') }
|
93
|
+
|
94
|
+
module TestLoad
|
95
|
+
class MyClass
|
96
|
+
attr_reader :x, :y
|
97
|
+
|
98
|
+
def __setstate__(attributes)
|
99
|
+
@x = attributes['x']
|
100
|
+
@y = attributes['y']
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
let(:constants) do
|
106
|
+
{
|
107
|
+
'__main__' => {
|
108
|
+
'MyClass' => TestLoad::MyClass
|
109
|
+
}
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
it "must map the Python classes to the Ruby classes" do
|
114
|
+
expect(subject.load_file(path, constants: constants)).to be_kind_of(TestLoad::MyClass)
|
115
|
+
end
|
116
|
+
end
|
63
117
|
end
|
64
118
|
|
65
119
|
describe ".dump" do
|
120
|
+
let(:object) { Object.new }
|
121
|
+
|
122
|
+
it do
|
123
|
+
expect {
|
124
|
+
subject.dump(object)
|
125
|
+
}.to raise_error(NotImplementedError,"pickle serializing is currently not supported")
|
126
|
+
end
|
66
127
|
end
|
67
128
|
|
68
129
|
describe ".infer_protocol_version" do
|