U
    ~fhd                  (   @  s  U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
mZmZmZmZmZmZmZmZmZmZ ddlmZmZmZmZ ddlmZ ddlmZmZ ddlm Z m!Z!m"Z"m#Z#m$Z$ dd	l%m&Z& dd
l'm(Z( ddl)m*Z* ddl+m,Z, ddl-m.Z. ddl/m0Z0 ddl1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8 ej9ej:ej;ej<ej=ej>dZ?G dd dZ@G dd dZAe
reeeBef  ZCneZCdZDG dd deCZEeEeAjFdZGdeHd< eEeAjIdZJdeHd< eEeAjKdZLdeHd< eLZMdeHd< d d d d!d"d#d$ZNd%d d d d&d'd(ZOeMfd dd d)d*d+ZPeMfd,dd d-d.d/ZQeMfd0dd d1d2d3ZRd d d d4d5d6ZSd dd7d8d9d:ZTd d;dd7d<d=d>ZUd dd7d8d?d@ZVd dd7d8dAdBZWd ddCd8dDdEZXd d dFd4dGdHZYd d d!d4dIdJZZd d dKd4dLdMZ[d d dNd4dOdPZ\d d d d4dQdRZ]d d d d4dSdTZ^d d d;d4dUdVZ_d d dWd4dXdYZ`d d dZd4d[d\Zad d d]d4d^d_Zbd d d`d4dadbZcd d dcd4dddeZdd dd7d8dfdgZed d dhd4didjZfeYe]eXeSecedeee[eTdkdl e`efebe^e\eZe_eadmZgdneHdo< ehegZidpd;dd d<dqdrZjd ddsd)dtduZkdKddsd)dvdwZldWdd d)dxdyZmd d d dzd{d|Znd ddsd)d}d~Zod;dd d)ddZpdZdd d)ddZqdddsd)ddZrdpddsd)ddZsdddsd)ddZtdddsd)ddZudFd dsdzddZvdhd dsdzddZwdhd dsdzddZxdddsd)ddZyd d dsdddZzd d dsdddZ{e|ene}esejere"eke~eqeepeBenedenejeueete*emeele&eye,e{e.eze0eve2eoe4eoe6ewe(exiZdeHd< i ZdeHd< eD ] Zeedree eej< qedd eD ZeMfd dd d)ddZd d;dddZdd;dddZdd;dddZdd;dddZe0dede*de(de6de.de,diZdeHd< eBee}eejee2ee&eiZdeHd< dd d;d;d;dddZd d;ddddZd d;ddddZdS )aO  Tools for using Python's :mod:`json` module with BSON documents.

This module provides two helper methods `dumps` and `loads` that wrap the
native :mod:`json` methods and provide explicit BSON conversion to and from
JSON. :class:`~bson.json_util.JSONOptions` provides a way to control how JSON
is emitted and parsed, with the default being the Relaxed Extended JSON format.
:mod:`~bson.json_util` can also generate Canonical or legacy `Extended JSON`_
when :const:`CANONICAL_JSON_OPTIONS` or :const:`LEGACY_JSON_OPTIONS` is
provided, respectively.

.. _Extended JSON: https://github.com/mongodb/specifications/blob/master/source/extended-json.rst

Example usage (deserialization):

.. doctest::

   >>> from bson.json_util import loads
   >>> loads(
   ...     '[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$scope": {}, "$code": "function x() { return 1; }"}}, {"bin": {"$type": "80", "$binary": "AQIDBA=="}}]'
   ... )
   [{'foo': [1, 2]}, {'bar': {'hello': 'world'}}, {'code': Code('function x() { return 1; }', {})}, {'bin': Binary(b'...', 128)}]

Example usage with :const:`RELAXED_JSON_OPTIONS` (the default):

.. doctest::

   >>> from bson import Binary, Code
   >>> from bson.json_util import dumps
   >>> dumps(
   ...     [
   ...         {"foo": [1, 2]},
   ...         {"bar": {"hello": "world"}},
   ...         {"code": Code("function x() { return 1; }")},
   ...         {"bin": Binary(b"")},
   ...     ]
   ... )
   '[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}}, {"bin": {"$binary": {"base64": "AQIDBA==", "subType": "00"}}}]'

Example usage (with :const:`CANONICAL_JSON_OPTIONS`):

