Source code for wolframclient.serializers.wxf

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


[docs] def serialize_rule(key, value, sep=(WXF_CONSTANTS.Rule,)): return chain(sep, key, value)
[docs] 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)
[docs] def compress(data): compressor = zlib.compressobj() yield from map(compressor.compress, map(concatenate_bytes, partition(data, 100))) yield compressor.flush()
[docs] class WXFSerializer(FormatSerializer): """Serialize python objects to WXF.""" def __init__(self, normalizer=None, compress=False, **opts): super().__init__(normalizer=normalizer, **opts) self.compress = compress
[docs] 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))
[docs] def serialize_symbol(self, name): yield WXF_CONSTANTS.Symbol yield varint_bytes(len(name)) yield force_bytes(name)
[docs] 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
[docs] 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
[docs] def serialize_float(self, number): yield WXF_CONSTANTS.Real64 yield float_to_bytes(number)
[docs] def serialize_decimal(self, number): number = py_encode_decimal(number) yield WXF_CONSTANTS.BigReal yield varint_bytes(len(number)) yield number
# text / bytes
[docs] def serialize_string(self, string): string = force_bytes(string) yield WXF_CONSTANTS.String yield varint_bytes(len(string)) yield string
[docs] 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"))
[docs] 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)), )
[docs] def serialize_numeric_array(self, data, dimensions, wl_type): return numeric_array_to_wxf(data, dimensions, wl_type)
[docs] def serialize_packed_array(self, data, dimensions, wl_type): return packed_array_to_wxf(data, dimensions, wl_type)