-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathwxf.py
140 lines (100 loc) · 4.07 KB
/
wxf.py
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
from __future__ import absolute_import, print_function, unicode_literals
from itertools import chain, starmap
from wolframclient.serializers.base import FormatSerializer
from wolframclient.serializers.utils import py_encode_decimal, safe_len
from wolframclient.serializers.wxfencoder.constants import (
WXF_CONSTANTS,
WXF_HEADER_COMPRESS,
WXF_HEADER_SEPARATOR,
WXF_VERSION,
)
from wolframclient.serializers.wxfencoder.utils import (
float_to_bytes,
integer_size,
integer_to_bytes,
numeric_array_to_wxf,
packed_array_to_wxf,
varint_bytes,
)
from wolframclient.utils import six
from wolframclient.utils.api import zlib
from wolframclient.utils.encoding import concatenate_bytes, force_bytes, force_text
from wolframclient.utils.functional import partition
def serialize_rule(key, value, sep=(WXF_CONSTANTS.Rule,)):
return chain(sep, key, value)
def get_length(iterable, length=None):
if length is not None:
return iterable, length
length = safe_len(iterable)
if length is not None:
return iterable, length
iterable = tuple(iterable)
return iterable, len(iterable)
def compress(data):
compressor = zlib.compressobj()
yield from map(compressor.compress, map(concatenate_bytes, partition(data, 100)))
yield compressor.flush()
class WXFSerializer(FormatSerializer):
"""Serialize python objects to WXF."""
def __init__(self, normalizer=None, compress=False, **opts):
super().__init__(normalizer=normalizer, **opts)
self.compress = compress
def generate_bytes(self, data):
if self.compress:
return chain(
(WXF_VERSION, WXF_HEADER_COMPRESS, WXF_HEADER_SEPARATOR),
compress(self.encode(data)),
)
return chain((WXF_VERSION, WXF_HEADER_SEPARATOR), self.encode(data))
def serialize_symbol(self, name):
yield WXF_CONSTANTS.Symbol
yield varint_bytes(len(name))
yield force_bytes(name)
def serialize_function(self, head, args, **opts):
iterable, length = get_length(args, **opts)
return chain(
(WXF_CONSTANTS.Function, varint_bytes(length)), head, chain.from_iterable(iterable)
)
# numeric
def serialize_int(self, number):
try:
wxf_type, int_size = integer_size(number)
yield wxf_type
yield integer_to_bytes(number, int_size)
except ValueError:
# WXFExprInteger is raising a ValueError if the integer is not in the appropriate bounds.
# that check needs to be done in case, it's better to do it only once.
number = b"%i" % number
yield WXF_CONSTANTS.BigInteger
yield varint_bytes(len(number))
yield number
def serialize_float(self, number):
yield WXF_CONSTANTS.Real64
yield float_to_bytes(number)
def serialize_decimal(self, number):
number = py_encode_decimal(number)
yield WXF_CONSTANTS.BigReal
yield varint_bytes(len(number))
yield number
# text / bytes
def serialize_string(self, string):
string = force_bytes(string)
yield WXF_CONSTANTS.String
yield varint_bytes(len(string))
yield string
def serialize_bytes(self, bytes, as_byte_array=not six.PY2):
if as_byte_array:
return (WXF_CONSTANTS.BinaryString, varint_bytes(len(bytes)), bytes)
else:
return self.serialize_string(force_text(bytes, encoding="iso8859-1"))
def serialize_mapping(self, keyvalue, **opts):
# the normalizer is always sending an generator key, value
iterable, length = get_length(keyvalue, **opts)
return chain(
(WXF_CONSTANTS.Association, varint_bytes(length)),
chain.from_iterable(starmap(serialize_rule, iterable)),
)
def serialize_numeric_array(self, data, dimensions, wl_type):
return numeric_array_to_wxf(data, dimensions, wl_type)
def serialize_packed_array(self, data, dimensions, wl_type):
return packed_array_to_wxf(data, dimensions, wl_type)