summaryrefslogtreecommitdiffstats
path: root/third_party/python/cbor2
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/python/cbor2')
-rw-r--r--third_party/python/cbor2/cbor2-4.0.1.dist-info/DESCRIPTION.rst26
-rw-r--r--third_party/python/cbor2/cbor2-4.0.1.dist-info/METADATA50
-rw-r--r--third_party/python/cbor2/cbor2-4.0.1.dist-info/RECORD11
-rw-r--r--third_party/python/cbor2/cbor2-4.0.1.dist-info/WHEEL6
-rw-r--r--third_party/python/cbor2/cbor2-4.0.1.dist-info/metadata.json1
-rw-r--r--third_party/python/cbor2/cbor2-4.0.1.dist-info/top_level.txt1
-rw-r--r--third_party/python/cbor2/cbor2/__init__.py3
-rw-r--r--third_party/python/cbor2/cbor2/compat.py49
-rw-r--r--third_party/python/cbor2/cbor2/decoder.py411
-rw-r--r--third_party/python/cbor2/cbor2/encoder.py362
-rw-r--r--third_party/python/cbor2/cbor2/types.py55
11 files changed, 975 insertions, 0 deletions
diff --git a/third_party/python/cbor2/cbor2-4.0.1.dist-info/DESCRIPTION.rst b/third_party/python/cbor2/cbor2-4.0.1.dist-info/DESCRIPTION.rst
new file mode 100644
index 0000000000..734481b638
--- /dev/null
+++ b/third_party/python/cbor2/cbor2-4.0.1.dist-info/DESCRIPTION.rst
@@ -0,0 +1,26 @@
+.. image:: https://travis-ci.org/agronholm/cbor2.svg?branch=master
+ :target: https://travis-ci.org/agronholm/cbor2
+ :alt: Build Status
+.. image:: https://coveralls.io/repos/github/agronholm/cbor2/badge.svg?branch=master
+ :target: https://coveralls.io/github/agronholm/cbor2?branch=master
+ :alt: Code Coverage
+
+This library provides encoding and decoding for the Concise Binary Object Representation (CBOR)
+(`RFC 7049`_) serialization format.
+
+There exists another Python CBOR implementation (cbor) which is faster on CPython due to its C
+extensions. On PyPy, cbor2 and cbor are almost identical in performance. The other implementation
+also lacks documentation and a comprehensive test suite, does not support most standard extension
+tags and is known to crash (segfault) when passed a cyclic structure (say, a list containing
+itself).
+
+.. _RFC 7049: https://tools.ietf.org/html/rfc7049
+
+Project links
+-------------
+
+* `Documentation <http://cbor2.readthedocs.org/>`_
+* `Source code <https://github.com/agronholm/cbor2>`_
+* `Issue tracker <https://github.com/agronholm/cbor2/issues>`_
+
+
diff --git a/third_party/python/cbor2/cbor2-4.0.1.dist-info/METADATA b/third_party/python/cbor2/cbor2-4.0.1.dist-info/METADATA
new file mode 100644
index 0000000000..c7f42ac60f
--- /dev/null
+++ b/third_party/python/cbor2/cbor2-4.0.1.dist-info/METADATA
@@ -0,0 +1,50 @@
+Metadata-Version: 2.0
+Name: cbor2
+Version: 4.0.1
+Summary: Pure Python CBOR (de)serializer with extensive tag support
+Home-page: https://github.com/agronholm/cbor2
+Author: Alex Grönholm
+Author-email: alex.gronholm@nextday.fi
+License: MIT
+Keywords: serialization cbor
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Provides-Extra: testing
+Requires-Dist: pytest; extra == 'testing'
+Requires-Dist: pytest-cov; extra == 'testing'
+
+.. image:: https://travis-ci.org/agronholm/cbor2.svg?branch=master
+ :target: https://travis-ci.org/agronholm/cbor2
+ :alt: Build Status
+.. image:: https://coveralls.io/repos/github/agronholm/cbor2/badge.svg?branch=master
+ :target: https://coveralls.io/github/agronholm/cbor2?branch=master
+ :alt: Code Coverage
+
+This library provides encoding and decoding for the Concise Binary Object Representation (CBOR)
+(`RFC 7049`_) serialization format.
+
+There exists another Python CBOR implementation (cbor) which is faster on CPython due to its C
+extensions. On PyPy, cbor2 and cbor are almost identical in performance. The other implementation
+also lacks documentation and a comprehensive test suite, does not support most standard extension
+tags and is known to crash (segfault) when passed a cyclic structure (say, a list containing
+itself).
+
+.. _RFC 7049: https://tools.ietf.org/html/rfc7049
+
+Project links
+-------------
+
+* `Documentation <http://cbor2.readthedocs.org/>`_
+* `Source code <https://github.com/agronholm/cbor2>`_
+* `Issue tracker <https://github.com/agronholm/cbor2/issues>`_
+
+
diff --git a/third_party/python/cbor2/cbor2-4.0.1.dist-info/RECORD b/third_party/python/cbor2/cbor2-4.0.1.dist-info/RECORD
new file mode 100644
index 0000000000..e29279b8df
--- /dev/null
+++ b/third_party/python/cbor2/cbor2-4.0.1.dist-info/RECORD
@@ -0,0 +1,11 @@
+cbor2/__init__.py,sha256=Si4l50bD5McrzpgQ6bEmhla2w2U910scs0lCqHzwxOo,239
+cbor2/compat.py,sha256=aBzyMrGwl061zdmlFPQrk4U1rqZQcVNl5ojRsQdG5d0,1033
+cbor2/decoder.py,sha256=6bJMq6fC8RRe5uJFrvKy9T-J3VLYKIkSF9UUmmlYj2A,11936
+cbor2/encoder.py,sha256=OimwLht642jK61Vl2X5FeIv3rHL0hd5yjQ7ajoO2hko,11496
+cbor2/types.py,sha256=I2lpvqktj8Nm8MJtUwdhOYXAUJw-UctYTQlKg0qZ9pc,1302
+cbor2-4.0.1.dist-info/DESCRIPTION.rst,sha256=1Lg57ktrF2XHHyDuGfWtKY5VZd4ydp3-7Ptr27cbWrE,1091
+cbor2-4.0.1.dist-info/METADATA,sha256=h1mC4t8mFZcyJc3cHWJFUf5wUWYVPAqh4Q4DRe0ajQg,1981
+cbor2-4.0.1.dist-info/RECORD,,
+cbor2-4.0.1.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110
+cbor2-4.0.1.dist-info/metadata.json,sha256=lHkH6x7w_MNrQqe5ZNu9kihQi3Gg-XOQpYTTElRtKe8,1006
+cbor2-4.0.1.dist-info/top_level.txt,sha256=4Z7JYs5_QM6eqOa2Ew1n_2-uKm2SYl76j2NWTtfCChs,6
diff --git a/third_party/python/cbor2/cbor2-4.0.1.dist-info/WHEEL b/third_party/python/cbor2/cbor2-4.0.1.dist-info/WHEEL
new file mode 100644
index 0000000000..8b6dd1b5a8
--- /dev/null
+++ b/third_party/python/cbor2/cbor2-4.0.1.dist-info/WHEEL
@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.29.0)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+
diff --git a/third_party/python/cbor2/cbor2-4.0.1.dist-info/metadata.json b/third_party/python/cbor2/cbor2-4.0.1.dist-info/metadata.json
new file mode 100644
index 0000000000..85d36a4496
--- /dev/null
+++ b/third_party/python/cbor2/cbor2-4.0.1.dist-info/metadata.json
@@ -0,0 +1 @@
+{"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6"], "extensions": {"python.details": {"contacts": [{"email": "alex.gronholm@nextday.fi", "name": "Alex Gr\u00f6nholm", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/agronholm/cbor2"}}}, "extras": ["testing"], "generator": "bdist_wheel (0.29.0)", "keywords": ["serialization", "cbor"], "license": "MIT", "metadata_version": "2.0", "name": "cbor2", "run_requires": [{"extra": "testing", "requires": ["pytest-cov", "pytest"]}], "summary": "Pure Python CBOR (de)serializer with extensive tag support", "version": "4.0.1"} \ No newline at end of file
diff --git a/third_party/python/cbor2/cbor2-4.0.1.dist-info/top_level.txt b/third_party/python/cbor2/cbor2-4.0.1.dist-info/top_level.txt
new file mode 100644
index 0000000000..615ca8aeba
--- /dev/null
+++ b/third_party/python/cbor2/cbor2-4.0.1.dist-info/top_level.txt
@@ -0,0 +1 @@
+cbor2
diff --git a/third_party/python/cbor2/cbor2/__init__.py b/third_party/python/cbor2/cbor2/__init__.py
new file mode 100644
index 0000000000..474841ace4
--- /dev/null
+++ b/third_party/python/cbor2/cbor2/__init__.py
@@ -0,0 +1,3 @@
+from cbor2.decoder import load, loads, CBORDecoder, CBORDecodeError # noqa
+from cbor2.encoder import dump, dumps, CBOREncoder, CBOREncodeError, shareable_encoder # noqa
+from cbor2.types import CBORTag, CBORSimpleValue, undefined # noqa
diff --git a/third_party/python/cbor2/cbor2/compat.py b/third_party/python/cbor2/cbor2/compat.py
new file mode 100644
index 0000000000..983efda59b
--- /dev/null
+++ b/third_party/python/cbor2/cbor2/compat.py
@@ -0,0 +1,49 @@
+import sys
+
+
+if sys.version_info.major < 3:
+ from datetime import tzinfo, timedelta
+
+ class timezone(tzinfo):
+ def __init__(self, offset):
+ self.offset = offset
+
+ def utcoffset(self, dt):
+ return self.offset
+
+ def dst(self, dt):
+ return timedelta(0)
+
+ def tzname(self, dt):
+ return 'UTC+00:00'
+
+ def as_unicode(string):
+ return string.decode('utf-8')
+
+ def iteritems(self):
+ return self.iteritems()
+
+ def bytes_from_list(values):
+ return bytes(bytearray(values))
+
+ byte_as_integer = ord
+ timezone.utc = timezone(timedelta(0))
+ xrange = xrange # noqa
+ long = long # noqa
+ unicode = unicode # noqa
+else:
+ from datetime import timezone
+
+ def byte_as_integer(bytestr):
+ return bytestr[0]
+
+ def as_unicode(string):
+ return string
+
+ def iteritems(self):
+ return self.items()
+
+ xrange = range # noqa
+ long = int # noqa
+ unicode = str # noqa
+ bytes_from_list = bytes
diff --git a/third_party/python/cbor2/cbor2/decoder.py b/third_party/python/cbor2/cbor2/decoder.py
new file mode 100644
index 0000000000..5833d9e9f4
--- /dev/null
+++ b/third_party/python/cbor2/cbor2/decoder.py
@@ -0,0 +1,411 @@
+import re
+import struct
+from datetime import datetime, timedelta
+from io import BytesIO
+
+from cbor2.compat import timezone, xrange, byte_as_integer
+from cbor2.types import CBORTag, undefined, break_marker, CBORSimpleValue
+
+timestamp_re = re.compile(r'^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)'
+ r'(?:\.(\d+))?(?:Z|([+-]\d\d):(\d\d))$')
+
+
+class CBORDecodeError(Exception):
+ """Raised when an error occurs deserializing a CBOR datastream."""
+
+
+def decode_uint(decoder, subtype, shareable_index=None, allow_infinite=False):
+ # Major tag 0
+ if subtype < 24:
+ return subtype
+ elif subtype == 24:
+ return struct.unpack('>B', decoder.read(1))[0]
+ elif subtype == 25:
+ return struct.unpack('>H', decoder.read(2))[0]
+ elif subtype == 26:
+ return struct.unpack('>L', decoder.read(4))[0]
+ elif subtype == 27:
+ return struct.unpack('>Q', decoder.read(8))[0]
+ elif subtype == 31 and allow_infinite:
+ return None
+ else:
+ raise CBORDecodeError('unknown unsigned integer subtype 0x%x' % subtype)
+
+
+def decode_negint(decoder, subtype, shareable_index=None):
+ # Major tag 1
+ uint = decode_uint(decoder, subtype)
+ return -uint - 1
+
+
+def decode_bytestring(decoder, subtype, shareable_index=None):
+ # Major tag 2
+ length = decode_uint(decoder, subtype, allow_infinite=True)
+ if length is None:
+ # Indefinite length
+ buf = bytearray()
+ while True:
+ initial_byte = byte_as_integer(decoder.read(1))
+ if initial_byte == 255:
+ return buf
+ else:
+ length = decode_uint(decoder, initial_byte & 31)
+ value = decoder.read(length)
+ buf.extend(value)
+ else:
+ return decoder.read(length)
+
+
+def decode_string(decoder, subtype, shareable_index=None):
+ # Major tag 3
+ return decode_bytestring(decoder, subtype).decode('utf-8')
+
+
+def decode_array(decoder, subtype, shareable_index=None):
+ # Major tag 4
+ items = []
+ decoder.set_shareable(shareable_index, items)
+ length = decode_uint(decoder, subtype, allow_infinite=True)
+ if length is None:
+ # Indefinite length
+ while True:
+ value = decoder.decode()
+ if value is break_marker:
+ break
+ else:
+ items.append(value)
+ else:
+ for _ in xrange(length):
+ item = decoder.decode()
+ items.append(item)
+
+ return items
+
+
+def decode_map(decoder, subtype, shareable_index=None):
+ # Major tag 5
+ dictionary = {}
+ decoder.set_shareable(shareable_index, dictionary)
+ length = decode_uint(decoder, subtype, allow_infinite=True)
+ if length is None:
+ # Indefinite length
+ while True:
+ key = decoder.decode()
+ if key is break_marker:
+ break
+ else:
+ value = decoder.decode()
+ dictionary[key] = value
+ else:
+ for _ in xrange(length):
+ key = decoder.decode()
+ value = decoder.decode()
+ dictionary[key] = value
+
+ if decoder.object_hook:
+ return decoder.object_hook(decoder, dictionary)
+ else:
+ return dictionary
+
+
+def decode_semantic(decoder, subtype, shareable_index=None):
+ # Major tag 6
+ tagnum = decode_uint(decoder, subtype)
+
+ # Special handling for the "shareable" tag
+ if tagnum == 28:
+ shareable_index = decoder._allocate_shareable()
+ return decoder.decode(shareable_index)
+
+ value = decoder.decode()
+ semantic_decoder = semantic_decoders.get(tagnum)
+ if semantic_decoder:
+ return semantic_decoder(decoder, value, shareable_index)
+
+ tag = CBORTag(tagnum, value)
+ if decoder.tag_hook:
+ return decoder.tag_hook(decoder, tag, shareable_index)
+ else:
+ return tag
+
+
+def decode_special(decoder, subtype, shareable_index=None):
+ # Simple value
+ if subtype < 20:
+ return CBORSimpleValue(subtype)
+
+ # Major tag 7
+ return special_decoders[subtype](decoder)
+
+
+#
+# Semantic decoders (major tag 6)
+#
+
+def decode_datetime_string(decoder, value, shareable_index=None):
+ # Semantic tag 0
+ match = timestamp_re.match(value)
+ if match:
+ year, month, day, hour, minute, second, micro, offset_h, offset_m = match.groups()
+ if offset_h:
+ tz = timezone(timedelta(hours=int(offset_h), minutes=int(offset_m)))
+ else:
+ tz = timezone.utc
+
+ return datetime(int(year), int(month), int(day), int(hour), int(minute), int(second),
+ int(micro or 0), tz)
+ else:
+ raise CBORDecodeError('invalid datetime string: {}'.format(value))
+
+
+def decode_epoch_datetime(decoder, value, shareable_index=None):
+ # Semantic tag 1
+ return datetime.fromtimestamp(value, timezone.utc)
+
+
+def decode_positive_bignum(decoder, value, shareable_index=None):
+ # Semantic tag 2
+ from binascii import hexlify
+ return int(hexlify(value), 16)
+
+
+def decode_negative_bignum(decoder, value, shareable_index=None):
+ # Semantic tag 3
+ return -decode_positive_bignum(decoder, value) - 1
+
+
+def decode_fraction(decoder, value, shareable_index=None):
+ # Semantic tag 4
+ from decimal import Decimal
+ exp = Decimal(value[0])
+ mantissa = Decimal(value[1])
+ return mantissa * (10 ** exp)
+
+
+def decode_bigfloat(decoder, value, shareable_index=None):
+ # Semantic tag 5
+ from decimal import Decimal
+ exp = Decimal(value[0])
+ mantissa = Decimal(value[1])
+ return mantissa * (2 ** exp)
+
+
+def decode_sharedref(decoder, value, shareable_index=None):
+ # Semantic tag 29
+ try:
+ shared = decoder._shareables[value]
+ except IndexError:
+ raise CBORDecodeError('shared reference %d not found' % value)
+
+ if shared is None:
+ raise CBORDecodeError('shared value %d has not been initialized' % value)
+ else:
+ return shared
+
+
+def decode_rational(decoder, value, shareable_index=None):
+ # Semantic tag 30
+ from fractions import Fraction
+ return Fraction(*value)
+
+
+def decode_regexp(decoder, value, shareable_index=None):
+ # Semantic tag 35
+ return re.compile(value)
+
+
+def decode_mime(decoder, value, shareable_index=None):
+ # Semantic tag 36
+ from email.parser import Parser
+ return Parser().parsestr(value)
+
+
+def decode_uuid(decoder, value, shareable_index=None):
+ # Semantic tag 37
+ from uuid import UUID
+ return UUID(bytes=value)
+
+
+#
+# Special decoders (major tag 7)
+#
+
+def decode_simple_value(decoder, shareable_index=None):
+ return CBORSimpleValue(struct.unpack('>B', decoder.read(1))[0])
+
+
+def decode_float16(decoder, shareable_index=None):
+ # Code adapted from RFC 7049, appendix D
+ from math import ldexp
+
+ def decode_single(single):
+ return struct.unpack("!f", struct.pack("!I", single))[0]
+
+ payload = struct.unpack('>H', decoder.read(2))[0]
+ value = (payload & 0x7fff) << 13 | (payload & 0x8000) << 16
+ if payload & 0x7c00 != 0x7c00:
+ return ldexp(decode_single(value), 112)
+
+ return decode_single(value | 0x7f800000)
+
+
+def decode_float32(decoder, shareable_index=None):
+ return struct.unpack('>f', decoder.read(4))[0]
+
+
+def decode_float64(decoder, shareable_index=None):
+ return struct.unpack('>d', decoder.read(8))[0]
+
+
+major_decoders = {
+ 0: decode_uint,
+ 1: decode_negint,
+ 2: decode_bytestring,
+ 3: decode_string,
+ 4: decode_array,
+ 5: decode_map,
+ 6: decode_semantic,
+ 7: decode_special
+}
+
+special_decoders = {
+ 20: lambda self: False,
+ 21: lambda self: True,
+ 22: lambda self: None,
+ 23: lambda self: undefined,
+ 24: decode_simple_value,
+ 25: decode_float16,
+ 26: decode_float32,
+ 27: decode_float64,
+ 31: lambda self: break_marker
+}
+
+semantic_decoders = {
+ 0: decode_datetime_string,
+ 1: decode_epoch_datetime,
+ 2: decode_positive_bignum,
+ 3: decode_negative_bignum,
+ 4: decode_fraction,
+ 5: decode_bigfloat,
+ 29: decode_sharedref,
+ 30: decode_rational,
+ 35: decode_regexp,
+ 36: decode_mime,
+ 37: decode_uuid
+}
+
+
+class CBORDecoder(object):
+ """
+ Deserializes a CBOR encoded byte stream.
+
+ :param tag_hook: Callable that takes 3 arguments: the decoder instance, the
+ :class:`~cbor2.types.CBORTag` and the shareable index for the resulting object, if any.
+ This callback is called for any tags for which there is no built-in decoder.
+ The return value is substituted for the CBORTag object in the deserialized output.
+ :param object_hook: Callable that takes 2 arguments: the decoder instance and the dictionary.
+ This callback is called for each deserialized :class:`dict` object.
+ The return value is substituted for the dict in the deserialized output.
+ """
+
+ __slots__ = ('fp', 'tag_hook', 'object_hook', '_shareables')
+
+ def __init__(self, fp, tag_hook=None, object_hook=None):
+ self.fp = fp
+ self.tag_hook = tag_hook
+ self.object_hook = object_hook
+ self._shareables = []
+
+ def _allocate_shareable(self):
+ self._shareables.append(None)
+ return len(self._shareables) - 1
+
+ def set_shareable(self, index, value):
+ """
+ Set the shareable value for the last encountered shared value marker, if any.
+
+ If the given index is ``None``, nothing is done.
+
+ :param index: the value of the ``shared_index`` argument to the decoder
+ :param value: the shared value
+
+ """
+ if index is not None:
+ self._shareables[index] = value
+
+ def read(self, amount):
+ """
+ Read bytes from the data stream.
+
+ :param int amount: the number of bytes to read
+
+ """
+ data = self.fp.read(amount)
+ if len(data) < amount:
+ raise CBORDecodeError('premature end of stream (expected to read {} bytes, got {} '
+ 'instead)'.format(amount, len(data)))
+
+ return data
+
+ def decode(self, shareable_index=None):
+ """
+ Decode the next value from the stream.
+
+ :raises CBORDecodeError: if there is any problem decoding the stream
+
+ """
+ try:
+ initial_byte = byte_as_integer(self.fp.read(1))
+ major_type = initial_byte >> 5
+ subtype = initial_byte & 31
+ except Exception as e:
+ raise CBORDecodeError('error reading major type at index {}: {}'
+ .format(self.fp.tell(), e))
+
+ decoder = major_decoders[major_type]
+ try:
+ return decoder(self, subtype, shareable_index)
+ except CBORDecodeError:
+ raise
+ except Exception as e:
+ raise CBORDecodeError('error decoding value at index {}: {}'.format(self.fp.tell(), e))
+
+ def decode_from_bytes(self, buf):
+ """
+ Wrap the given bytestring as a file and call :meth:`decode` with it as the argument.
+
+ This method was intended to be used from the ``tag_hook`` hook when an object needs to be
+ decoded separately from the rest but while still taking advantage of the shared value
+ registry.
+
+ """
+ old_fp = self.fp
+ self.fp = BytesIO(buf)
+ retval = self.decode()
+ self.fp = old_fp
+ return retval
+
+
+def loads(payload, **kwargs):
+ """
+ Deserialize an object from a bytestring.
+
+ :param bytes payload: the bytestring to serialize
+ :param kwargs: keyword arguments passed to :class:`~.CBORDecoder`
+ :return: the deserialized object
+
+ """
+ fp = BytesIO(payload)
+ return CBORDecoder(fp, **kwargs).decode()
+
+
+def load(fp, **kwargs):
+ """
+ Deserialize an object from an open file.
+
+ :param fp: the input file (any file-like object)
+ :param kwargs: keyword arguments passed to :class:`~.CBORDecoder`
+ :return: the deserialized object
+
+ """
+ return CBORDecoder(fp, **kwargs).decode()
diff --git a/third_party/python/cbor2/cbor2/encoder.py b/third_party/python/cbor2/cbor2/encoder.py
new file mode 100644
index 0000000000..adcb2722e5
--- /dev/null
+++ b/third_party/python/cbor2/cbor2/encoder.py
@@ -0,0 +1,362 @@
+import re
+import struct
+from collections import OrderedDict, defaultdict
+from contextlib import contextmanager
+from functools import wraps
+from datetime import datetime, date, time
+from io import BytesIO
+
+from cbor2.compat import iteritems, timezone, long, unicode, as_unicode, bytes_from_list
+from cbor2.types import CBORTag, undefined, CBORSimpleValue
+
+
+class CBOREncodeError(Exception):
+ """Raised when an error occurs while serializing an object into a CBOR datastream."""
+
+
+def shareable_encoder(func):
+ """
+ Wrap the given encoder function to gracefully handle cyclic data structures.
+
+ If value sharing is enabled, this marks the given value shared in the datastream on the
+ first call. If the value has already been passed to this method, a reference marker is
+ instead written to the data stream and the wrapped function is not called.
+
+ If value sharing is disabled, only infinite recursion protection is done.
+
+ """
+ @wraps(func)
+ def wrapper(encoder, value, *args, **kwargs):
+ value_id = id(value)
+ container, container_index = encoder._shared_containers.get(value_id, (None, None))
+ if encoder.value_sharing:
+ if container is value:
+ # Generate a reference to the previous index instead of encoding this again
+ encoder.write(encode_length(0xd8, 0x1d))
+ encode_int(encoder, container_index)
+ else:
+ # Mark the container as shareable
+ encoder._shared_containers[value_id] = (value, len(encoder._shared_containers))
+ encoder.write(encode_length(0xd8, 0x1c))
+ func(encoder, value, *args, **kwargs)
+ else:
+ if container is value:
+ raise CBOREncodeError('cyclic data structure detected but value sharing is '
+ 'disabled')
+ else:
+ encoder._shared_containers[value_id] = (value, None)
+ func(encoder, value, *args, **kwargs)
+ del encoder._shared_containers[value_id]
+
+ return wrapper
+
+
+def encode_length(major_tag, length):
+ if length < 24:
+ return struct.pack('>B', major_tag | length)
+ elif length < 256:
+ return struct.pack('>BB', major_tag | 24, length)
+ elif length < 65536:
+ return struct.pack('>BH', major_tag | 25, length)
+ elif length < 4294967296:
+ return struct.pack('>BL', major_tag | 26, length)
+ else:
+ return struct.pack('>BQ', major_tag | 27, length)
+
+
+def encode_int(encoder, value):
+ # Big integers (2 ** 64 and over)
+ if value >= 18446744073709551616 or value < -18446744073709551616:
+ if value >= 0:
+ major_type = 0x02
+ else:
+ major_type = 0x03
+ value = -value - 1
+
+ values = []
+ while value > 0:
+ value, remainder = divmod(value, 256)
+ values.insert(0, remainder)
+
+ payload = bytes_from_list(values)
+ encode_semantic(encoder, CBORTag(major_type, payload))
+ elif value >= 0:
+ encoder.write(encode_length(0, value))
+ else:
+ encoder.write(encode_length(0x20, abs(value) - 1))
+
+
+def encode_bytestring(encoder, value):
+ encoder.write(encode_length(0x40, len(value)) + value)
+
+
+def encode_bytearray(encoder, value):
+ encode_bytestring(encoder, bytes(value))
+
+
+def encode_string(encoder, value):
+ encoded = value.encode('utf-8')
+ encoder.write(encode_length(0x60, len(encoded)) + encoded)
+
+
+@shareable_encoder
+def encode_array(encoder, value):
+ encoder.write(encode_length(0x80, len(value)))
+ for item in value:
+ encoder.encode(item)
+
+
+@shareable_encoder
+def encode_map(encoder, value):
+ encoder.write(encode_length(0xa0, len(value)))
+ for key, val in iteritems(value):
+ encoder.encode(key)
+ encoder.encode(val)
+
+
+def encode_semantic(encoder, value):
+ encoder.write(encode_length(0xc0, value.tag))
+ encoder.encode(value.value)
+
+
+#
+# Semantic decoders (major tag 6)
+#
+
+def encode_datetime(encoder, value):
+ # Semantic tag 0
+ if not value.tzinfo:
+ if encoder.timezone:
+ value = value.replace(tzinfo=encoder.timezone)
+ else:
+ raise CBOREncodeError(
+ 'naive datetime encountered and no default timezone has been set')
+
+ if encoder.datetime_as_timestamp:
+ from calendar import timegm
+ timestamp = timegm(value.utctimetuple()) + value.microsecond // 1000000
+ encode_semantic(encoder, CBORTag(1, timestamp))
+ else:
+ datestring = as_unicode(value.isoformat().replace('+00:00', 'Z'))
+ encode_semantic(encoder, CBORTag(0, datestring))
+
+
+def encode_date(encoder, value):
+ value = datetime.combine(value, time()).replace(tzinfo=timezone.utc)
+ encode_datetime(encoder, value)
+
+
+def encode_decimal(encoder, value):
+ # Semantic tag 4
+ if value.is_nan():
+ encoder.write(b'\xf9\x7e\x00')
+ elif value.is_infinite():
+ encoder.write(b'\xf9\x7c\x00' if value > 0 else b'\xf9\xfc\x00')
+ else:
+ dt = value.as_tuple()
+ mantissa = sum(d * 10 ** i for i, d in enumerate(reversed(dt.digits)))
+ with encoder.disable_value_sharing():
+ encode_semantic(encoder, CBORTag(4, [dt.exponent, mantissa]))
+
+
+def encode_rational(encoder, value):
+ # Semantic tag 30
+ with encoder.disable_value_sharing():
+ encode_semantic(encoder, CBORTag(30, [value.numerator, value.denominator]))
+
+
+def encode_regexp(encoder, value):
+ # Semantic tag 35
+ encode_semantic(encoder, CBORTag(35, as_unicode(value.pattern)))
+
+
+def encode_mime(encoder, value):
+ # Semantic tag 36
+ encode_semantic(encoder, CBORTag(36, as_unicode(value.as_string())))
+
+
+def encode_uuid(encoder, value):
+ # Semantic tag 37
+ encode_semantic(encoder, CBORTag(37, value.bytes))
+
+
+#
+# Special encoders (major tag 7)
+#
+
+def encode_simple_value(encoder, value):
+ if value.value < 20:
+ encoder.write(struct.pack('>B', 0xe0 | value.value))
+ else:
+ encoder.write(struct.pack('>BB', 0xf8, value.value))
+
+
+def encode_float(encoder, value):
+ # Handle special values efficiently
+ import math
+ if math.isnan(value):
+ encoder.write(b'\xf9\x7e\x00')
+ elif math.isinf(value):
+ encoder.write(b'\xf9\x7c\x00' if value > 0 else b'\xf9\xfc\x00')
+ else:
+ encoder.write(struct.pack('>Bd', 0xfb, value))
+
+
+def encode_boolean(encoder, value):
+ encoder.write(b'\xf5' if value else b'\xf4')
+
+
+def encode_none(encoder, value):
+ encoder.write(b'\xf6')
+
+
+def encode_undefined(encoder, value):
+ encoder.write(b'\xf7')
+
+
+default_encoders = OrderedDict([
+ (bytes, encode_bytestring),
+ (bytearray, encode_bytearray),
+ (unicode, encode_string),
+ (int, encode_int),
+ (long, encode_int),
+ (float, encode_float),
+ (('decimal', 'Decimal'), encode_decimal),
+ (bool, encode_boolean),
+ (type(None), encode_none),
+ (tuple, encode_array),
+ (list, encode_array),
+ (dict, encode_map),
+ (defaultdict, encode_map),
+ (OrderedDict, encode_map),
+ (type(undefined), encode_undefined),
+ (datetime, encode_datetime),
+ (date, encode_date),
+ (type(re.compile('')), encode_regexp),
+ (('fractions', 'Fraction'), encode_rational),
+ (('email.message', 'Message'), encode_mime),
+ (('uuid', 'UUID'), encode_uuid),
+ (CBORSimpleValue, encode_simple_value),
+ (CBORTag, encode_semantic)
+])
+
+
+class CBOREncoder(object):
+ """
+ Serializes objects to a byte stream using Concise Binary Object Representation.
+
+ :param datetime_as_timestamp: set to ``True`` to serialize datetimes as UNIX timestamps
+ (this makes datetimes more concise on the wire but loses the time zone information)
+ :param datetime.tzinfo timezone: the default timezone to use for serializing naive datetimes
+ :param value_sharing: if ``True``, allows more efficient serializing of repeated values and,
+ more importantly, cyclic data structures, at the cost of extra line overhead
+ :param default: a callable that is called by the encoder with three arguments
+ (encoder, value, file object) when no suitable encoder has been found, and should use the
+ methods on the encoder to encode any objects it wants to add to the data stream
+ """
+
+ __slots__ = ('fp', 'datetime_as_timestamp', 'timezone', 'default', 'value_sharing',
+ 'json_compatible', '_shared_containers', '_encoders')
+
+ def __init__(self, fp, datetime_as_timestamp=False, timezone=None, value_sharing=False,
+ default=None):
+ self.fp = fp
+ self.datetime_as_timestamp = datetime_as_timestamp
+ self.timezone = timezone
+ self.value_sharing = value_sharing
+ self.default = default
+ self._shared_containers = {} # indexes used for value sharing
+ self._encoders = default_encoders.copy()
+
+ def _find_encoder(self, obj_type):
+ from sys import modules
+
+ for type_, enc in list(iteritems(self._encoders)):
+ if type(type_) is tuple:
+ modname, typename = type_
+ imported_type = getattr(modules.get(modname), typename, None)
+ if imported_type is not None:
+ del self._encoders[type_]
+ self._encoders[imported_type] = enc
+ type_ = imported_type
+ else: # pragma: nocover
+ continue
+
+ if issubclass(obj_type, type_):
+ self._encoders[obj_type] = enc
+ return enc
+
+ return None
+
+ @contextmanager
+ def disable_value_sharing(self):
+ """Disable value sharing in the encoder for the duration of the context block."""
+ old_value_sharing = self.value_sharing
+ self.value_sharing = False
+ yield
+ self.value_sharing = old_value_sharing
+
+ def write(self, data):
+ """
+ Write bytes to the data stream.
+
+ :param data: the bytes to write
+
+ """
+ self.fp.write(data)
+
+ def encode(self, obj):
+ """
+ Encode the given object using CBOR.
+
+ :param obj: the object to encode
+
+ """
+ obj_type = obj.__class__
+ encoder = self._encoders.get(obj_type) or self._find_encoder(obj_type) or self.default
+ if not encoder:
+ raise CBOREncodeError('cannot serialize type %s' % obj_type.__name__)
+
+ encoder(self, obj)
+
+ def encode_to_bytes(self, obj):
+ """
+ Encode the given object to a byte buffer and return its value as bytes.
+
+ This method was intended to be used from the ``default`` hook when an object needs to be
+ encoded separately from the rest but while still taking advantage of the shared value
+ registry.
+
+ """
+ old_fp = self.fp
+ self.fp = fp = BytesIO()
+ self.encode(obj)
+ self.fp = old_fp
+ return fp.getvalue()
+
+
+def dumps(obj, **kwargs):
+ """
+ Serialize an object to a bytestring.
+
+ :param obj: the object to serialize
+ :param kwargs: keyword arguments passed to :class:`~.CBOREncoder`
+ :return: the serialized output
+ :rtype: bytes
+
+ """
+ fp = BytesIO()
+ dump(obj, fp, **kwargs)
+ return fp.getvalue()
+
+
+def dump(obj, fp, **kwargs):
+ """
+ Serialize an object to a file.
+
+ :param obj: the object to serialize
+ :param fp: a file-like object
+ :param kwargs: keyword arguments passed to :class:`~.CBOREncoder`
+
+ """
+ CBOREncoder(fp, **kwargs).encode(obj)
diff --git a/third_party/python/cbor2/cbor2/types.py b/third_party/python/cbor2/cbor2/types.py
new file mode 100644
index 0000000000..1d3afb0601
--- /dev/null
+++ b/third_party/python/cbor2/cbor2/types.py
@@ -0,0 +1,55 @@
+class CBORTag(object):
+ """
+ Represents a CBOR semantic tag.
+
+ :param int tag: tag number
+ :param value: encapsulated value (any object)
+ """
+
+ __slots__ = 'tag', 'value'
+
+ def __init__(self, tag, value):
+ self.tag = tag
+ self.value = value
+
+ def __eq__(self, other):
+ if isinstance(other, CBORTag):
+ return self.tag == other.tag and self.value == other.value
+ return NotImplemented
+
+ def __repr__(self):
+ return 'CBORTag({self.tag}, {self.value!r})'.format(self=self)
+
+
+class CBORSimpleValue(object):
+ """
+ Represents a CBOR "simple value".
+
+ :param int value: the value (0-255)
+ """
+
+ __slots__ = 'value'
+
+ def __init__(self, value):
+ if value < 0 or value > 255:
+ raise TypeError('simple value too big')
+ self.value = value
+
+ def __eq__(self, other):
+ if isinstance(other, CBORSimpleValue):
+ return self.value == other.value
+ elif isinstance(other, int):
+ return self.value == other
+ return NotImplemented
+
+ def __repr__(self):
+ return 'CBORSimpleValue({self.value})'.format(self=self)
+
+
+class UndefinedType(object):
+ __slots__ = ()
+
+
+#: Represents the "undefined" value.
+undefined = UndefinedType()
+break_marker = object()