-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_msgpack.txt
166 lines (110 loc) · 3.96 KB
/
test_msgpack.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
Msgpack Marshaller
******************
>>> from cromlech.marshallers import MsgpackMarshaller
>>> marshaller = MsgpackMarshaller()
The `msgpack` marshaller handles binary data :
>>> marshaller.binary
True
Straightforward dump/load
=========================
Respecting the conventions set by the `marshal` and `json` native
packages, we use the `dumps` and `loads` to handle string or bytes.
>>> marshaller.dumps([1, "two", 3])
b'\x93\x01\xa3two\x03'
>>> struct = {
... "Accept-Language": "en-US,en;q=0.8",
... "Host": "headers.jsontest.com",
... "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.3",
... "Accept": "text/html,application/xhtml+xml;q=0.9,*/*;q=0.8"
... }
>>> data = marshaller.dumps(struct)
>>> assert marshaller.loads(data) == struct
Non-basic types
---------------
As for now, the `msgpack` marshaller can convert datetime and date.
>>> from datetime import datetime
>>> mydate = datetime(2017, 12, 25)
>>> mydatetime = datetime(2017, 12, 19, 11, 30, 25)
>>> structure = {
... 'date': mydate,
... 'datetime': mydatetime,
... }
>>> data = marshaller.dumps(structure)
>>> assert marshaller.loads(data) == {
... 'datetime': datetime(2017, 12, 19, 11, 30, 25),
... 'date': datetime(2017, 12, 25, 0, 0)
... }
Decorator
---------
We can use the marshaller as a decorator
>>> @marshaller.wraps
... def my_renderer():
... return [1, 2, "three", 12.145]
>>> my_renderer
<function my_renderer at ...>
>>> my_renderer()
b'\x94\x01\x02\xa5three\xcb@(J=p\xa3\xd7\n'
>>> marshaller.loads(my_renderer())
[1, 2, 'three', 12.145]
Streams and files
=================
Each marshaller has 4 methods devoted to handling file or stream.
`dump` and `load` work with streams. `dump_to` and `load_from` work
with filesystem paths.
Files
-----
>>> import os
>>> path = str(getfixture('tmpdir'))
>>> filepath = os.path.join(path, 'data.msg')
>>> struct = [1, "two", 3.00001]
>>> marshaller.dump_to(struct, filepath)
The `dump_to` method is in charge of writing the data in the file.
We can load the content of this file using the `load_from` method :
>>> marshaller.load_from(filepath)
[1, 'two', 3.00001]
We can check manually the content of the file :
>>> with open(filepath, 'rb') as fd:
... fd.read()
b'\x93\x01\xa3two\xcb@\x08\x00\x05>-b9'
Streams
--------
The `dump` method is in charge writing the data in the stream.
We can interpret the content of this stream using the `load` method.
We use a binary stream since our marshaller handles binary data.
>>> from io import BytesIO
>>> stream = BytesIO()
>>> marshaller.dump(struct, stream)
>>> stream.getvalue()
b'\x93\x01\xa3two\xcb@\x08\x00\x05>-b9'
We now return to the offset 0 of the file and we can load it:
>>> assert stream.seek(0) == 0
>>> marshaller.load(stream)
[1, 'two', 3.00001]
Concurrency and timeout
-----------------------
Concurrency is handled via a file lock. We use the cross-os `portalocker`
package.
For our test, let's simulate a lock in place :
>>> import portalocker
>>> lock = portalocker.Lock(filepath)
>>> assert lock.acquire()
When we try to write to this file, we get an `OSError` raised by our
marshaller in response of the lock timeout :
>>> import pytest
>>> with pytest.raises(IOError) as timeout:
... marshaller.dump_to(struct, filepath, timeout=0)
>>> timeout.value
OSError('Resource is busy and could not be freed.')
Once we release the problematic timeout, we can write :
>>> lock.release()
>>> marshaller.dump_to(struct, filepath, timeout=0)
The same happens with the read :
>>> assert lock.acquire()
>>> with pytest.raises(IOError) as timeout:
... marshaller.load_from(filepath, timeout=0)
>>> timeout.value
OSError('Resource is busy and could not be freed.')
>>> lock.release()
>>> assert marshaller.load_from(filepath, timeout=0) == struct
Please note that the read/write are tied by the same lock. You can't read
and write at the same time.