.. doctest::

   >>> from bson import Binary, Code
   >>> from bson.json_util import dumps, CANONICAL_JSON_OPTIONS
   >>> dumps(
   ...     [
   ...         {"foo": [1, 2]},
   ...         {"bar": {"hello": "world"}},
   ...         {"code": Code("function x() { return 1; }")},
   ...         {"bin": Binary(b"")},
   ...     ],
   ...     json_options=CANONICAL_JSON_OPTIONS,
   ... )
   '[{"foo": [{"$numberInt": "1"}, {"$numberInt": "2"}]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}}, {"bin": {"$binary": {"base64": "AQIDBA==", "subType": "00"}}}]'

Example usage (with :const:`LEGACY_JSON_OPTIONS`):

.. doctest::

   >>> from bson import Binary, Code
   >>> from bson.json_util import dumps, LEGACY_JSON_OPTIONS
   >>> dumps(
   ...     [
   ...         {"foo": [1, 2]},
   ...         {"bar": {"hello": "world"}},
   ...         {"code": Code("function x() { return 1; }", {})},
   ...         {"bin": Binary(b"")},
   ...     ],
   ...     json_options=LEGACY_JSON_OPTIONS,
   ... )
   '[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }", "$scope": {}}}, {"bin": {"$binary": "AQIDBA==", "$type": "00"}}]'

Alternatively, you can manually pass the `default` to :func:`json.dumps`.
It won't handle :class:`~bson.binary.Binary` and :class:`~bson.code.Code`
instances (as they are extended strings you can't provide custom defaults),
but it will be faster as there is less recursion.

.. note::
   If your application does not need the flexibility offered by
   :class:`JSONOptions` and spends a large amount of time in the `json_util`
   module, look to
   `python-bsonjs <https://pypi.python.org/pypi/python-bsonjs>`_ for a nice
   performance improvement. `python-bsonjs` is a fast BSON to MongoDB
   Extended JSON converter for Python built on top of
   `libbson <https://github.com/mongodb/libbson>`_. `python-bsonjs` works best
   with PyMongo when using :class:`~bson.raw_bson.RawBSONDocument`.
    )annotationsN)TYPE_CHECKINGAnyCallableMappingMutableMappingOptionalSequenceTupleTypeUnioncast)ALL_UUID_SUBTYPESUUID_SUBTYPEBinaryUuidRepresentation)Code)CodecOptionsDatetimeConversion)_MAX_UTC_MSEPOCH_AWARE
