| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| |
| from __future__ import absolute_import |
| |
| import uuid |
| |
| from cproton import PN_ARRAY, PN_BINARY, PN_BOOL, PN_BYTE, PN_CHAR, PN_DECIMAL128, PN_DECIMAL32, PN_DECIMAL64, \ |
| PN_DESCRIBED, PN_DOUBLE, PN_FLOAT, PN_INT, PN_LIST, PN_LONG, PN_MAP, PN_NULL, PN_OVERFLOW, PN_SHORT, PN_STRING, \ |
| PN_SYMBOL, PN_TIMESTAMP, PN_UBYTE, PN_UINT, PN_ULONG, PN_USHORT, PN_UUID, pn_data, pn_data_clear, pn_data_copy, \ |
| pn_data_decode, pn_data_dump, pn_data_encode, pn_data_encoded_size, pn_data_enter, pn_data_error, pn_data_exit, \ |
| pn_data_format, pn_data_free, pn_data_get_array, pn_data_get_array_type, pn_data_get_binary, pn_data_get_bool, \ |
| pn_data_get_byte, pn_data_get_char, pn_data_get_decimal128, pn_data_get_decimal32, pn_data_get_decimal64, \ |
| pn_data_get_double, pn_data_get_float, pn_data_get_int, pn_data_get_list, pn_data_get_long, pn_data_get_map, \ |
| pn_data_get_short, pn_data_get_string, pn_data_get_symbol, pn_data_get_timestamp, pn_data_get_ubyte, \ |
| pn_data_get_uint, pn_data_get_ulong, pn_data_get_ushort, pn_data_get_uuid, pn_data_is_array_described, \ |
| pn_data_is_described, pn_data_is_null, pn_data_lookup, pn_data_narrow, pn_data_next, pn_data_prev, \ |
| pn_data_put_array, pn_data_put_binary, pn_data_put_bool, pn_data_put_byte, pn_data_put_char, pn_data_put_decimal128, \ |
| pn_data_put_decimal32, pn_data_put_decimal64, pn_data_put_described, pn_data_put_double, pn_data_put_float, \ |
| pn_data_put_int, pn_data_put_list, pn_data_put_long, pn_data_put_map, pn_data_put_null, pn_data_put_short, \ |
| pn_data_put_string, pn_data_put_symbol, pn_data_put_timestamp, pn_data_put_ubyte, pn_data_put_uint, \ |
| pn_data_put_ulong, pn_data_put_ushort, pn_data_put_uuid, pn_data_rewind, pn_data_type, pn_data_widen, pn_error_text |
| |
| from . import _compat |
| from ._common import Constant |
| from ._exceptions import DataException, EXCEPTIONS |
| |
| # |
| # Hacks to provide Python2 <---> Python3 compatibility |
| # |
| # The results are |
| # | |long|unicode| |
| # |Python2|long|unicode| |
| # |Python3| int| str| |
| try: |
| long() |
| except NameError: |
| long = int |
| try: |
| unicode() |
| except NameError: |
| unicode = str |
| |
| |
| class UnmappedType: |
| |
| def __init__(self, msg): |
| self.msg = msg |
| |
| def __repr__(self): |
| return "UnmappedType(%s)" % self.msg |
| |
| |
| class ulong(long): |
| """ |
| The ulong AMQP type. |
| |
| An unsigned 64 bit integer in the range :math:`0` to :math:`2^{64} - 1` inclusive. |
| """ |
| |
| def __init__(self, l): |
| if (l < 0): |
| raise AssertionError("initializing ulong with negative value") |
| super(ulong, self).__new__(ulong, l) |
| |
| def __repr__(self): |
| return "ulong(%s)" % long.__repr__(self) |
| |
| |
| class timestamp(long): |
| """ |
| The timestamp AMQP type. |
| |
| An absolute point in time, represented by a signed 64 bit value measuring |
| milliseconds since the epoch. This value is encoded using the Unix ``time_t`` |
| [IEEE1003] encoding of UTC, but with a precision of milliseconds. For |
| example, ``1311704463521`` represents the moment ``2011-07-26T18:21:03.521Z``. |
| """ |
| |
| def __repr__(self): |
| return "timestamp(%s)" % long.__repr__(self) |
| |
| |
| class symbol(unicode): |
| """ |
| The symbol AMQP type. |
| |
| Symbolic values from a constrained domain, represented by a sequence of ASCII characters. |
| """ |
| |
| def __repr__(self): |
| return "symbol(%s)" % unicode.__repr__(self) |
| |
| |
| class char(unicode): |
| """ |
| The char AMQP type. |
| |
| A 32 bit UTF-32BE encoded Unicode character. |
| """ |
| |
| def __repr__(self): |
| return "char(%s)" % unicode.__repr__(self) |
| |
| |
| class byte(int): |
| """ |
| The byte AMQP type. |
| |
| An 8 bit signed integer in the range :math:`-(2^7)` to :math:`2^7 - 1` inclusive. |
| """ |
| |
| def __repr__(self): |
| return "byte(%s)" % int.__repr__(self) |
| |
| |
| class short(int): |
| """ |
| The short AMQP type. |
| |
| A 16 bit signed integer in the range :math:`-(2^{15})` to :math:`2^{15} - 1` inclusive. |
| """ |
| |
| def __repr__(self): |
| return "short(%s)" % int.__repr__(self) |
| |
| |
| class int32(int): |
| """ |
| The signed int AMQP type. |
| |
| A 32 bit signed integer in the range :math:`-(2^{31})` to :math:`2^{31} - 1` inclusive. |
| """ |
| |
| def __repr__(self): |
| return "int32(%s)" % int.__repr__(self) |
| |
| |
| class ubyte(int): |
| """ |
| The unsigned byte AMQP type. |
| |
| An 8 bit unsigned integer in the range :math:`0` to :math:`2^8 - 1` inclusive. |
| """ |
| |
| def __init__(self, i): |
| if (i < 0): |
| raise AssertionError("initializing ubyte with negative value") |
| super(ubyte, self).__new__(ubyte, i) |
| |
| def __repr__(self): |
| return "ubyte(%s)" % int.__repr__(self) |
| |
| |
| class ushort(int): |
| """ |
| The unsigned short AMQP type. |
| |
| A 16 bit unsigned integer in the range :math:`0` to :math:`2^{16} - 1` inclusive. |
| """ |
| |
| def __init__(self, i): |
| if (i < 0): |
| raise AssertionError("initializing ushort with negative value") |
| super(ushort, self).__new__(ushort, i) |
| |
| def __repr__(self): |
| return "ushort(%s)" % int.__repr__(self) |
| |
| |
| class uint(long): |
| """ |
| The unsigned int AMQP type. |
| |
| A 32 bit unsigned integer in the range :math:`0` to :math:`2^{32} - 1` inclusive. |
| """ |
| |
| def __init__(self, l): |
| if (l < 0): |
| raise AssertionError("initializing uint with negative value") |
| super(uint, self).__new__(uint, l) |
| |
| def __repr__(self): |
| return "uint(%s)" % long.__repr__(self) |
| |
| |
| class float32(float): |
| """ |
| The float AMQP type. |
| |
| A 32 bit floating point number (IEEE 754-2008 binary32). |
| """ |
| |
| def __repr__(self): |
| return "float32(%s)" % float.__repr__(self) |
| |
| |
| class decimal32(int): |
| """ |
| The decimal32 AMQP type. |
| |
| A 32 bit decimal floating point number (IEEE 754-2008 decimal32). |
| """ |
| |
| def __repr__(self): |
| return "decimal32(%s)" % int.__repr__(self) |
| |
| |
| class decimal64(long): |
| """ |
| The decimal64 AMQP type. |
| |
| A 64 bit decimal floating point number (IEEE 754-2008 decimal64). |
| """ |
| |
| def __repr__(self): |
| return "decimal64(%s)" % long.__repr__(self) |
| |
| |
| class decimal128(bytes): |
| """ |
| The decimal128 AMQP type. |
| |
| A 128-bit decimal floating-point number (IEEE 754-2008 decimal128). |
| """ |
| |
| def __repr__(self): |
| return "decimal128(%s)" % bytes.__repr__(self) |
| |
| |
| class Described(object): |
| """ |
| A described AMQP type. |
| |
| :ivar descriptor: A symbol describing the value. |
| :vartype descriptor: :class:`symbol` |
| :ivar value: The described value |
| :vartype value: Any AMQP value |
| """ |
| |
| def __init__(self, descriptor, value): |
| self.descriptor = descriptor |
| self.value = value |
| |
| def __repr__(self): |
| return "Described(%r, %r)" % (self.descriptor, self.value) |
| |
| def __eq__(self, o): |
| if isinstance(o, Described): |
| return self.descriptor == o.descriptor and self.value == o.value |
| else: |
| return False |
| |
| |
| UNDESCRIBED = Constant("UNDESCRIBED") |
| |
| |
| class Array(object): |
| """ |
| An AMQP array, a sequence of AMQP values of a single type. |
| |
| This class provides a convenient way to handle AMQP arrays when used with |
| convenience methods :func:`Data.get_py_array` and :func:`Data.put_py_array`. |
| |
| :ivar descriptor: Optional descriptor if the array is to be described, otherwise ``None`` |
| :ivar type: Array element type, as an integer. The :class:`Data` class has constants defined |
| for all the valid AMQP types. For example, for an array of double values, use |
| :const:`Data.DOUBLE`, which has integer value 14. |
| :ivar elements: A Python list of elements of the appropriate type. |
| """ |
| |
| def __init__(self, descriptor, type, *elements): |
| self.descriptor = descriptor |
| self.type = type |
| self.elements = elements |
| |
| def __iter__(self): |
| return iter(self.elements) |
| |
| def __repr__(self): |
| if self.elements: |
| els = ", %s" % (", ".join(map(repr, self.elements))) |
| else: |
| els = "" |
| return "Array(%r, %r%s)" % (self.descriptor, self.type, els) |
| |
| def __eq__(self, o): |
| if isinstance(o, Array): |
| return self.descriptor == o.descriptor and \ |
| self.type == o.type and self.elements == o.elements |
| else: |
| return False |
| |
| |
| def _check_type(s, allow_ulong=False, raise_on_error=True): |
| if isinstance(s, symbol): |
| return s |
| if allow_ulong and isinstance(s, ulong): |
| return s |
| if isinstance(s, str): |
| # Must be py2 or py3 str |
| return symbol(s) |
| if isinstance(s, unicode): |
| # This must be python2 unicode as we already detected py3 str above |
| return symbol(s.encode('utf-8')) |
| if raise_on_error: |
| raise TypeError('Non-symbol type %s: %s' % (type(s), s)) |
| return s |
| |
| |
| def _check_is_symbol(s, raise_on_error=True): |
| return _check_type(s, allow_ulong=False, raise_on_error=raise_on_error) |
| |
| |
| def _check_is_symbol_or_ulong(s, raise_on_error=True): |
| return _check_type(s, allow_ulong=True, raise_on_error=raise_on_error) |
| |
| |
| class RestrictedKeyDict(dict): |
| """Parent class for :class:`PropertyDict` and :class:`AnnotationDict`""" |
| def __init__(self, validation_fn, e=None, raise_on_error=True, **kwargs): |
| super(RestrictedKeyDict, self).__init__() |
| self.validation_fn = validation_fn |
| self.raise_on_error = raise_on_error |
| self.update(e, **kwargs) |
| |
| def __setitem__(self, key, value): |
| """Checks if the key is a :class:`symbol` type before setting the value""" |
| try: |
| return super(RestrictedKeyDict, self).__setitem__(self.validation_fn(key, self.raise_on_error), value) |
| except TypeError: |
| pass |
| # __setitem__() must raise a KeyError, not TypeError |
| raise KeyError('invalid non-symbol key: %s: %s' % (type(key), key)) |
| |
| def update(self, e=None, **kwargs): |
| """ |
| Equivalent to dict.update(), but it was needed to call :meth:`__setitem__()` |
| instead of ``dict.__setitem__()``. |
| """ |
| if e: |
| try: |
| for k in e: |
| self.__setitem__(k, e[k]) |
| except TypeError: |
| self.__setitem__(k[0], k[1]) # use tuple consumed from from zip |
| for (k, v) in e: |
| self.__setitem__(k, v) |
| for k in kwargs: |
| self.__setitem__(k, kwargs[k]) |
| |
| |
| class PropertyDict(RestrictedKeyDict): |
| """ |
| A dictionary that only takes :class:`symbol` types as a key. |
| However, if a string key is provided, it will be silently converted |
| into a symbol key. |
| |
| >>> from proton import symbol, ulong, PropertyDict |
| >>> a = PropertyDict(one=1, two=2) |
| >>> b = PropertyDict({'one':1, symbol('two'):2}) |
| >>> c = PropertyDict(zip(['one', symbol('two')], [1, 2])) |
| >>> d = PropertyDict([(symbol('one'), 1), ('two', 2)]) |
| >>> e = PropertyDict(a) |
| >>> a == b == c == d == e |
| True |
| |
| By default, non-string and non-symbol keys cause a ``KeyError`` to be raised: |
| |
| >>> PropertyDict({'one':1, 2:'two'}) |
| ... |
| KeyError: "invalid non-symbol key: <type 'int'>: 2" |
| |
| but by setting ``raise_on_error=False``, non-string and non-symbol keys will be ignored: |
| |
| >>> PropertyDict({'one':1, 2:'two'}, raise_on_error=False) |
| PropertyDict({2: 'two', symbol(u'one'): 1}) |
| |
| :param e: Initialization for ``dict`` |
| :type e: ``dict`` or ``list`` of ``tuple`` or ``zip`` object |
| :param raise_on_error: If ``True``, will raise an ``KeyError`` if a non-string or non-symbol |
| is encountered as a key in the initialization, or in a subsequent operation which |
| adds such an key. If ``False``, non-strings and non-symbols will be added as keys |
| to the dictionary without an error. |
| :type raise_on_error: ``bool`` |
| :param kwargs: Keyword args for initializing a ``dict`` of the form key1=val1, key2=val2, ... |
| """ |
| def __init__(self, e=None, raise_on_error=True, **kwargs): |
| super(PropertyDict, self).__init__(_check_is_symbol, e, raise_on_error, **kwargs) |
| |
| def __repr__(self): |
| """ Representation of PropertyDict """ |
| return 'PropertyDict(%s)' % super(PropertyDict, self).__repr__() |
| |
| |
| class AnnotationDict(RestrictedKeyDict): |
| """ |
| A dictionary that only takes :class:`symbol` or :class:`ulong` types |
| as a key. However, if a string key is provided, it will be silently |
| converted into a symbol key. |
| |
| >>> from proton import symbol, ulong, AnnotationDict |
| >>> a = AnnotationDict(one=1, two=2) |
| >>> a[ulong(3)] = 'three' |
| >>> b = AnnotationDict({'one':1, symbol('two'):2, ulong(3):'three'}) |
| >>> c = AnnotationDict(zip([symbol('one'), 'two', ulong(3)], [1, 2, 'three'])) |
| >>> d = AnnotationDict([('one', 1), (symbol('two'), 2), (ulong(3), 'three')]) |
| >>> e = AnnotationDict(a) |
| >>> a == b == c == d == e |
| True |
| |
| By default, non-string, non-symbol and non-ulong keys cause a ``KeyError`` to be raised: |
| |
| >>> AnnotationDict({'one': 1, 2: 'two'}) |
| ... |
| KeyError: "invalid non-symbol key: <type 'int'>: 2" |
| |
| but by setting ``raise_on_error=False``, non-string, non-symbol and non-ulong keys will be ignored: |
| |
| >>> AnnotationDict({'one': 1, 2: 'two'}, raise_on_error=False) |
| AnnotationDict({2: 'two', symbol(u'one'): 1}) |
| |
| :param e: Initialization for ``dict`` |
| :type e: ``dict`` or ``list`` of ``tuple`` or ``zip`` object |
| :param raise_on_error: If ``True``, will raise an ``KeyError`` if a non-string, non-symbol or |
| non-ulong is encountered as a key in the initialization, or in a subsequent |
| operation which adds such an key. If ``False``, non-strings, non-ulongs and non-symbols |
| will be added as keys to the dictionary without an error. |
| :type raise_on_error: ``bool`` |
| :param kwargs: Keyword args for initializing a ``dict`` of the form key1=val1, key2=val2, ... |
| """ |
| def __init__(self, e=None, raise_on_error=True, **kwargs): |
| super(AnnotationDict, self).__init__(_check_is_symbol_or_ulong, e, raise_on_error, **kwargs) |
| |
| def __repr__(self): |
| """ Representation of AnnotationDict """ |
| return 'AnnotationDict(%s)' % super(AnnotationDict, self).__repr__() |
| |
| |
| class SymbolList(list): |
| """ |
| A list that can only hold :class:`symbol` elements. However, if any string elements |
| are present, they will be converted to symbols. |
| |
| >>> a = SymbolList(['one', symbol('two'), 'three']) |
| >>> b = SymbolList([symbol('one'), 'two', symbol('three')]) |
| >>> c = SymbolList(a) |
| >>> a == b == c |
| True |
| |
| By default, using any key other than a symbol or string will result in a ``TypeError``: |
| |
| >>> SymbolList(['one', symbol('two'), 3]) |
| ... |
| TypeError: Non-symbol type <class 'int'>: 3 |
| |
| but by setting ``raise_on_error=False``, non-symbol and non-string keys will be ignored: |
| |
| >>> SymbolList(['one', symbol('two'), 3], raise_on_error=False) |
| SymbolList([symbol(u'one'), symbol(u'two'), 3]) |
| |
| :param t: Initialization for list |
| :type t: ``list`` |
| :param raise_on_error: If ``True``, will raise an ``TypeError`` if a non-string or non-symbol is |
| encountered in the initialization list, or in a subsequent operation which adds such |
| an element. If ``False``, non-strings and non-symbols will be added to the list without |
| an error. |
| :type raise_on_error: ``bool`` |
| """ |
| def __init__(self, t=None, raise_on_error=True): |
| super(SymbolList, self).__init__() |
| self.raise_on_error = raise_on_error |
| if t: |
| self.extend(t) |
| |
| def _check_list(self, t): |
| """ Check all items in list are :class:`symbol`s (or are converted to symbols). """ |
| l = [] |
| if t: |
| for v in t: |
| l.append(_check_is_symbol(v, self.raise_on_error)) |
| return l |
| |
| def append(self, v): |
| """ Add a single value v to the end of the list """ |
| return super(SymbolList, self).append(_check_is_symbol(v, self.raise_on_error)) |
| |
| def extend(self, t): |
| """ Add all elements of an iterable t to the end of the list """ |
| return super(SymbolList, self).extend(self._check_list(t)) |
| |
| def insert(self, i, v): |
| """ Insert a value v at index i """ |
| return super(SymbolList, self).insert(i, _check_is_symbol(v, self.raise_on_error)) |
| |
| def __add__(self, t): |
| """ Handles list1 + list2 """ |
| return SymbolList(super(SymbolList, self).__add__(self._check_list(t)), raise_on_error=self.raise_on_error) |
| |
| def __iadd__(self, t): |
| """ Handles list1 += list2 """ |
| return super(SymbolList, self).__iadd__(self._check_list(t)) |
| |
| def __setitem__(self, i, t): |
| """ Handles list[i] = v """ |
| return super(SymbolList, self).__setitem__(i, _check_is_symbol(t, self.raise_on_error)) |
| |
| def __repr__(self): |
| """ Representation of SymbolList """ |
| return 'SymbolList(%s)' % super(SymbolList, self).__repr__() |
| |
| |
| class Data: |
| """ |
| The :class:`Data` class provides an interface for decoding, extracting, |
| creating, and encoding arbitrary AMQP data. A :class:`Data` object |
| contains a tree of AMQP values. Leaf nodes in this tree correspond |
| to scalars in the AMQP type system such as :const:`ints <INT>` or |
| :const:`strings <STRING>`. Non-leaf nodes in this tree correspond to |
| compound values in the AMQP type system such as :const:`lists <LIST>`, |
| :const:`maps <MAP>`, :const:`arrays <ARRAY>`, or :const:`described values <DESCRIBED>`. |
| The root node of the tree is the :class:`Data` object itself and can have |
| an arbitrary number of children. |
| |
| A :class:`Data` object maintains the notion of the current sibling node |
| and a current parent node. Siblings are ordered within their parent. |
| Values are accessed and/or added by using the :meth:`next`, :meth:`prev`, |
| :meth:`enter`, and :meth:`exit` methods to navigate to the desired location in |
| the tree and using the supplied variety of ``put_*`` / ``get_*`` methods to |
| access or add a value of the desired type. |
| |
| The ``put_*`` methods will always add a value *after* the current node |
| in the tree. If the current node has a next sibling the ``put_*`` method |
| will overwrite the value on this node. If there is no current node |
| or the current node has no next sibling then one will be added. The |
| ``put_*`` methods always set the added/modified node to the current |
| node. The ``get_*`` methods read the value of the current node and do |
| not change which node is current. |
| |
| The following types of scalar values are supported: |
| |
| * :const:`NULL` |
| * :const:`BOOL` |
| * :const:`UBYTE` |
| * :const:`USHORT` |
| * :const:`SHORT` |
| * :const:`UINT` |
| * :const:`INT` |
| * :const:`ULONG` |
| * :const:`LONG` |
| * :const:`FLOAT` |
| * :const:`DOUBLE` |
| * :const:`BINARY` |
| * :const:`STRING` |
| * :const:`SYMBOL` |
| |
| The following types of compound values are supported: |
| |
| * :const:`DESCRIBED` |
| * :const:`ARRAY` |
| * :const:`LIST` |
| * :const:`MAP` |
| """ |
| |
| NULL = PN_NULL; "A null value." |
| BOOL = PN_BOOL; "A boolean value." |
| UBYTE = PN_UBYTE; "An unsigned byte value." |
| BYTE = PN_BYTE; "A signed byte value." |
| USHORT = PN_USHORT; "An unsigned short value." |
| SHORT = PN_SHORT; "A short value." |
| UINT = PN_UINT; "An unsigned int value." |
| INT = PN_INT; "A signed int value." |
| CHAR = PN_CHAR; "A character value." |
| ULONG = PN_ULONG; "An unsigned long value." |
| LONG = PN_LONG; "A signed long value." |
| TIMESTAMP = PN_TIMESTAMP; "A timestamp value." |
| FLOAT = PN_FLOAT; "A float value." |
| DOUBLE = PN_DOUBLE; "A double value." |
| DECIMAL32 = PN_DECIMAL32; "A DECIMAL32 value." |
| DECIMAL64 = PN_DECIMAL64; "A DECIMAL64 value." |
| DECIMAL128 = PN_DECIMAL128; "A DECIMAL128 value." |
| UUID = PN_UUID; "A UUID value." |
| BINARY = PN_BINARY; "A binary string." |
| STRING = PN_STRING; "A unicode string." |
| SYMBOL = PN_SYMBOL; "A symbolic string." |
| DESCRIBED = PN_DESCRIBED; "A described value." |
| ARRAY = PN_ARRAY; "An array value." |
| LIST = PN_LIST; "A list value." |
| MAP = PN_MAP; "A map value." |
| |
| type_names = { |
| NULL: "null", |
| BOOL: "bool", |
| BYTE: "byte", |
| UBYTE: "ubyte", |
| SHORT: "short", |
| USHORT: "ushort", |
| INT: "int", |
| UINT: "uint", |
| CHAR: "char", |
| LONG: "long", |
| ULONG: "ulong", |
| TIMESTAMP: "timestamp", |
| FLOAT: "float", |
| DOUBLE: "double", |
| DECIMAL32: "decimal32", |
| DECIMAL64: "decimal64", |
| DECIMAL128: "decimal128", |
| UUID: "uuid", |
| BINARY: "binary", |
| STRING: "string", |
| SYMBOL: "symbol", |
| DESCRIBED: "described", |
| ARRAY: "array", |
| LIST: "list", |
| MAP: "map" |
| } |
| """ |
| A map which uses the enumerated type as a key to get a text name for the type. |
| """ |
| |
| @classmethod |
| def type_name(amqptype): |
| """ |
| Return a string name for an AMQP type. |
| |
| :param type: Numeric Proton AMQP type (`enum pn_type_t`) |
| :type type: integer |
| :rtype: String describing the AMQP type with numeric value `amqptype` |
| """ |
| return Data.type_names[amqptype] |
| |
| def __init__(self, capacity=16): |
| if isinstance(capacity, (int, long)): |
| self._data = pn_data(capacity) |
| self._free = True |
| else: |
| self._data = capacity |
| self._free = False |
| |
| def __del__(self): |
| if self._free and hasattr(self, "_data"): |
| pn_data_free(self._data) |
| del self._data |
| |
| def _check(self, err): |
| if err < 0: |
| exc = EXCEPTIONS.get(err, DataException) |
| raise exc("[%s]: %s" % (err, pn_error_text(pn_data_error(self._data)))) |
| else: |
| return err |
| |
| def clear(self): |
| """ |
| Clears the data object. |
| """ |
| pn_data_clear(self._data) |
| |
| def rewind(self): |
| """ |
| Clears current node and sets the parent to the root node. Clearing the |
| current node sets it _before_ the first node, calling next() will advance to |
| the first node. |
| """ |
| assert self._data is not None |
| pn_data_rewind(self._data) |
| |
| def next(self): |
| """ |
| Advances the current node to its next sibling and returns its |
| type. If there is no next sibling the current node remains |
| unchanged and ``None`` is returned. |
| |
| :return: Node type or ``None`` |
| :rtype: ``int`` or ``None`` |
| """ |
| found = pn_data_next(self._data) |
| if found: |
| return self.type() |
| else: |
| return None |
| |
| def prev(self): |
| """ |
| Advances the current node to its previous sibling and returns its |
| type. If there is no previous sibling the current node remains |
| unchanged and ``None`` is returned. |
| |
| :return: Node type or ``None`` |
| :rtype: ``int`` or ``None`` |
| """ |
| found = pn_data_prev(self._data) |
| if found: |
| return self.type() |
| else: |
| return None |
| |
| def enter(self): |
| """ |
| Sets the parent node to the current node and clears the current node. |
| Clearing the current node sets it *before* the first child, |
| call :meth:`next` to advance to the first child. |
| |
| :return: ``True`` iff the pointers to the current/parent nodes are changed, |
| ``False`` otherwise. |
| :rtype: ``bool`` |
| """ |
| return pn_data_enter(self._data) |
| |
| def exit(self): |
| """ |
| Sets the current node to the parent node and the parent node to |
| its own parent. |
| |
| :return: ``True`` iff the pointers to the current/parent nodes are changed, |
| ``False`` otherwise. |
| :rtype: ``bool`` |
| """ |
| return pn_data_exit(self._data) |
| |
| def lookup(self, name): |
| return pn_data_lookup(self._data, name) |
| |
| def narrow(self): |
| """ |
| Modify this :class:`Data` object to behave as if the current node is the |
| root node of the tree. This impacts the behavior of :meth:`rewind`, |
| :meth:`next`, :meth:`prev`, and anything else that depends on the |
| navigational state of the :class:`Data` object. Use :meth:`widen` |
| to reverse the effect of this operation. |
| """ |
| pn_data_narrow(self._data) |
| |
| def widen(self): |
| """ Reverse the effect of :meth:`narrow`. """ |
| pn_data_widen(self._data) |
| |
| def type(self): |
| """ |
| Returns the type of the current node. Returns `None` if there is no |
| current node. |
| |
| :return: The current node type enumeration. |
| :rtype: ``int`` or ``None`` |
| """ |
| dtype = pn_data_type(self._data) |
| if dtype == -1: |
| return None |
| else: |
| return dtype |
| |
| def encoded_size(self): |
| """ |
| Returns the size in bytes needed to encode the data in AMQP format. |
| |
| :return: The size of the encoded data or an error code if data is invalid. |
| :rtype: ``int`` |
| """ |
| return pn_data_encoded_size(self._data) |
| |
| def encode(self): |
| """ |
| Returns a representation of the data encoded in AMQP format. |
| |
| :return: The size of the encoded data |
| :rtype: ``int`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| size = 1024 |
| while True: |
| cd, enc = pn_data_encode(self._data, size) |
| if cd == PN_OVERFLOW: |
| size *= 2 |
| elif cd >= 0: |
| return enc |
| else: |
| self._check(cd) |
| |
| def decode(self, encoded): |
| """ |
| Decodes the first value from supplied AMQP data and returns the |
| number of bytes consumed. |
| |
| :type encoded: binary |
| :param encoded: AMQP encoded binary data |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| return self._check(pn_data_decode(self._data, encoded)) |
| |
| def put_list(self): |
| """ |
| Puts a list value. Elements may be filled by entering the list |
| node and putting element values. |
| |
| >>> data = Data() |
| >>> data.put_list() |
| >>> data.enter() |
| >>> data.put_int(1) |
| >>> data.put_int(2) |
| >>> data.put_int(3) |
| >>> data.exit() |
| |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_list(self._data)) |
| |
| def put_map(self): |
| """ |
| Puts a map value. Elements may be filled by entering the map node |
| and putting alternating key value pairs. |
| |
| >>> data = Data() |
| >>> data.put_map() |
| >>> data.enter() |
| >>> data.put_string("key") |
| >>> data.put_string("value") |
| >>> data.exit() |
| |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_map(self._data)) |
| |
| def put_array(self, described, element_type): |
| """ |
| Puts an array value. Elements may be filled by entering the array |
| node and putting the element values. The values must all be of the |
| specified array element type. If an array is described then the |
| first child value of the array is the descriptor and may be of any |
| type. |
| |
| >>> data = Data() |
| >>> |
| >>> data.put_array(False, Data.INT) |
| >>> data.enter() |
| >>> data.put_int(1) |
| >>> data.put_int(2) |
| >>> data.put_int(3) |
| >>> data.exit() |
| >>> |
| >>> data.put_array(True, Data.DOUBLE) |
| >>> data.enter() |
| >>> data.put_symbol("array-descriptor") |
| >>> data.put_double(1.1) |
| >>> data.put_double(1.2) |
| >>> data.put_double(1.3) |
| >>> data.exit() |
| |
| :type described: bool |
| :param described: specifies whether the array is described |
| :type element_type: int |
| :param element_type: the type of the array elements |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_array(self._data, described, element_type)) |
| |
| def put_described(self): |
| """ |
| Puts a described value. A described node has two children, the |
| descriptor and the value. These are specified by entering the node |
| and putting the desired values. |
| |
| >>> data = Data() |
| >>> data.put_described() |
| >>> data.enter() |
| >>> data.put_symbol("value-descriptor") |
| >>> data.put_string("the value") |
| >>> data.exit() |
| |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_described(self._data)) |
| |
| def put_null(self): |
| """ |
| Puts a null value. |
| |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_null(self._data)) |
| |
| def put_bool(self, b): |
| """ |
| Puts a boolean value. |
| |
| :param b: a boolean value |
| :type b: ``bool`` or ``int`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_bool(self._data, b)) |
| |
| def put_ubyte(self, ub): |
| """ |
| Puts an unsigned byte value. |
| |
| :param ub: an integral value in the range :math:`0` to :math:`2^8 - 1` inclusive |
| :type ub: ``int``, :class:`ubyte` |
| :raise: * ``AssertionError`` if parameter is out of the range :math:`0` to :math:`2^8 - 1` inclusive. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_ubyte(self._data, ub)) |
| |
| def put_byte(self, b): |
| """ |
| Puts a signed byte value. |
| |
| :param b: an integral value in the range :math:`-(2^7)` to :math:`2^7 - 1` inclusive. |
| :type b: ``int``, :class:`byte` |
| :raise: * ``AssertionError`` if parameter is out of the range :math:`-(2^7)` to :math:`2^7 - 1` inclusive. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_byte(self._data, b)) |
| |
| def put_ushort(self, us): |
| """ |
| Puts an unsigned short value. |
| |
| :param us: an integral value in the range :math:`0` to :math:`2^{16} - 1` inclusive. |
| :type us: ``int``, :class:`ushort` |
| :raise: * ``AssertionError`` if parameter is out of the range :math:`0` to :math:`2^{16} - 1` inclusive. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_ushort(self._data, us)) |
| |
| def put_short(self, s): |
| """ |
| Puts a signed short value. |
| |
| :param s: an integral value in the range :math:`-(2^{15})` to :math:`2^{15} - 1` inclusive. |
| :type s: ``int``, :class:`short` |
| :raise: * ``AssertionError`` if parameter is out of the range :math:`-(2^{15})` to :math:`2^{15} - 1` inclusive. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_short(self._data, s)) |
| |
| def put_uint(self, ui): |
| """ |
| Puts an unsigned int value. |
| |
| :param ui: an integral value in the range :math:`0` to :math:`2^{32} - 1` inclusive. |
| :type ui: ``int``, :class:`uint` |
| :raise: * ``AssertionError`` if parameter is out of the range :math:`0` to :math:`2^{32} - 1` inclusive. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_uint(self._data, ui)) |
| |
| def put_int(self, i): |
| """ |
| Puts a signed int value. |
| |
| :param i: an integral value in the range :math:`-(2^{31})` to :math:`2^{31} - 1` inclusive. |
| :type i: ``int``, :class:`int32` |
| :raise: * ``AssertionError`` if parameter is out of the range :math:`-(2^{31})` to :math:`2^{31} - 1` inclusive. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_int(self._data, i)) |
| |
| def put_char(self, c): |
| """ |
| Puts a char value. |
| |
| :param c: a single character |
| :type c: ``str``, :class:`char` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_char(self._data, ord(c))) |
| |
| def put_ulong(self, ul): |
| """ |
| Puts an unsigned long value. |
| |
| :param ul: an integral value in the range :math:`0` to :math:`2^{64} - 1` inclusive. |
| :type ul: ``int``, ``long``, :class:`ulong` |
| :raise: * ``AssertionError`` if parameter is out of the range :math:`0` to :math:`2^{64} - 1` inclusive. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_ulong(self._data, ul)) |
| |
| def put_long(self, l): |
| """ |
| Puts a signed long value. |
| |
| :param l: an integral value in the range :math:`-(2^{63})` to :math:`2^{63} - 1` inclusive. |
| :type ul: ``int``, ``long`` |
| :raise: * ``AssertionError`` if parameter is out of the range :math:`-(2^{63})` to :math:`2^{63} - 1` inclusive. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_long(self._data, l)) |
| |
| def put_timestamp(self, t): |
| """ |
| Puts a timestamp value. |
| |
| :param t: a positive integral value |
| :type t: ``int``, :class:`timestamp` |
| :raise: * ``AssertionError`` if parameter is negative. |
| * :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_timestamp(self._data, t)) |
| |
| def put_float(self, f): |
| """ |
| Puts a float value. |
| |
| :param f: a floating point value |
| :type f: ``float``, :class:`float32` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_float(self._data, f)) |
| |
| def put_double(self, d): |
| """ |
| Puts a double value. |
| |
| :param d: a floating point value. |
| :type d: ``double`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_double(self._data, d)) |
| |
| def put_decimal32(self, d): |
| """ |
| Puts a decimal32 value. |
| |
| :param d: a decimal32 number encoded in an 32-bit integral value. |
| :type d: ``int``, :class:`decimal32` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_decimal32(self._data, d)) |
| |
| def put_decimal64(self, d): |
| """ |
| Puts a decimal64 value. |
| |
| :param d: a decimal64 number encoded in an 32-bit integral value. |
| :type d: ``int``, ``long``, :class:`decimal64` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_decimal64(self._data, d)) |
| |
| def put_decimal128(self, d): |
| """ |
| Puts a decimal128 value. |
| |
| :param d: a decimal128 value encoded in a 16-byte binary value. |
| :type d: ``bytes``, :class:`decimal128` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_decimal128(self._data, d)) |
| |
| def put_uuid(self, u): |
| """ |
| Puts a UUID value. |
| |
| :param u: a uuid value. |
| :type u: ``uuid.UUID`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_uuid(self._data, u.bytes)) |
| |
| def put_binary(self, b): |
| """ |
| Puts a binary value. |
| |
| :param b: a binary value |
| :type b: ``bytes`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_binary(self._data, b)) |
| |
| def put_memoryview(self, mv): |
| """ |
| Put a Python memoryview object as an AMQP binary value. |
| |
| :param mv: A Python memoryview object |
| :type mv: ``memoryview`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self.put_binary(mv.tobytes()) |
| |
| def put_buffer(self, buff): |
| """ |
| Put a Python buffer object as an AMQP binary value. |
| |
| :param buff: A Python buffer object (**CHECK THIS**) |
| :type buff: Any object supporting the Python buffer interface. |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self.put_binary(bytes(buff)) |
| |
| def put_string(self, s): |
| """ |
| Puts a unicode value. |
| |
| :param s: a unicode string |
| :type s: ``str`` (Python 3.x) or ``unicode`` (Python 2.x) |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_string(self._data, s.encode("utf8"))) |
| |
| def put_symbol(self, s): |
| """ |
| Puts a symbolic value. |
| |
| :param s: the symbol name |
| :type s: string, :class:`symbol` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_put_symbol(self._data, s.encode('ascii'))) |
| |
| def get_list(self): |
| """ |
| If the current node is a list, return the number of elements, |
| otherwise return 0. List elements can be accessed by entering |
| the list. |
| |
| >>> count = data.get_list() |
| >>> data.enter() |
| >>> for i in range(count): |
| ... type = data.next() |
| ... if type == Data.STRING: |
| ... print data.get_string() |
| ... elif type == ...: |
| ... ... |
| >>> data.exit() |
| |
| :return: the number of child elements of a list node |
| :rtype: ``int`` |
| """ |
| return pn_data_get_list(self._data) |
| |
| def get_map(self): |
| """ |
| If the current node is a map, return the number of child elements, |
| otherwise return 0. Key value pairs can be accessed by entering |
| the map. |
| |
| >>> count = data.get_map() |
| >>> data.enter() |
| >>> for i in range(count/2): |
| ... type = data.next() |
| ... if type == Data.STRING: |
| ... print data.get_string() |
| ... elif type == ...: |
| ... ... |
| >>> data.exit() |
| |
| :return: the number of child elements of a map node |
| :rtype: ``int`` |
| """ |
| return pn_data_get_map(self._data) |
| |
| def get_array(self): |
| """ |
| If the current node is an array, return a tuple of the element |
| count, a boolean indicating whether the array is described, and |
| the type of each element, otherwise return ``None``. Array |
| data can be accessed by entering the array. |
| |
| >>> # read an array of strings with a symbolic descriptor |
| >>> count, described, type = data.get_array() |
| >>> data.enter() |
| >>> data.next() |
| >>> print "Descriptor:", data.get_symbol() |
| >>> for i in range(count): |
| ... data.next() |
| ... print "Element:", data.get_string() |
| >>> data.exit() |
| |
| :return: A tuple containing the number of array elements, the descriptor |
| (or ``None`` if no descriptor) and the enumerated array element type. |
| :rtype: ``tuple`` (``int``, ``str`` or ``None``, ``int``) |
| """ |
| count = pn_data_get_array(self._data) |
| described = pn_data_is_array_described(self._data) |
| type = pn_data_get_array_type(self._data) |
| if type == -1: |
| type = None |
| return count, described, type |
| |
| def is_described(self): |
| """ |
| Checks if the current node is a described value. The descriptor |
| and value may be accessed by entering the described value. |
| |
| >>> # read a symbolically described string |
| >>> assert data.is_described() # will error if the current node is not described |
| >>> data.enter() |
| >>> data.next() |
| >>> print data.get_symbol() |
| >>> data.next() |
| >>> print data.get_string() |
| >>> data.exit() |
| |
| :return: ``True`` if the current node is a described type, ``False`` otherwise. |
| :rtype: ``bool`` |
| """ |
| return pn_data_is_described(self._data) |
| |
| def is_null(self): |
| """ |
| Checks if the current node is the AMQP null type. |
| |
| :return: ``True`` if the current node is the AMQP null type, ``False`` otherwise. |
| :rtype: ``bool`` |
| """ |
| return pn_data_is_null(self._data) |
| |
| def get_bool(self): |
| """ |
| Get the current node value as a ``bool``. |
| |
| :return: If the current node is a boolean type, returns its value, |
| ``False`` otherwise. |
| :rtype: ``bool`` |
| """ |
| return pn_data_get_bool(self._data) |
| |
| def get_ubyte(self): |
| """ |
| Get the current node value as a :class:`ubyte`. |
| |
| :return: If the current node is an unsigned byte, its value, 0 otherwise. |
| :rtype: :class:`ubyte` |
| """ |
| return ubyte(pn_data_get_ubyte(self._data)) |
| |
| def get_byte(self): |
| """ |
| Get the current node value as a :class:`byte`. |
| |
| :return: If the current node is a signed byte, its value, 0 otherwise. |
| :rtype: :class:`byte` |
| """ |
| return byte(pn_data_get_byte(self._data)) |
| |
| def get_ushort(self): |
| """ |
| Get the current node value as a :class:`ushort`. |
| |
| :return: If the current node is an unsigned short, its value, 0 otherwise. |
| :rtype: :class:`ushort` |
| """ |
| return ushort(pn_data_get_ushort(self._data)) |
| |
| def get_short(self): |
| """ |
| Get the current node value as a :class:`short`. |
| |
| :return: If the current node is a signed short, its value, 0 otherwise. |
| :rtype: :class:`short` |
| """ |
| return short(pn_data_get_short(self._data)) |
| |
| def get_uint(self): |
| """ |
| Get the current node value as a :class:`uint`. |
| |
| :return: If the current node is an unsigned int, its value, 0 otherwise. |
| :rtype: :class:`uint` |
| """ |
| return uint(pn_data_get_uint(self._data)) |
| |
| def get_int(self): |
| """ |
| Get the current node value as a :class:`int32`. |
| |
| :return: If the current node is a signed int, its value, 0 otherwise. |
| :rtype: :class:`int32` |
| """ |
| return int32(pn_data_get_int(self._data)) |
| |
| def get_char(self): |
| """ |
| Get the current node value as a :class:`char`. |
| |
| :return: If the current node is a char, its value, 0 otherwise. |
| :rtype: :class:`char` |
| """ |
| return char(_compat.unichr(pn_data_get_char(self._data))) |
| |
| def get_ulong(self): |
| """ |
| Get the current node value as a :class:`long`. |
| |
| :return: If the current node is an unsigned long, its value, 0 otherwise. |
| :rtype: :class:`ulong` |
| """ |
| return ulong(pn_data_get_ulong(self._data)) |
| |
| def get_long(self): |
| """ |
| Get the current node value as a :class:`ulong`. |
| |
| :return: If the current node is an signed long, its value, 0 otherwise. |
| :rtype: :class:`long` |
| """ |
| return long(pn_data_get_long(self._data)) |
| |
| def get_timestamp(self): |
| """ |
| Get the current node value as a :class:`timestamp`. |
| |
| :return: If the current node is a timestamp, its value, 0 otherwise. |
| :rtype: :class:`timestamp` |
| """ |
| return timestamp(pn_data_get_timestamp(self._data)) |
| |
| def get_float(self): |
| """ |
| Get the current node value as a :class:`float32`. |
| |
| :return: If the current node is a float, its value, 0 otherwise. |
| :rtype: :class:`float32` |
| """ |
| return float32(pn_data_get_float(self._data)) |
| |
| def get_double(self): |
| """ |
| Get the current node value as a ``double``. |
| |
| :return: If the current node is a double, its value, 0 otherwise. |
| :rtype: ``double`` |
| """ |
| return pn_data_get_double(self._data) |
| |
| # XXX: need to convert |
| def get_decimal32(self): |
| """ |
| Get the current node value as a :class:`decimal32`. |
| |
| :return: If the current node is a decimal32, its value, 0 otherwise. |
| :rtype: :class:`decimal32` |
| """ |
| return decimal32(pn_data_get_decimal32(self._data)) |
| |
| # XXX: need to convert |
| def get_decimal64(self): |
| """ |
| Get the current node value as a :class:`decimal64`. |
| |
| :return: If the current node is a decimal64, its value, 0 otherwise. |
| :rtype: :class:`decimal64` |
| """ |
| return decimal64(pn_data_get_decimal64(self._data)) |
| |
| # XXX: need to convert |
| def get_decimal128(self): |
| """ |
| Get the current node value as a :class:`decimal128`. |
| |
| :return: If the current node is a decimal128, its value, 0 otherwise. |
| :rtype: :class:`decimal128` |
| """ |
| return decimal128(pn_data_get_decimal128(self._data)) |
| |
| def get_uuid(self): |
| """ |
| Get the current node value as a ``uuid.UUID``. |
| |
| :return: If the current node is a UUID, its value, ``None`` otherwise. |
| :rtype: ``uuid.UUID`` or ``None`` |
| """ |
| if pn_data_type(self._data) == Data.UUID: |
| return uuid.UUID(bytes=pn_data_get_uuid(self._data)) |
| else: |
| return None |
| |
| def get_binary(self): |
| """ |
| Get the current node value as ``bytes``. |
| |
| :return: If the current node is binary, its value, ``""`` otherwise. |
| :rtype: ``bytes`` |
| """ |
| return pn_data_get_binary(self._data) |
| |
| def get_string(self): |
| """ |
| Get the current node value as ``str``. |
| |
| :return: If the current node is a string, its value, ``""`` otherwise. |
| :rtype: ``str`` |
| """ |
| return pn_data_get_string(self._data).decode("utf8") |
| |
| def get_symbol(self): |
| """ |
| Get the current node value as :class:`symbol`. |
| |
| :return: If the current node is a symbol, its value, ``""`` otherwise. |
| :rtype: :class:`symbol` |
| """ |
| return symbol(pn_data_get_symbol(self._data).decode('ascii')) |
| |
| def copy(self, src): |
| """ |
| Copy the contents of another pn_data_t object. Any values in the |
| data object will be lost. |
| |
| :param src: The source object from which to copy |
| :type src: :class:`Data` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self._check(pn_data_copy(self._data, src._data)) |
| |
| def format(self): |
| """ |
| Formats the contents of this :class:`Data` object in a human readable way. |
| |
| :return: A Formatted string containing contents of this :class:`Data` object. |
| :rtype: ``str`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| sz = 16 |
| while True: |
| err, result = pn_data_format(self._data, sz) |
| if err == PN_OVERFLOW: |
| sz *= 2 |
| continue |
| else: |
| self._check(err) |
| return result |
| |
| def dump(self): |
| """ |
| Dumps a debug representation of the internal state of this :class:`Data` |
| object that includes its navigational state to ``cout`` (``stdout``) for |
| debugging purposes. |
| """ |
| pn_data_dump(self._data) |
| |
| def put_dict(self, d): |
| """ |
| A convenience method for encoding the contents of a Python ``dict`` |
| as an AMQP map. |
| |
| :param d: The dictionary to be encoded |
| :type d: ``dict`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self.put_map() |
| self.enter() |
| try: |
| for k, v in d.items(): |
| self.put_object(k) |
| self.put_object(v) |
| finally: |
| self.exit() |
| |
| def get_dict(self): |
| """ |
| A convenience method for decoding an AMQP map as a Python ``dict``. |
| |
| :returns: The decoded dictionary. |
| :rtype: ``dict`` |
| """ |
| if self.enter(): |
| try: |
| result = {} |
| while self.next(): |
| k = self.get_object() |
| if self.next(): |
| v = self.get_object() |
| else: |
| v = None |
| result[k] = v |
| finally: |
| self.exit() |
| return result |
| |
| def put_sequence(self, s): |
| """ |
| A convenience method for encoding a Python ``list`` as an |
| AMQP list. |
| |
| :param s: The sequence to be encoded |
| :type s: ``list`` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self.put_list() |
| self.enter() |
| try: |
| for o in s: |
| self.put_object(o) |
| finally: |
| self.exit() |
| |
| def get_sequence(self): |
| """ |
| A convenience method for decoding an AMQP list as a Python ``list``. |
| |
| :returns: The decoded list. |
| :rtype: ``list`` |
| """ |
| if self.enter(): |
| try: |
| result = [] |
| while self.next(): |
| result.append(self.get_object()) |
| finally: |
| self.exit() |
| return result |
| |
| def get_py_described(self): |
| """ |
| A convenience method for decoding an AMQP described value. |
| |
| :returns: The decoded AMQP descriptor. |
| :rtype: :class:`Described` |
| """ |
| if self.enter(): |
| try: |
| self.next() |
| descriptor = self.get_object() |
| self.next() |
| value = self.get_object() |
| finally: |
| self.exit() |
| return Described(descriptor, value) |
| |
| def put_py_described(self, d): |
| """ |
| A convenience method for encoding a :class:`Described` object |
| as an AMQP described value. This method encapsulates all the steps |
| described in :func:`put_described` into a single method. |
| |
| :param d: The descriptor to be encoded |
| :type d: :class:`Described` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| self.put_described() |
| self.enter() |
| try: |
| self.put_object(d.descriptor) |
| self.put_object(d.value) |
| finally: |
| self.exit() |
| |
| def get_py_array(self): |
| """ |
| A convenience method for decoding an AMQP array into an |
| :class:`Array` object. This method encapsulates all the |
| steps described in :func:`get_array` into a single function. |
| |
| If the current node is an array, return an Array object |
| representing the array and its contents. Otherwise return ``None``. |
| |
| :returns: The decoded AMQP array. |
| :rtype: :class:`Array` |
| """ |
| |
| count, described, type = self.get_array() |
| if type is None: return None |
| if self.enter(): |
| try: |
| if described: |
| self.next() |
| descriptor = self.get_object() |
| else: |
| descriptor = UNDESCRIBED |
| elements = [] |
| while self.next(): |
| elements.append(self.get_object()) |
| finally: |
| self.exit() |
| return Array(descriptor, type, *elements) |
| |
| def put_py_array(self, a): |
| """ |
| A convenience method for encoding an :class:`Array` object as |
| an AMQP array. This method encapsulates the steps described in |
| :func:`put_array` into a single function. |
| |
| :param a: The array object to be encoded |
| :type a: :class:`Array` |
| :raise: :exc:`DataException` if there is a Proton error. |
| """ |
| described = a.descriptor != UNDESCRIBED |
| self.put_array(described, a.type) |
| self.enter() |
| try: |
| if described: |
| self.put_object(a.descriptor) |
| for e in a.elements: |
| self.put_object(e) |
| finally: |
| self.exit() |
| |
| put_mappings = { |
| None.__class__: lambda s, _: s.put_null(), |
| bool: put_bool, |
| ubyte: put_ubyte, |
| ushort: put_ushort, |
| uint: put_uint, |
| ulong: put_ulong, |
| byte: put_byte, |
| short: put_short, |
| int32: put_int, |
| long: put_long, |
| float32: put_float, |
| float: put_double, |
| decimal32: put_decimal32, |
| decimal64: put_decimal64, |
| decimal128: put_decimal128, |
| char: put_char, |
| timestamp: put_timestamp, |
| uuid.UUID: put_uuid, |
| bytes: put_binary, |
| unicode: put_string, |
| symbol: put_symbol, |
| list: put_sequence, |
| tuple: put_sequence, |
| dict: put_dict, |
| Described: put_py_described, |
| Array: put_py_array, |
| AnnotationDict: put_dict, |
| PropertyDict: put_dict, |
| SymbolList: put_sequence |
| } |
| # for Python 3.x, long is merely an alias for int, but for Python 2.x |
| # we need to add an explicit int since it is a different type |
| if int not in put_mappings: |
| put_mappings[int] = put_int |
| # Python >=3.0 has 'memoryview', <=2.5 has 'buffer', >=2.6 has both. |
| try: |
| put_mappings[memoryview] = put_memoryview |
| except NameError: |
| pass |
| try: |
| put_mappings[buffer] = put_buffer |
| except NameError: |
| pass |
| get_mappings = { |
| NULL: lambda s: None, |
| BOOL: get_bool, |
| BYTE: get_byte, |
| UBYTE: get_ubyte, |
| SHORT: get_short, |
| USHORT: get_ushort, |
| INT: get_int, |
| UINT: get_uint, |
| CHAR: get_char, |
| LONG: get_long, |
| ULONG: get_ulong, |
| TIMESTAMP: get_timestamp, |
| FLOAT: get_float, |
| DOUBLE: get_double, |
| DECIMAL32: get_decimal32, |
| DECIMAL64: get_decimal64, |
| DECIMAL128: get_decimal128, |
| UUID: get_uuid, |
| BINARY: get_binary, |
| STRING: get_string, |
| SYMBOL: get_symbol, |
| DESCRIBED: get_py_described, |
| ARRAY: get_py_array, |
| LIST: get_sequence, |
| MAP: get_dict |
| } |
| |
| def put_object(self, obj): |
| putter = self.put_mappings[obj.__class__] |
| putter(self, obj) |
| |
| def get_object(self): |
| type = self.type() |
| if type is None: return None |
| getter = self.get_mappings.get(type) |
| if getter: |
| return getter(self) |
| else: |
| return UnmappedType(str(type)) |
| |
| |
| def dat2obj(dimpl): |
| if dimpl: |
| d = Data(dimpl) |
| d.rewind() |
| d.next() |
| obj = d.get_object() |
| d.rewind() |
| return obj |
| |
| |
| def obj2dat(obj, dimpl): |
| if obj is not None: |
| d = Data(dimpl) |
| d.put_object(obj) |