Пример #1
0
 def parse_array(self, token):
     # Parsing array rank and dimensions
     rank = parse_varint(self.reader)
     if rank == 0:
         raise WolframParserException("Array rank cannot be zero.")
     token.dimensions = []
     for i in range(rank):
         dim = parse_varint(self.reader)
         if dim == 0:
             raise WolframParserException("Array dimensions cannot be zero.")
         token.dimensions.append(dim)
     # reading values
     bytecount = constants.ARRAY_TYPES_ELEM_SIZE[token.array_type] * token.element_count
     token.data = self.reader.read(bytecount)
Пример #2
0
 def parse_header(self):
     compress = False
     next_byte = self.reader.read(1)
     if next_byte == WXF_VERSION:
         version = int(next_byte)
         next_byte = self.reader.read(1)
     else:
         raise WolframParserException("Invalid version %s." % next_byte)
     if next_byte == WXF_HEADER_COMPRESS:
         compress = True
         next_byte = self.reader.read(1)
     if next_byte != WXF_HEADER_SEPARATOR:
         raise WolframParserException(
             "Invalid header. Failed to find header separator ':'.")
     return (version, compress)
Пример #3
0
 def consume_bigint(self, current_token, tokens, **kwargs):
     """Consume a :class:`~wolframclient.deserializers.wxf.wxfparser.WXFToken` of type *big integer* as a :class:`int`."""
     try:
         return int(current_token.data)
     except ValueError:
         raise WolframParserException("Invalid big integer value: %s" %
                                      current_token.data)
Пример #4
0
def parse_varint(reader):
    """Parse a readable binary buffer for a positive varint encoded integer."""
    count = 0
    continuation = True
    shift = 0
    length = 0
    # when we read from stream we get a sequence of bytes. Its length is 1
    # except if we reached EOF in which case taking index 0 raises IndexError.
    try:
        while continuation and count < 8:
            count += 1
            next_byte = reader.read(1)
            next_byte = ord(next_byte)
            length |= (next_byte & 0x7F) << shift
            shift = shift + 7
            continuation = (next_byte & 0x80) != 0

        if continuation:
            next_byte = reader.read(1)
            next_byte = ord(next_byte)
            next_byte &= 0x7F
            if next_byte == 0:
                raise WolframParserException("Invalid last varint byte.")
            length |= next_byte << shift

        return length
    except IndexError:
        raise EOFError("EOF reached while parsing varint encoded integer.")
Пример #5
0
 def token_for_rule(self, token):
     if not self.context.is_rule_valid():
         raise WolframParserException(
             "Rule and RuleDelayed must be parts of an Association."
         )
     self.context.step_into_new_rule()
     return token
Пример #6
0
 def _consumer_from_type(self, wxf_type):
     try:
         func = self._mapping[wxf_type]
     except KeyError:
         raise WolframParserException(
             "Class %s does not implement any consumer method for WXF token %s"
             % (self.__class__.__name__, wxf_type))
     return getattr(self, func)
Пример #7
0
 def token_for_numeric_array(self, token):
     self.context.add_part()
     token.array_type = self.reader.read(1)
     if token.array_type not in constants.ARRAY_TYPES_ELEM_SIZE:
         raise WolframParserException(
             "Invalid NumericArray value type: %s" % token.array_type)
     self.parse_array(token)
     return token
Пример #8
0
 def token_for_packed_array(self, token):
     self.context.add_part()
     token.array_type = self.reader.read(1)
     if token.array_type not in constants.VALID_PACKED_ARRAY_TYPES:
         raise WolframParserException("Invalid PackedArray value type: %s" %
                                      token.array_type)
     self.parse_array(token)
     return token
Пример #9
0
    def next_token(self):
        next_byte = self.reader.read(1)

        try:
            handler = self._mapping[next_byte]
        except KeyError:
            raise WolframParserException("Unexpected token %s" % next_byte)

        return getattr(self, handler)(WXFToken(next_byte))
Пример #10
0
def binary_deserialize(wxf_input, consumer=None, **kwargs):
    """Deserialize binary data and return a Python object.

    Serialize a Python object to WXF::

        >>> wxf = export({'key' : [1,2,3]}, target_format='wxf')

    Retrieve the input object::

        >>> binary_deserialize(wxf)
        {'key': [1, 2, 3]}

    A stream of :class:`~wolframclient.deserializers.wxf.wxfparser.WXFToken` is generated from the WXF input by a instance
    of :class:`~wolframclient.deserializers.wxf.wxfparser.WXFParser`.

    The consumer must be an instance of :class:`~wolframclient.deserializers.wxf.wxfconsumer.WXFConsumer`. If none is
    provided, :class:`~wolframclient.deserializers.wxf.wxfconsumer.WXFConsumer` is used. To enable NumPy array support,
    use :class:`~wolframclient.deserializers.wxf.wxfconsumer.WXFConsumerNumpy`.

    Named parameters are passed to the consumer. They can be any valid parameter of
    :meth:`~wolframclient.deserializers.wxf.wxfconsumer.WXFConsumer.next_expression`, namely:

    * `dict_class`: map WXF `Association` to `dict_class` in place of a regular :class:`dict`

    """
    parser = WXFParser(wxf_input)
    if consumer is None:
        consumer = WXFConsumer()

    try:
        o = consumer.next_expression(parser.tokens(), **kwargs)
    except StopIteration:
        raise WolframParserException(
            'Input data does not represent a valid expression in WXF format. Expecting more input data.'
        )
    if not parser.context.is_valid_final_state():
        raise WolframParserException(
            'Input data does not represent a valid expression in WXF format. Some expressions are incomplete.'
        )
    return o
Пример #11
0
    def consume_bigreal(self, current_token, tokens, **kwargs):
        """Parse a WXF big real as a WXF serializable big real.

        There is not such thing as a big real, in Wolfram Language notation, in Python. This
        wrapper ensures round tripping of big reals without the need of `ToExpression`.
        Introducing `ToExpression` would imply to marshall the big real data to avoid malicious
        code from being introduced in place of an actual real.
        """

        match = self.BIGREAL_RE.match(current_token.data)

        if match:

            num, _, _, exp = match.groups()

            if exp:
                return decimal.Decimal("%se%s" % (num, exp))

            return decimal.Decimal(num)

        raise WolframParserException("Invalid big real value: %s" % current_token.data)