DatetimeMS_datetime_to_millis_millis_to_datetime)DBRef)
Decimal128)Int64)MaxKey)MinKey)ObjectId)Regex)RE_TYPE	Timestamp)utc)ilmsuxc                   @  s   e Zd ZdZdZdZdS )DatetimeRepresentationr         N)__name__
__module____qualname__LEGACY
NUMBERLONGISO8601 r4   r4   2/tmp/pip-unpacked-wheel-36gvocj8/bson/json_util.pyr+      s   r+   c                   @  s   e Zd ZdZdZdZdS )JSONModer   r,   r-   N)r.   r/   r0   r1   RELAXED	CANONICALr4   r4   r4   r5   r6      s   r6   l        c                
      s   e Zd ZU ded< ded< ded< ded< ded< d	d	d
 fddZdddejfdddddd	d	d d fddZdd fddZdd fddZ	d	d dddZ
  ZS )JSONOptionsint	json_modeboolstrict_number_longdatetime_representationstrict_uuidzType[MutableMapping[str, Any]]document_classr   )argskwargsc                   s   t    dS )a  Encapsulates JSON options for :func:`dumps` and :func:`loads`.

        :param strict_number_long: If ``True``, :class:`~bson.int64.Int64` objects
            are encoded to MongoDB Extended JSON's *Strict mode* type
            `NumberLong`, ie ``'{"$numberLong": "<number>" }'``. Otherwise they
            will be encoded as an `int`. Defaults to ``False``.
        :param datetime_representation: The representation to use when encoding
            instances of :class:`datetime.datetime`. Defaults to
            :const:`~DatetimeRepresentation.LEGACY`.
        :param strict_uuid: If ``True``, :class:`uuid.UUID` object are encoded to
            MongoDB Extended JSON's *Strict mode* type `Binary`. Otherwise it
            will be encoded as ``'{"$uuid": "<hex>" }'``. Defaults to ``False``.
        :param json_mode: The :class:`JSONMode` to use when encoding BSON types to
            Extended JSON. Defaults to :const:`~JSONMode.LEGACY`.
        :param document_class: BSON documents returned by :func:`loads` will be
            decoded to an instance of this class. Must be a subclass of
            :class:`collections.MutableMapping`. Defaults to :class:`dict`.
        :param uuid_representation: The :class:`~bson.binary.UuidRepresentation`
            to use when encoding and decoding instances of :class:`uuid.UUID`.
            Defaults to :const:`~bson.binary.UuidRepresentation.UNSPECIFIED`.
        :param tz_aware: If ``True``, MongoDB Extended JSON's *Strict mode* type
            `Date` will be decoded to timezone aware instances of
            :class:`datetime.datetime`. Otherwise they will be naive. Defaults
            to ``False``.
        :param tzinfo: A :class:`datetime.tzinfo` subclass that specifies the
            timezone from which :class:`~datetime.datetime` objects should be
            decoded. Defaults to :const:`~bson.tz_util.utc`.
        :param datetime_conversion: Specifies how UTC datetimes should be decoded
            within BSON. Valid options include 'datetime_ms' to return as a
            DatetimeMS, 'datetime' to return as a datetime.datetime and
            raising a ValueError for out-of-range values, 'datetime_auto' to
            return DatetimeMS objects when the underlying datetime is
            out-of-range and 'datetime_clamp' to clamp to the minimum and
            maximum possible datetimes. Defaults to 'datetime'. See
            :ref:`handling-out-of-range-datetimes` for details.
        :param args: arguments to :class:`~bson.codec_options.CodecOptions`
        :param kwargs: arguments to :class:`~bson.codec_options.CodecOptions`

        .. seealso:: The specification for Relaxed and Canonical `Extended JSON`_.

        .. versionchanged:: 4.0
           The default for `json_mode` was changed from :const:`JSONMode.LEGACY`
           to :const:`JSONMode.RELAXED`.
           The default for `uuid_representation` was changed from
           :const:`~bson.binary.UuidRepresentation.PYTHON_LEGACY` to
           :const:`~bson.binary.UuidRepresentation.UNSPECIFIED`.

        .. versionchanged:: 3.5
           Accepts the optional parameter `json_mode`.

        .. versionchanged:: 4.0
           Changed default value of `tz_aware` to False.
        N)super__init__)selfrA   rB   	__class__r4   r5   rD      s    6zJSONOptions.__init__NzType[JSONOptions]zOptional[bool]zOptional[int])clsr=   r>   r?   r;   rA   rB   returnc                   s|  | dd|d< |d r(| dt|d< |tjtjtjd fkrFtdttt	 j
| f||}|tjtjtjfkr|td||_|jtjkr|rtd|d tjfkrtd|dkrtd	d|_tj|_d
|_n|jtjkr4|dkrtd|d tjfkrtd|dkrtd	d
|_tj|_d
|_nDd|_tj|_d|_|d k	rX||_|d k	rh||_|d k	rx||_|S )Ntz_awareFtzinfoznJSONOptions.datetime_representation must be one of LEGACY, NUMBERLONG, or ISO8601 from DatetimeRepresentation.zQJSONOptions.json_mode must be one of LEGACY, RELAXED, or CANONICAL from JSONMode.z<Cannot specify strict_number_long=True with JSONMode.RELAXEDz_datetime_representation must be DatetimeRepresentation.ISO8601 or omitted with JSONMode.RELAXED)NTz6Cannot specify strict_uuid=False with JSONMode.RELAXEDTz=Cannot specify strict_number_long=False with JSONMode.RELAXEDzbdatetime_representation must be DatetimeRepresentation.NUMBERLONG or omitted with JSONMode.RELAXED)getr$   r+   r1   r2   r3   
ValueErrorr   r9   rC   __new__r6   r7   r8   r;   r=   r>   r?   )rH   r=   r>   r?   r;   rA   rB   rE   rF   r4   r5   rN   1  sh    	



