python-pickle 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|