zJSONOptions.__new__str)rI   c                   s    d | j| j| j| jt  S )Nz[strict_number_long={!r}, datetime_representation={!r}, strict_uuid={!r}, json_mode={!r}, {})formatr=   r>   r?   r;   rC   _arguments_repr)rE   rF   r4   r5   rQ   t  s    zJSONOptions._arguments_reprzdict[Any, Any]c                   s*   t   }|| j| j| j| jd |S )Nr=   r>   r?   r;   )rC   _options_dictupdater=   r>   r?   r;   )rE   Zoptions_dictrF   r4   r5   rS     s    
zJSONOptions._options_dict)rB   rI   c                 K  s<   |   }dD ]}||t| |||< q|| tf |S )a  
        Make a copy of this JSONOptions, overriding some options::

            >>> from bson.json_util import CANONICAL_JSON_OPTIONS
            >>> CANONICAL_JSON_OPTIONS.tz_aware
            True
            >>> json_options = CANONICAL_JSON_OPTIONS.with_options(tz_aware=False, tzinfo=None)
            >>> json_options.tz_aware
            False

        .. versionadded:: 3.12
        rR   )rS   rL   getattrrT   r9   )rE   rB   optsoptr4   r4   r5   with_options  s
    
zJSONOptions.with_options)r.   r/   r0   __annotations__rD   r6   r7   rN   rQ   rS   rX   __classcell__r4   r4   rF   r5   r9      s   
:"Cr9   )r;   LEGACY_JSON_OPTIONSCANONICAL_JSON_OPTIONSRELAXED_JSON_OPTIONSDEFAULT_JSON_OPTIONSr   rO   )objrA   rB   rI   c                 O  s$   | dt}tjt| |f||S )aQ  Helper function that wraps :func:`json.dumps`.

    Recursive function that handles all BSON types including
    :class:`~bson.binary.Binary` and :class:`~bson.code.Code`.

    :param json_options: A :class:`JSONOptions` instance used to modify the
        encoding of MongoDB Extended JSON types. Defaults to
        :const:`DEFAULT_JSON_OPTIONS`.

    .. versionchanged:: 4.0
       Now outputs MongoDB Relaxed Extended JSON by default (using
       :const:`DEFAULT_JSON_OPTIONS`).

    .. versionchanged:: 3.4
       Accepts optional parameter `json_options`. See :class:`JSONOptions`.
    json_options)popr^   jsondumps_json_convert)r_   rA   rB   r`   r4   r4   r5   rc     s    rc   zUnion[str, bytes, bytearray])r(   rA   rB   rI   c                   sJ   | dt  jtkr( fdd|d< n fdd|d< tj| f||S )a  Helper function that wraps :func:`json.loads`.

    Automatically passes the object_hook for BSON type conversion.

    Raises ``TypeError``, ``ValueError``, ``KeyError``, or
    :exc:`~bson.errors.InvalidId` on invalid MongoDB Extended JSON.

    :param json_options: A :class:`JSONOptions` instance used to modify the
        decoding of MongoDB Extended JSON types. Defaults to
        :const:`DEFAULT_JSON_OPTIONS`.

    .. versionchanged:: 4.0
       Now loads :class:`datetime.datetime` instances as naive by default. To
       load timezone aware instances utilize the `json_options` parameter.
       See :ref:`tz_aware_default_change` for an example.

    .. versionchanged:: 3.5
       Parses Relaxed and Canonical Extended JSON as well as PyMongo's legacy
       format. Now raises ``TypeError`` or ``ValueError`` when parsing JSON
       type wrappers with values of the wrong type or any extra keys.

    .. versionchanged:: 3.4
       Accepts optional parameter `json_options`. See :class:`JSONOptions`.
    r`   c                   s
   t |  S N)object_hookr_   r`   r4   r5   <lambda>      zloads.<locals>.<lambda>rf   c                   s
   t |  S re   )object_pairs_hook)pairsrh   r4   r5   ri     rj   rk   )ra   r^   r@   dictrb   loads)r(   rA   rB   r4   rh   r5   rn     s
    
rn   )r_   r`   rI   c                   st   t | dr  fdd|  D S t | drJt| ttfsJ fdd| D S zt|  W S  tk
rn   |  Y S X dS )z]Recursive helper method that converts BSON types so they can be
    converted into json.
    itemsc                   s   i | ]\}}|t | qS r4   rd   ).0kvrh   r4   r5   
<dictcomp>  s      z!_json_convert.<locals>.<dictcomp>__iter__c                   s   g | ]}t | qS r4   rp   )rq   rs   rh   r4   r5   
<listcomp>  s     z!_json_convert.<locals>.<listcomp>N)hasattrro   
isinstancerO   bytesdefault	TypeErrorr_   r`   r4   rh   r5   rd     s    
rd   zSequence[Tuple[str, Any]])rl   r`   rI   c                 C  s   t || |S re   )rf   r@   )rl   r`   r4   r4   r5   rk     s    rk   zMapping[str, Any])dctr`   rI   c                 C  s4   d }| D ]}|t kr|} qq|r0t| | |S | S re   )_PARSERS_SET_PARSERS)r}   r`   matchrr   r4   r4   r5   rf     s    rf   )docdummy0rI   c                 C  sJ   | d }t |ttfs| S d}| ddD ]}|t|dO }q*t||S )N$regexr   $options )rx   rO   ry   rL   _RE_OPT_TABLEr    )r   r   patternflagsrW   r4   r4   r5   _parse_legacy_regex  s    r   zUnion[Binary, uuid.UUID])r   r`   rI   c                 C  sh   t | dkrtd|  t| d ts6td|  |jtjkrVtt	
| d S t	
| d S dS )z*Decode a JSON legacy $uuid to Python UUID.r,   zBad $uuid, extra field(s): $uuidz$uuid must be a string: N)lenr{   rx   rO   uuid_representationr   UNSPECIFIEDr   	from_uuiduuidUUIDr   r`   r4   r4   r5   _parse_legacy_uuid)  s    r   r:   )datasubtyper`   rI   c                 C  sn   |t krP|j}t| |}|tjkr&|S |tkr6tj}n|tjkrFtj}||S |dkrdt	t
j| S t| |S Nr   )r   r   r   r   r   r   ZSTANDARDZPYTHON_LEGACYZas_uuidr   r   r   )r   r   r`   r   Zbinary_valuer4   r4   r5   _binary_or_uuid5  s    



r   c                 C  sh   t | d trd| d  | d< t| d d}|dkrJt| d dd  d}t| d  }t|||S )N$type%02x   l       $binary)rx   r:   base64	b64decodeencoder   )r   r`   r   r   r4   r4   r5   _parse_legacy_binaryJ  s    r   c                 C  s   | d }|d }|d }t |ts0td|  t |trFt|dkrTtd|  t|dkrntd|  t| }t|t|d|S )	Nr   r   subTypez!$binary base64 must be a string: r-   z7$binary subType must be a string at most 2 characters: z=$binary must include only "base64" and "subType" components: r   )	rx   rO   r{   r   r   r   r   r   r:   )r   r`   binaryZb64r   r   r4   r4   r5   _parse_canonical_binaryT  s    
r   z$Union[datetime.datetime, DatetimeMS]c                 C  sd  | d }t | dkr"td|  t|trP|d dkrL|dd }d}n|d dkr~|d	 d
kr~|dd }|dd }nT|d dkr|dd }|dd }n.|d	 dkr|dd	 }|d	d }n|}d}|d}d}|dkrtt||d d }|d| }tj|dj	|t
d}|r|dkrt |dkrt|dd d
\}}	t|d t|	d  }
nZt |dkrt|dd d t|dd d  }
n"t |dkrt|dd d }
|d dkr|
d9 }
|tj|
d }|jr*|jr||j}|jtjkr&t|S |S |j	dd}|jtjkrLt|S |S tt|td|S )z3Decode a JSON datetime to python datetime.datetime.$dater,   zBad $date, extra field(s): ZNi)+-:r   .r   i@B %Y-%m-%dT%H:%M:%S)microsecondrK   r   i  <         r   )secondsrK   zCodecOptions[Any])r   r{   rx   rO   rfindr:   floatdatetimestrptimereplacer$   split	timedeltarJ   rK   
astimezoneZdatetime_conversionr   ZDATETIME_MSr   r   r   )r   r`   ZdtmdtoffsetZ	dot_indexr   ZawarehoursminutesZsecsZaware_tzinfo_noner4   r4   r5   _parse_canonical_datetimec  sb    

 *r   r   c                 C  s&   t | dkrtd|  t| d S )z1Decode a JSON ObjectId to bson.objectid.ObjectId.r,   zBad $oid, extra field(s): $oid)r   r{   r   r   r   r4   r4   r5   _parse_canonical_oid  s    r   c                 C  s*   | d }t | dkr"td|  t|S )z&Decode a JSON symbol to Python string.$symbolr,   zBad $symbol, extra field(s): )r   r{   rO   )r   r   symbolr4   r4   r5   _parse_canonical_symbol  s    r   r   c                 C  s6   | D ]}|dkrt d|  qt| d | ddS )z%Decode a JSON code to bson.code.Code.$code$scopezBad $code, extra field(s): r   r   )scope)r{   r   rL   )r   r   keyr4   r4   r5   _parse_canonical_code  s    r   z
Regex[str]c                 C  sl   | d }t | dkr"td|  t |dkr<td|  |d }t|ts^tdt| t|d |S )	z(Decode a JSON regex to bson.regex.Regex.$regularExpressionr,   z(Bad $regularExpression, extra field(s): r-   zLBad $regularExpression must include only "pattern and "options" components: optionszCBad $regularExpression options, options must be string, was type %sr   )r   r{   rx   rO   typer    )r   r   regexrV   r4   r4   r5   _parse_canonical_regex  s    

r   c                 C  s^   t | dtrZd| krZt | dttdfrZt| d| dfd| ddi| S | S )z(Decode a JSON DBRef to bson.dbref.DBRef.$refz$idz$dbNdatabase)rx   rL   rO   r   r   ra   r   r4   r4   r5   _parse_canonical_dbref  s    *r   c                 C  s   | d }t | dkr"td|  t|tr| }|jdk	rLtd| t|jtsftd| t |dkrtd| |S td	|  dS )
z9Decode a JSON (deprecated) DBPointer to bson.dbref.DBRef.
$dbPointerr,   z Bad $dbPointer, extra field(s): Nz!Bad $dbPointer, extra field $db: z)Bad $dbPointer, $id must be an ObjectId: r-   z)Bad $dbPointer, extra field(s) in DBRef: z"Bad $dbPointer, expected a DBRef: )r   r{   rx   r   as_docr   idr   )r   r   ZdbrefZ	dbref_docr4   r4   r5   _parse_canonical_dbpointer  s    

r   c                 C  sB   | d }t | dkr"td|  t|ts:td|  t|S )z"Decode a JSON int32 to python int.
$numberIntr,   z Bad $numberInt, extra field(s): z$numberInt must be string: )r   r{   rx   rO   r:   )r   r   Zi_strr4   r4   r5   _parse_canonical_int32  s    
r   r   c                 C  s*   | d }t | dkr"td|  t|S )z(Decode a JSON int64 to bson.int64.Int64.$numberLongr,   z!Bad $numberLong, extra field(s): )r   r{   r   )r   r   Zl_strr4   r4   r5   _parse_canonical_int64  s    r   r   c                 C  sB   | d }t | dkr"td|  t|ts:td|  t|S )z%Decode a JSON double to python float.$numberDoubler,   z#Bad $numberDouble, extra field(s): z$numberDouble must be string: )r   r{   rx   rO   r   r   r   Zd_strr4   r4   r5   _parse_canonical_double  s    
r   r   c                 C  sB   | d }t | dkr"td|  t|ts:td|  t|S )z7Decode a JSON decimal128 to bson.decimal128.Decimal128.$numberDecimalr,   z$Bad $numberDecimal, extra field(s): z$numberDecimal must be string: )r   r{   rx   rO   r   r   r4   r4   r5   _parse_canonical_decimal128  s    
r   r   c                 C  sJ   t | d tk	s| d dkr*td|  t| dkrDtd|  t S )z,Decode a JSON MinKey to bson.min_key.MinKey.$minKeyr,   z$minKey value must be 1: Bad $minKey, extra field(s): )r   r:   r{   r   r   r   r4   r4   r5   _parse_canonical_minkey  s
    r   r   c                 C  sH   t | d tk	s| d dkr(td| ft| dkrBtd|  t S )z,Decode a JSON MaxKey to bson.max_key.MaxKey.$maxKeyr,   z$maxKey value must be 1: %sr   )r   r:   r{   r   r   r   r4   r4   r5   _parse_canonical_maxkey  s
    r   c                 C  s    d| krt | |S t| |S d S )Nr   )r   r   r   r4   r4   r5   _parse_binary#  s    
r   r#   c                 C  s   | d }t |d |d S )N
$timestamptr%   r"   )r   r   Ztspr4   r4   r5   _parse_timestamp*  s    r   c                 C  s   d S re   r4   )_Z_1r4   r4   r5   ri   9  rj   ri   )r   r   r   r   r   r   r   r   r   z
$undefinedr   r   r   r   r   r   r   r   z,dict[str, Callable[[Any, JSONOptions], Any]]r   ry   c                 C  s@   |j tjkr$t|  d| dS dt|  d| diS )Nr   )r   r   r   )r   r   )r;   r6   r1   r   	b64encodedecode)r   r   r`   r4   r4   r5   _encode_binaryF  s    r   rm   c                 C  sf   |j tjkr6dt|   kr$tkr6n nt|  |S |j tjkrRdtt| iS ddtt| iiS )Nr   r   r   )	r>   r+   r3   r:   r   _encode_datetimeZas_datetimer1   rO   r|   r4   r4   r5   _encode_datetimemsL  s    
 
r   c                 C  s0   | j d krdt| iS t| t| j |dS d S )Nr   r   )r   rO   rd   r|   r4   r4   r5   _encode_codeW  s    
r   c                 C  s   |j rdt| iS t| S d S )Nr   )r=   rO   r:   r|   r4   r4   r5   _encode_int64^  s    r   )r_   r   rI   c                 C  s   | S re   r4   r_   r   r4   r4   r5   _encode_noope  s    r   c                 C  s   d}| j tj@ r|d7 }| j tj@ r,|d7 }| j tj@ r@|d7 }| j tj@ rT|d7 }| j tj@ rh|d7 }| j tj@ r||d7 }t| j	t
r| j	}n| j	d}|jtjkr||d	S d
||diS )Nr   r%   r&   r'   r(   r)   r*   zutf-8)r   r   r   )r   r   )r   re
IGNORECASELOCALE	MULTILINEDOTALLUNICODEVERBOSErx   r   rO   r   r;   r6   r1   )r_   r`   r   r   r4   r4   r5   _encode_regexi  s&    
r   c                 C  sB   |j tjkr>t |   kr"tk r2n ndt| iS dt| iS | S )Nr   r   )r;   r6   r8   
_INT32_MAXrO   r|   r4   r4   r5   _encode_int  s
    r   c                 C  s`   |j tjkr\t| rddiS t| r@| dkr4dnd}d|iS |j tjkr\dtt| iS | S )Nr   NaNr   Infinityz	-Infinity)	r;   r6   r1   mathisnanisinfr8   rO   repr)r_   r`   Zrepresentationr4   r4   r5   _encode_float  s    

r  zdatetime.datetimec                 C  s   |j tjkr| js,| jtd} | jd k	s,t| tkr| j| }|j	|j
|jfdkrZd}n
| d}t| jd }|rd|f nd}dd	| d
||iS t| }|j tjkrd|iS ddt|iiS )Nr   )r   r   r   r   z%zi  z.%03dr   r   z{}{}{}r   r   )r>   r+   r3   rK   r   r$   AssertionErrorr   	utcoffsetdaysr   microsecondsstrftimer:   r   rP   r   r1   rO   )r_   r`   offZ	tz_stringZmillisZfracsecsr4   r4   r5   r     s$    
 r   c                 C  s   t | d|S r   )r   r|   r4   r4   r5   _encode_bytes  s    r  r   c                 C  s   t | | j|S re   )r   r   r|   r4   r4   r5   _encode_binary_obj  s    r  z	uuid.UUIDc                 C  s2   |j r$tj| |jd}t||j|S d| jiS d S )N)r   r   )r?   r   r   r   r   r   hex)r_   r`   Zbinvalr4   r4   r5   _encode_uuid  s    r  c                 C  s   dt | iS )Nr   rO   r   r4   r4   r5   _encode_objectid  s    r  c                 C  s   d| j | jdiS )Nr   )r   r%   )timeincr   r4   r4   r5   _encode_timestamp  s    r  c                 C  s   dt | iS )Nr   r  r   r4   r4   r5   _encode_decimal128  s    r  r   c                 C  s   t |  |dS )Nrh   )rd   r   r|   r4   r4   r5   _encode_dbref  s    r  )r   dummy1rI   c                 C  s   ddiS )Nr   r,   r4   r   r  r4   r4   r5   _encode_minkey  s    r  c                 C  s   ddiS )Nr   r,   r4   r  r4   r4   r5   _encode_maxkey  s    r  z-dict[Type, Callable[[Any, JSONOptions], Any]]	_ENCODERSz,dict[int, Callable[[Any, JSONOptions], Any]]_MARKERS_type_markerc                 c  s   | ]
}|V  qd S re   r4   )rq   r   r4   r4   r5   	<genexpr>  s     r  c                 C  s   zt t|  | |W S  tk
r(   Y nX t| dr`| j}|tkr`t| }|t t| < || |S tD ]0}t| |rdt | }|t t| < || |  S qdtd|  d S )Nr  z%r is not JSON serializable)	r  r   KeyErrorrw   r  r  _BUILT_IN_TYPESrx   r{   )r_   r`   markerfuncbaser4   r4   r5   rz     s     


rz   )r_   rI   c                 C  s   t | S re   )r   rg   r4   r4   r5   _get_str_size  s    r#  c                 C  s   dt t|   S )Nr   )r   rO   r  rg   r4   r4   r5   _get_datetime_size  s    r$  r    c                 C  s   dt | j S )N   )r   r   rg   r4   r4   r5   _get_regex_size   s    r&  c                 C  s   dt | j S )N"   )r   Z
collectionrg   r4   r4   r5   _get_dbref_size$  s    r(              zdict[Any, int]_CONSTANT_SIZE_TABLEzdict[Any, Callable[[Any], int]]_VARIABLE_SIZE_TABLE)r_   max_sizecurrent_sizerI   c                 C  s,  ||kr|S t | }z
t| W S  tk
r2   Y nX zt| | W S  tk
rV   Y nX |tkr| jr|dt| j|| t|  t| j 7 }n|dt|  7 }n|tkr| 	 D ]8\}}|t|||7 }|t|||7 }||kr|  S qn:t
| dr(| D ](}|t|||7 }||k r|  S  q|S )z!Recursively finds size of objectsr   ru   )r   r-  r  r.  r   r   get_sizer   rm   ro   rw   )r_   r/  r0  Zobj_typerr   rs   r%   r4   r4   r5   r1  ;  s:    
"
r1  zTuple[Any, int])r_   
max_lengthrI   c                 C  s   |dkrdS |}t | dr^i }|  D ].\}}t||\}}|rH|||< |dkr& qVq&||fS t | drt| ttfsg }| D ],}t||\}}|r|| |dkr~ qq~||fS t| |S dS )zMRecursively truncate documents as needed to fit inside max_length characters.r   r   ro   ru   N)rw   ro   _truncate_documentsrx   rO   ry   append	_truncate)r_   r2  	remaining	truncatedrr   rs   Ztruncated_vr4   r4   r5   r3  d  s,    

r3  )r_   r6  rI   c                 C  sX   t | |}||kr| || fS z| d | }W n tk
rF   | }Y nX ||| fS d S re   )r1  r{   )r_   r6  sizer7  r4   r4   r5   r5    s    

r5  )r   )__doc__
__future__r   r   r   rb   r   r   r   typingr   r   r   r   r   r   r	   r
   r   r   r   Zbson.binaryr   r   r   r   Z	bson.coder   Zbson.codec_optionsr   r   Zbson.datetime_msr   r   r   r   r   Z
bson.dbrefr   Zbson.decimal128r   Z
bson.int64r   Zbson.max_keyr   Zbson.min_keyr   Zbson.objectidr   Z
bson.regexr    Zbson.sonr!   Zbson.timestampr#   Zbson.tz_utilr$   ILMSUXr   r+   r6   rO   Z_BASE_CLASSr   r9   r1   r[   rY   r8   r\   r7   r]   r^   rc   rn   rd   rk   rf   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   setr~   r   r   r   r   r   r   r   r  r   r  r  r  r  r  r  r  r  r  r<   ry   r   r:   r   r   r  r  Z_typrw   r  tupler  rz   r#  r$  r&  r(  r-  r.  r1  r3  r5  r4   r4   r4   r5   <module>   sr  W4
$+ 1"
B


			                                	)