o
    'hi                     @  s,  U d Z ddlmZ ddlZddlZddlZddlmZ ddl	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 ddlmZ ddlmZ dd	lmZ dd
lmZ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)m*Z* ddl+m,Z, ddl-m.Z. ddl/m0Z0 e
rddl1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8m9Z9 dZ:G dd dZ;G dd dZ<dDd d!Z=G d"d# d#Z>G d$d% d%Z?G d&d' d'Z@dEd+d,ZAdFd/d0ZBe#eCd1d2gB ZDd3eEd4< d5ZFdGd8d9ZGed:ZHe
rdd;lImJZJ G d<d= d=ZKG d>d? d?ZLG d@dA dAZMG dBdC dCejNZOdS )Ha  Logical sessions for ordering sequential operations.

.. versionadded:: 3.6

Causally Consistent Reads
=========================

.. code-block:: python

  with client.start_session(causal_consistency=True) as session:
      collection = client.db.collection
      collection.update_one({"_id": 1}, {"$set": {"x": 10}}, session=session)
      secondary_c = collection.with_options(read_preference=ReadPreference.SECONDARY)

      # A secondary read waits for replication of the write.
      secondary_c.find_one({"_id": 1}, session=session)

If `causal_consistency` is True (the default), read operations that use
the session are causally after previous read and write operations. Using a
causally consistent session, an application can read its own writes and is
guaranteed monotonic reads, even when reading from replica set secondaries.

.. seealso:: The MongoDB documentation on `causal-consistency <https://dochub.mongodb.org/core/causal-consistency>`_.

.. _transactions-ref:

Transactions
============

.. versionadded:: 3.7

MongoDB 4.0 adds support for transactions on replica set primaries. A
transaction is associated with a :class:`ClientSession`. To start a transaction
on a session, use :meth:`ClientSession.start_transaction` in a with-statement.
Then, execute an operation within the transaction by passing the session to the
operation:

.. code-block:: python

  orders = client.db.orders
  inventory = client.db.inventory
  with client.start_session() as session:
      with session.start_transaction():
          orders.insert_one({"sku": "abc123", "qty": 100}, session=session)
          inventory.update_one(
              {"sku": "abc123", "qty": {"$gte": 100}},
              {"$inc": {"qty": -100}},
              session=session,
          )

Upon normal completion of ``with session.start_transaction()`` block, the
transaction automatically calls :meth:`ClientSession.commit_transaction`.
If the block exits with an exception, the transaction automatically calls
:meth:`ClientSession.abort_transaction`.

In general, multi-document transactions only support read/write (CRUD)
operations on existing collections. However, MongoDB 4.4 adds support for
creating collections and indexes with some limitations, including an
insert operation that would result in the creation of a new collection.
For a complete description of all the supported and unsupported operations
see the `MongoDB server's documentation for transactions
<http://dochub.mongodb.org/core/transactions>`_.

A session may only have a single active transaction at a time, multiple
transactions on the same session can be executed in sequence.

Sharded Transactions
^^^^^^^^^^^^^^^^^^^^

.. versionadded:: 3.9

PyMongo 3.9 adds support for transactions on sharded clusters running MongoDB
>=4.2. Sharded transactions have the same API as replica set transactions.
When running a transaction against a sharded cluster, the session is
pinned to the mongos server selected for the first operation in the
transaction. All subsequent operations that are part of the same transaction
are routed to the same mongos server. When the transaction is completed, by
running either commitTransaction or abortTransaction, the session is unpinned.

.. seealso:: The MongoDB documentation on `transactions <https://dochub.mongodb.org/core/transactions>`_.

.. _snapshot-reads-ref:

Snapshot Reads
==============

.. versionadded:: 3.12

MongoDB 5.0 adds support for snapshot reads. Snapshot reads are requested by
passing the ``snapshot`` option to
:meth:`~pymongo.mongo_client.MongoClient.start_session`.
If ``snapshot`` is True, all read operations that use this session read data
from the same snapshot timestamp. The server chooses the latest
majority-committed snapshot timestamp when executing the first read operation
using the session. Subsequent reads on this session read from the same
snapshot timestamp. Snapshot reads are also supported when reading from
replica set secondaries.

.. code-block:: python

  # Each read using this session reads data from the same point in time.
  with client.start_session(snapshot=True) as session:
      order = orders.find_one({"sku": "abc123"}, session=session)
      inventory = inventory.find_one({"sku": "abc123"}, session=session)

Snapshot Reads Limitations
^^^^^^^^^^^^^^^^^^^^^^^^^^

Snapshot reads sessions are incompatible with ``causal_consistency=True``.
Only the following read operations are supported in a snapshot reads session:

- :meth:`~pymongo.collection.Collection.find`
- :meth:`~pymongo.collection.Collection.find_one`
- :meth:`~pymongo.collection.Collection.aggregate`
- :meth:`~pymongo.collection.Collection.count_documents`
- :meth:`~pymongo.collection.Collection.distinct` (on unsharded collections)

Classes
=======
    )annotationsN)Mapping)
TYPE_CHECKINGAnyCallableContextManagerr   MutableMappingNoReturnOptionalTypeTypeVar)Binary)Int64)	Timestamp)_csot)ConfigurationErrorConnectionFailureInvalidOperationOperationFailurePyMongoErrorWTimeoutError)_RETRYABLE_ERROR_CODES)_Op)ReadConcern)ReadPreference_ServerMode)SERVER_TYPE)_ConnectionManager)WriteConcern)TracebackType)
Connection)Server)ClusterTime_AddressTc                   @  sL   e Zd ZdZ			ddddZedddZedddZedddZdS )SessionOptionsat  Options for a new :class:`ClientSession`.

    :param causal_consistency: If True, read operations are causally
        ordered within the session. Defaults to True when the ``snapshot``
        option is ``False``.
    :param default_transaction_options: The default
        TransactionOptions to use for transactions started on this session.
    :param snapshot: If True, then all reads performed using this
        session will read from the same snapshot. This option is incompatible
        with ``causal_consistency=True``. Defaults to ``False``.

    .. versionchanged:: 3.12
       Added the ``snapshot`` parameter.
    NFcausal_consistencyOptional[bool]default_transaction_optionsOptional[TransactionOptions]snapshotreturnNonec                 C  sX   |r|rt dd}n|d u rd}|| _|d ur$t|ts$td||| _|| _d S )Nz5snapshot reads do not support causal_consistency=TrueFTzgdefault_transaction_options must be an instance of pymongo.client_session.TransactionOptions, not: {!r})r   _causal_consistency
isinstanceTransactionOptions	TypeErrorformat_default_transaction_options	_snapshot)selfr%   r'   r)    r4   ^/var/www/html/olx_land/venv/lib/python3.10/site-packages/pymongo/synchronous/client_session.py__init__   s"   

zSessionOptions.__init__boolc                 C     | j S )z)Whether causal consistency is configured.)r,   r3   r4   r4   r5   r%         z!SessionOptions.causal_consistencyc                 C  r8   )zThe default TransactionOptions to use for transactions started on
        this session.

        .. versionadded:: 3.7
        )r1   r9   r4   r4   r5   r'      s   z*SessionOptions.default_transaction_optionsc                 C  r8   )zOWhether snapshot reads are configured.

        .. versionadded:: 3.12
        )r2   r9   r4   r4   r5   r)         zSessionOptions.snapshot)NNF)r%   r&   r'   r(   r)   r&   r*   r+   r*   r7   )r*   r(   )r*   r&   )	__name__
__module____qualname____doc__r6   propertyr%   r'   r)   r4   r4   r4   r5   r$      s    r$   c                   @  s\   e Zd ZdZ				ddddZedddZedddZedddZedddZ	dS )r.   a  Options for :meth:`ClientSession.start_transaction`.

    :param read_concern: The
        :class:`~pymongo.read_concern.ReadConcern` to use for this transaction.
        If ``None`` (the default) the :attr:`read_preference` of
        the :class:`MongoClient` is used.
    :param write_concern: The
        :class:`~pymongo.write_concern.WriteConcern` to use for this
        transaction. If ``None`` (the default) the :attr:`read_preference` of
        the :class:`MongoClient` is used.
    :param read_preference: The read preference to use. If
        ``None`` (the default) the :attr:`read_preference` of this
        :class:`MongoClient` is used. See :mod:`~pymongo.read_preferences`
        for options. Transactions which read must use
        :attr:`~pymongo.read_preferences.ReadPreference.PRIMARY`.
    :param max_commit_time_ms: The maximum amount of time to allow a
        single commitTransaction command to run. This option is an alias for
        maxTimeMS option on the commitTransaction command. If ``None`` (the
        default) maxTimeMS is not used.

    .. versionchanged:: 3.9
       Added the ``max_commit_time_ms`` option.

    .. versionadded:: 3.7
    Nread_concernOptional[ReadConcern]write_concernOptional[WriteConcern]read_preferenceOptional[_ServerMode]max_commit_time_msOptional[int]r*   r+   c                 C  s   || _ || _|| _|| _|d urt|tstd||d ur6t|ts,td||js6t	d||d urFt|t
sFt|d|d urXt|tsZtdt| d S d S )NzKread_concern must be an instance of pymongo.read_concern.ReadConcern, not: zNwrite_concern must be an instance of pymongo.write_concern.WriteConcern, not: z:transactions do not support unacknowledged write concern: zR is not valid for read_preference. See pymongo.read_preferences for valid options.z3max_commit_time_ms must be an integer or None, not )_read_concern_write_concern_read_preference_max_commit_time_msr-   r   r/   r   acknowledgedr   r   inttype)r3   rB   rD   rF   rH   r4   r4   r5   r6     sH   



zTransactionOptions.__init__c                 C  r8   )z>This transaction's :class:`~pymongo.read_concern.ReadConcern`.)rJ   r9   r4   r4   r5   rB   <  r:   zTransactionOptions.read_concernc                 C  r8   )z@This transaction's :class:`~pymongo.write_concern.WriteConcern`.)rK   r9   r4   r4   r5   rD   A  r:   z TransactionOptions.write_concernc                 C  r8   )zEThis transaction's :class:`~pymongo.read_preferences.ReadPreference`.)rL   r9   r4   r4   r5   rF   F  r:   z"TransactionOptions.read_preferencec                 C  r8   )zfThe maxTimeMS to use when running a commitTransaction command.

        .. versionadded:: 3.9
        )rM   r9   r4   r4   r5   rH   K  r;   z%TransactionOptions.max_commit_time_msNNNN)
rB   rC   rD   rE   rF   rG   rH   rI   r*   r+   )r*   rC   )r*   rE   r*   rG   )r*   rI   )
r=   r>   r?   r@   r6   rA   rB   rD   rF   rH   r4   r4   r4   r5   r.      s    )r.   sessionOptional[ClientSession]rD   rE   r*   c                 C  s.   | r|dur|j s| jrdS td|| S )zValidate that an explicit session is not used with an unack'ed write.

    Returns the session to use for the next operation.
    NzFExplicit sessions are incompatible with unacknowledged write concern: )rN   	_implicitr   )rS   rD   r4   r4   r5   _validate_session_write_concernT  s   rV   c                   @  s.   e Zd ZdZdddZdddZdddZdS )_TransactionContextz;Internal transaction context manager for start_transaction.rS   ClientSessionc                 C  s
   || _ d S N)_TransactionContext__session)r3   rS   r4   r4   r5   r6   o     
z_TransactionContext.__init__r*   c                 C     | S rY   r4   r9   r4   r4   r5   	__enter__r     z_TransactionContext.__enter__exc_typeOptional[Type[BaseException]]exc_valOptional[BaseException]exc_tbOptional[TracebackType]r+   c                 C  s0   | j jr|d u r| j   d S | j   d S d S rY   )rZ   in_transactioncommit_transactionabort_transactionr3   r_   ra   rc   r4   r4   r5   __exit__u  s
   z_TransactionContext.__exit__N)rS   rX   )r*   rW   )r_   r`   ra   rb   rc   rd   r*   r+   )r=   r>   r?   r@   r6   r]   ri   r4   r4   r4   r5   rW   l  s
    

rW   c                   @  s$   e Zd ZdZdZdZdZdZdZdS )	_TxnState                  N)	r=   r>   r?   NONESTARTINGIN_PROGRESS	COMMITTEDCOMMITTED_EMPTYABORTEDr4   r4   r4   r5   rj     s    rj   c                   @  sd   e Zd ZdZdddZd d
dZd ddZed!ddZd"ddZ	d#ddZ
d#ddZd#ddZdS )$_TransactionzBInternal class to hold transaction information in a ClientSession.optsr(   clientMongoClientc                 C  s6   || _ tj| _d| _d | _d | _d | _d| _|| _	d S NFr   )
rx   rj   rq   stateshardedpinned_addressconn_mgrrecovery_tokenattemptry   )r3   rx   ry   r4   r4   r5   r6     s   
z_Transaction.__init__r*   r7   c                 C  s   | j tjtjfv S rY   )r|   rj   rr   rs   r9   r4   r4   r5   active     z_Transaction.activec                 C  s   | j tjkS rY   )r|   rj   rr   r9   r4   r4   r5   starting  s   z_Transaction.startingOptional[Connection]c                 C  s   |   r| jr| jjS d S rY   )r   r   connr9   r4   r4   r5   pinned_conn  s   z_Transaction.pinned_connserverr!   r   r    r+   c                 C  s:   d| _ |jj| _|jjtjkr|  t|d| _	d S d S )NTF)
r}   descriptionaddressr~   server_typer   LoadBalancerpin_txnr   r   r3   r   r   r4   r4   r5   pin  s   
z_Transaction.pinc                 C  s    d | _ | jr| j  d | _d S rY   )r~   r   closer9   r4   r4   r5   unpin  s   

z_Transaction.unpinc                 C  s&   |    tj| _d| _d | _d| _d S r{   )r   rj   rq   r|   r}   r   r   r9   r4   r4   r5   reset  s
   
z_Transaction.resetc                 C  s&   | j r| jdd | j  d | _ d S d S Nr   )r   ry   _close_cursor_soonr9   r4   r4   r5   __del__  s   
z_Transaction.__del__N)rx   r(   ry   rz   r<   r*   r   r   r!   r   r    r*   r+   r*   r+   )r=   r>   r?   r@   r6   r   r   rA   r   r   r   r   r   r4   r4   r4   r5   rw     s    






rw   excr   r	   c                 C  s   |  d  )zDRe-raise an exception with the UnknownTransactionCommitResult label.UnknownTransactionCommitResult)_add_error_labelr   r4   r4   r5   _reraise_with_unknown_commit  s   
r   r   r7   c                 C  s   t | to	| jdkS )z/Return true if exc is a MaxTimeMSExpired error.2   )r-   r   coder   r4   r4   r5   _max_time_expired_error  s   r   @   r   	frozenset_UNKNOWN_COMMIT_ERROR_CODESx   
start_timefloatc                 C  s   t  |  tk S )z/Are we within the with_transaction retry limit?)time	monotonic"_WITH_TRANSACTION_RETRY_TIME_LIMIT)r   r4   r4   r5   _within_time_limit  s   r   _T)rz   c                   @  s  e Zd ZdZdddZdddZdddZdddZdddZdddZ	dddZ
edddZedd d!Zedd#d$Zedd&d'Zedd)d*Zedd,d-Zdd2d3Z	4	4	4	4ddd?d@Z	4	4	4	4dddBdCZddDdEZddFdGZddJdKZddNdOZddRdSZddTdUZddWdXZddZd[Zdd]d^Zedd_d`ZeddadbZeddcddZ eddfdgZ!eddidjZ"ddmdnZ#ddodpZ$ddqdrZ%dddtduZ&ddzd{Z'dd|d}Z(dddZ)dddZ*d4S )rX   a  A session for ordering sequential operations.

    :class:`ClientSession` instances are **not thread-safe or fork-safe**.
    They can only be used by one thread or process at a time. A single
    :class:`ClientSession` cannot be used to run multiple operations
    concurrently.

    Should not be initialized directly by application developers - to create a
    :class:`ClientSession`, call
    :meth:`~pymongo.mongo_client.MongoClient.start_session`.
    ry   rz   server_sessionr   optionsr$   implicitr7   r*   r+   c                 C  s:   || _ || _|| _d | _d | _d | _|| _td || _d S rY   )	_client_server_session_options_cluster_time_operation_time_snapshot_timerU   rw   _transaction)r3   ry   r   r   r   r4   r4   r5   r6     s   zClientSession.__init__c                 C  s   | j dd dS )zFinish this session. If a transaction has started, abort it.

        It is an error to use the session after the session has ended.
        TlockN_end_sessionr9   r4   r4   r5   end_session  s   zClientSession.end_sessionr   c              	   C  sV   | j d ur)z| jr|   |   W | j| j  d | _ d S | j| j  d | _ w d S rY   )r   re   rg   _unpinr   _return_server_session)r3   r   r4   r4   r5   r     s   


zClientSession._end_sessionc                 C  s&   | j d ur| j| j  d | _ d S d S rY   )r   r   r   r9   r4   r4   r5   _end_implicit_session  s   

z#ClientSession._end_implicit_sessionc                 C  s   | j d u r	tdd S )NzCannot use ended session)r   r   r9   r4   r4   r5   _check_ended  s   
zClientSession._check_endedc                 C  r\   rY   r4   r9   r4   r4   r5   r]   "  r^   zClientSession.__enter__r_   ra   rc   c                 C  s   | j dd d S )NTr   r   rh   r4   r4   r5   ri   %  s   zClientSession.__exit__c                 C  r8   )z^The :class:`~pymongo.mongo_client.MongoClient` this session was
        created from.
        )r   r9   r4   r4   r5   ry   (     zClientSession.clientc                 C  r8   )z:The :class:`SessionOptions` this session was created with.)r   r9   r4   r4   r5   r   /  r:   zClientSession.optionsMapping[str, Any]c                 C  s    |    | | jjj | jjS )z6A BSON document, the opaque server session identifier.)r   _materializer   topology_descriptionlogical_session_timeout_minutesr   
session_idr9   r4   r4   r5   r   4  s   zClientSession.session_idr   c                 C  s   |  | jjj | jjS )z=The current transaction id for the underlying server session.)r   r   r   r   r   transaction_idr9   r4   r4   r5   _transaction_id;  s   zClientSession._transaction_idOptional[ClusterTime]c                 C  r8   )zZThe cluster time returned by the last operation executed
        in this session.
        r   r9   r4   r4   r5   cluster_timeA  r   zClientSession.cluster_timeOptional[Timestamp]c                 C  r8   )z\The operation time returned by the last operation executed
        in this session.
        r   r9   r4   r4   r5   operation_timeH  r   zClientSession.operation_timenamestrvalr   c                 C  s2   |r|S | j j}|ot||}|r|S t| j|S )z-Return the inherited TransactionOption value.)r   r'   getattrry   )r3   r   r   txn_opts
parent_valr4   r4   r5   _inherit_optionO  s   zClientSession._inherit_optionNcallbackCallable[[ClientSession], _T]rB   rC   rD   rE   rF   rG   rH   rI   c           	   
   C  s   t  }	 | |||| z|| }W n( ty; } z| jr"|   t|tr6|dr6t	|r6W Y d}~q d}~ww | jsA|S 	 z| 
  W |S  tyx } z#|drdt	|rdt|sdW Y d}~qA|drst	|rsW Y d}~n d}~ww q)a  Execute a callback in a transaction.

        This method starts a transaction on this session, executes ``callback``
        once, and then commits the transaction. For example::

          def callback(session):
              orders = session.client.db.orders
              inventory = session.client.db.inventory
              orders.insert_one({"sku": "abc123", "qty": 100}, session=session)
              inventory.update_one({"sku": "abc123", "qty": {"$gte": 100}},
                                   {"$inc": {"qty": -100}}, session=session)

          with client.start_session() as session:
              session.with_transaction(callback)

        To pass arbitrary arguments to the ``callback``, wrap your callable
        with a ``lambda`` like this::

          def callback(session, custom_arg, custom_kwarg=None):
              # Transaction operations...

          with client.start_session() as session:
              session.with_transaction(
                  lambda s: callback(s, "custom_arg", custom_kwarg=1))

        In the event of an exception, ``with_transaction`` may retry the commit
        or the entire transaction, therefore ``callback`` may be invoked
        multiple times by a single call to ``with_transaction``. Developers
        should be mindful of this possibility when writing a ``callback`` that
        modifies application state or has any other side-effects.
        Note that even when the ``callback`` is invoked multiple times,
        ``with_transaction`` ensures that the transaction will be committed
        at-most-once on the server.

        The ``callback`` should not attempt to start new transactions, but
        should simply run operations meant to be contained within a
        transaction. The ``callback`` should also not commit the transaction;
        this is handled automatically by ``with_transaction``. If the
        ``callback`` does commit or abort the transaction without error,
        however, ``with_transaction`` will return without taking further
        action.

        :class:`ClientSession` instances are **not thread-safe or fork-safe**.
        Consequently, the ``callback`` must not attempt to execute multiple
        operations concurrently.

        When ``callback`` raises an exception, ``with_transaction``
        automatically aborts the current transaction. When ``callback`` or
        :meth:`~ClientSession.commit_transaction` raises an exception that
        includes the ``"TransientTransactionError"`` error label,
        ``with_transaction`` starts a new transaction and re-executes
        the ``callback``.

        When :meth:`~ClientSession.commit_transaction` raises an exception with
        the ``"UnknownTransactionCommitResult"`` error label,
        ``with_transaction`` retries the commit until the result of the
        transaction is known.

        This method will cease retrying after 120 seconds has elapsed. This
        timeout is not configurable and any exception raised by the
        ``callback`` or by :meth:`ClientSession.commit_transaction` after the
        timeout is reached will be re-raised. Applications that desire a
        different timeout duration should not use this method.

        :param callback: The callable ``callback`` to run inside a transaction.
            The callable must accept a single argument, this session. Note,
            under certain error conditions the callback may be run multiple
            times.
        :param read_concern: The
            :class:`~pymongo.read_concern.ReadConcern` to use for this
            transaction.
        :param write_concern: The
            :class:`~pymongo.write_concern.WriteConcern` to use for this
            transaction.
        :param read_preference: The read preference to use for this
            transaction. If ``None`` (the default) the :attr:`read_preference`
            of this :class:`Database` is used. See
            :mod:`~pymongo.read_preferences` for options.

        :return: The return value of the ``callback``.

        .. versionadded:: 3.9
        TTransientTransactionErrorNr   )r   r   start_transactionBaseExceptionre   rg   r-   r   has_error_labelr   rf   r   )	r3   r   rB   rD   rF   rH   r   retr   r4   r4   r5   with_transactionY  sP   [
zClientSession.with_transactionr   c                 C  s   |    | jjrtd| jrtd| d|}| d|}| d|}|du r2| jj}|r2|j}t||||| j	_
| j	  tj| j	_|   t| S )zStart a multi-statement transaction.

        Takes the same arguments as :class:`TransactionOptions`.

        .. versionchanged:: 3.9
           Added the ``max_commit_time_ms`` option.

        .. versionadded:: 3.7
        z3Transactions are not supported in snapshot sessionszTransaction already in progressrB   rD   rF   N)r   r   r)   r   re   r   r'   rH   r.   r   rx   r   rj   rr   r|   _start_retryable_writerW   )r3   rB   rD   rF   rH   rx   r4   r4   r5   r     s&   

zClientSession.start_transactionc              
   C  sZ  |    | jj}|tju rtd|tjtjfv r tj| j_dS |tju r)td|tj	u r3tj
| j_zsz| d W nK tyV } z|d t| W Y d}~n=d}~w tyk } z
t| W Y d}~n0d}~w ty } z|jtvrx t| W Y d}~nd}~ww W tj	| j_dS W tj	| j_dS W tj	| j_dS W tj	| j_dS tj	| j_w )zMCommit a multi-statement transaction.

        .. versionadded:: 3.7
        No transaction startedNz<Cannot call commitTransaction after calling abortTransactioncommitTransactionr   )r   r   r|   rj   rq   r   rr   ru   rv   rt   rs   _finish_transaction_with_retryr   _remove_error_labelr   r   r   r   r   )r3   r|   r   r4   r4   r5   rf     sD   







z ClientSession.commit_transactionc              	   C  s   |    | jj}|tju rtd|tju rtj| j_dS |tju r&td|tjtj	fv r2tdz+z| 
d W n ttfyE   Y nw W tj| j_|   dS W tj| j_|   dS tj| j_|   w )zLAbort a multi-statement transaction.

        .. versionadded:: 3.7
        r   Nz"Cannot call abortTransaction twicez<Cannot call abortTransaction after calling commitTransactionabortTransaction)r   r   r|   rj   rq   r   rr   rv   rt   ru   r   r   r   r   )r3   r|   r4   r4   r5   rg   3  s0   







zClientSession.abort_transactioncommand_namedict[str, Any]c                   s(   d fd	d
}j j|ddtjdS )zRun commit or abort with one retry after any retryable error.

        :param command_name: Either "commitTransaction" or "abortTransaction".
        _sessionrT   r   r    
_retryabler7   r*   r   c                   s    | S rY   )_finish_transaction)r   r   r   r   r3   r4   r5   funcU  s   z:ClientSession._finish_transaction_with_retry.<locals>.funcNT)	retryable	operation)r   rT   r   r    r   r7   r*   r   )r   _retry_internalr   ABORT)r3   r   r   r4   r   r5   r   O  s   z,ClientSession._finish_transaction_with_retryr   r    c                 C  s   | j  jd7  _| j j}|sJ |j}|di}|dkrG|jr)t d u r)|j|d< | j jdkrG|s3J |j}d|d< |dd t	di |}| j j
rQ| j j
|d< | jjj||| |d	d
S )Nrk   r   	maxTimeMSmajoritywwtimeouti'  recoveryTokenT)rS   rD   parse_write_concern_errorr4   )r   r   rx   rD   rH   r   get_timeoutdocument
setdefaultr   r   r   admin_command)r3   r   r   rx   wccmdwc_docr4   r4   r5   r   \  s&   

z!ClientSession._finish_transactionr   Optional[Mapping[str, Any]]c                 C  s@   | j du r
|| _ dS |dur|d | j d kr|| _ dS dS dS )zInternal cluster time helper.NclusterTimer   r3   r   r4   r4   r5   _advance_cluster_timew  s   


z#ClientSession._advance_cluster_timec                 C  sB   t |tstdt| t |dtstd| | dS )zUpdate the cluster time for this session.

        :param cluster_time: The
            :data:`~pymongo.client_session.ClientSession.cluster_time` from
            another `ClientSession` instance.
        z<cluster_time must be a subclass of collections.Mapping, not r   zInvalid cluster_timeN)r-   _Mappingr/   rP   getr   
ValueErrorr   r   r4   r4   r5   advance_cluster_time  s   
z"ClientSession.advance_cluster_timer   c                 C  s8   | j du r
|| _ dS |dur|| j kr|| _ dS dS dS )zInternal operation time helper.Nr   r3   r   r4   r4   r5   _advance_operation_time  s   



z%ClientSession._advance_operation_timer   c                 C  s*   t |tstdt| | | dS )zUpdate the operation time for this session.

        :param operation_time: The
            :data:`~pymongo.client_session.ClientSession.operation_time` from
            another `ClientSession` instance.
        zDoperation_time must be an instance of bson.timestamp.Timestamp, not N)r-   r   r/   rP   r  r  r4   r4   r5   advance_operation_time  s
   
z$ClientSession.advance_operation_timereplyc                 C  s   |  |d | |d | jjr-| jdu r-d|v r%|d d}n|d}|| _| jrA| jjrC|d}|rE|| j_	dS dS dS dS )z?Process a response to a command that was run with this session.z$clusterTimeoperationTimeNcursoratClusterTimer   )
r   r   r  r   r)   r   re   r   r}   r   )r3   r  ctr   r4   r4   r5   _process_response  s   

zClientSession._process_responsec                 C  s
   | j du S )z!True if this session is finished.N)r   r9   r4   r4   r5   	has_ended     
zClientSession.has_endedc                 C  
   | j  S )zhTrue if this session has an active multi-statement transaction.

        .. versionadded:: 3.10
        )r   r   r9   r4   r4   r5   re        
zClientSession.in_transactionc                 C  r  )z?True if this session is starting a multi-statement transaction.)r   r   r9   r4   r4   r5   _starting_transaction  r  z#ClientSession._starting_transactionOptional[_Address]c                 C  s   | j  r	| j jS dS )z3The mongos address this transaction was created on.N)r   r   r~   r9   r4   r4   r5   _pinned_address  s   
zClientSession._pinned_addressr   c                 C  s   | j jS )z/The connection this transaction was started on.)r   r   r9   r4   r4   r5   _pinned_connection  s   z ClientSession._pinned_connectionr   r!   c                 C  s   | j || dS )z@Pin this session to the given Server or to the given connection.N)r   r   r   r4   r4   r5   _pin  s   zClientSession._pinc                 C  s   | j   dS )z*Unpin this session from any pinned Server.N)r   r   r9   r4   r4   r5   r     s   zClientSession._unpinc                 C  s    | j r| jjs	J | jjjS dS )z3Return read preference of this transaction or None.N)re   r   rx   rF   r9   r4   r4   r5   _txn_read_preference  s   
z"ClientSession._txn_read_preferencer   c                 C  s>   t | jtr| j}| jj|| _|jr| j  d S d S d S rY   )r-   r   _EmptyServerSessionr   	_topologyget_server_sessionstarted_retryable_writeinc_transaction_id)r3   r   oldr4   r4   r5   r     s   zClientSession._materializecommandMutableMapping[str, Any]is_retryabler   c                 C  s   |j s| js
tdd S |   | |j | jjr | || t	
 | j_| jj|d< |r6| jj|d< d S | jr~|tjkrEtd|| jjtjkrrtj| j_d|d< | jjs[J | jjjrl| jjjj}|rl||d< | || | jj|d< d|d	< d S d S )
Nz5Sessions are not supported by this MongoDB deploymentlsid	txnNumberz7read preference in a transaction must be primary, not: TstartTransactionreadConcernF
autocommit)supports_sessionsrU   r   r   r   r   r   r)   _update_read_concernr   r   r   last_user   r   re   r   PRIMARYr   r   r|   rj   rr   rs   rx   rB   r   )r3   r  r  rF   r   rcr4   r4   r5   	_apply_to  s<   


zClientSession._apply_toc                 C  s   |    | j  d S rY   )r   r   r  r9   r4   r4   r5   r     s   z$ClientSession._start_retryable_writer   c                 C  sr   | j jr| jd ur| j|di d< | j jr5|jdk rtd|di }d|d< | jd ur7| j|d< d S d S d S )Nr"  afterClusterTime   z+Snapshot reads require MongoDB 5.0 or laterr)   levelr	  )r   r%   r   r   r)   max_wire_versionr   r   )r3   r   r   r(  r4   r4   r5   r%    s   

z"ClientSession._update_read_concernr	   c                 C  s   t d)Nz>A ClientSession cannot be copied, create a new session instead)r/   r9   r4   r4   r5   __copy__#  s   zClientSession.__copy__)
ry   rz   r   r   r   r$   r   r7   r*   r+   r   )r   r7   r*   r+   )r*   rX   )r_   r   ra   r   rc   r   r*   r+   )r*   rz   )r*   r$   )r*   r   r*   r   )r*   r   )r*   r   )r   r   r   r   r*   r   rQ   )r   r   rB   rC   rD   rE   rF   rG   rH   rI   r*   r   )
rB   rC   rD   rE   rF   rG   rH   rI   r*   r   )r   r   r*   r   )r   r    r   r   r*   r   )r   r   r*   r+   )r   r   r*   r+   )r   r   r*   r+   )r   r   r*   r+   )r  r   r*   r+   r<   )r*   r  r   r   rR   rY   )r   rI   r*   r+   )
r  r  r  r7   rF   r   r   r    r*   r+   )r   r  r   r    r*   r+   )r*   r	   )+r=   r>   r?   r@   r6   r   r   r   r   r]   ri   rA   ry   r   r   r   r   r   r   r   r   rf   rg   r   r   r   r  r  r  r  r  re   r  r  r  r  r   r  r   r)  r   r%  r.  r4   r4   r4   r5   rX     sx    







 

(
+










	
,
rX   c                   @  s.   e Zd ZdZdddZdddZddd	Zd
S )r  dirtyr  r*   r+   c                 C  s   d| _ d| _d S )NFr0  r9   r4   r4   r5   r6   *  s   
z_EmptyServerSession.__init__c                 C  
   d| _ d S NTr1  r9   r4   r4   r5   
mark_dirty.  r[   z_EmptyServerSession.mark_dirtyc                 C  r2  r3  )r  r9   r4   r4   r5   r  1  r[   z&_EmptyServerSession.inc_transaction_idNr   )r=   r>   r?   	__slots__r6   r5  r  r4   r4   r4   r5   r  '  s
    

r  c                   @  sB   e Zd ZdddZdddZdddZedddZdddZdS )_ServerSession
generationrO   c                 C  s6   dt t jdi| _t | _d| _d| _	|| _
d S )Nidrn   r   F)r   uuiduuid4bytesr   r   r   r&  r   r1  r8  )r3   r8  r4   r4   r5   r6   6  s
   

z_ServerSession.__init__r*   r+   c                 C  s
   d| _ dS )zMark this session as dirty.

        A server session is marked dirty when a command fails with a network
        error. Dirty sessions are later discarded from the server session pool.
        TNr4  r9   r4   r4   r5   r5  >  r  z_ServerSession.mark_dirtysession_timeout_minutesrI   r7   c                 C  s*   |d u rdS t  | j }||d d kS )NFrk   <   )r   r   r&  )r3   r=  idle_secondsr4   r4   r5   	timed_outF  s   z_ServerSession.timed_outr   c                 C  s
   t | jS )zPositive 64-bit integer.)r   r   r9   r4   r4   r5   r   O  r  z_ServerSession.transaction_idc                 C  s   |  j d7  _ d S Nrk   )r   r9   r4   r4   r5   r  T  r   z!_ServerSession.inc_transaction_idN)r8  rO   r   )r=  rI   r*   r7   r/  )	r=   r>   r?   r6   r5  r@  rA   r   r  r4   r4   r4   r5   r7  5  s    


	r7  c                      sT   e Zd ZdZd fddZdd	d
ZdddZdddZdddZdddZ	  Z
S )_ServerSessionPoolzDPool of _ServerSession objects.

    This class is thread-safe.
    argsr   kwargsc                   s   t  j|i | d| _d S r   )superr6   r8  )r3   rC  rD  	__class__r4   r5   r6   ^  s   
z_ServerSessionPool.__init__r*   r+   c                 C  s   |  j d7  _ |   d S rA  )r8  clearr9   r4   r4   r5   r   b  s   z_ServerSessionPool.resetlist[_ServerSession]c                 C  s2   g }	 z
| |  j W n
 ty   Y |S w qrY   )appendpopr   
IndexError)r3   idsr4   r4   r5   pop_allf  s   z_ServerSessionPool.pop_allr=  rI   r7  c                 C  sF   |  | 	 z|  }W n	 ty   Y n	w ||s|S qt| jS rY   )_clear_stalepopleftrL  r@  r7  r8  r3   r=  sr4   r4   r5   r  o  s   


z%_ServerSessionPool.get_server_sessionr   c                 C  s(   |j | j kr|js| | d S d S d S rY   )r8  r1  
appendleft)r3   r   r4   r4   r5   return_server_session  s   z(_ServerSessionPool.return_server_sessionc                 C  s>   	 z|   }W n
 ty   Y d S w ||s| | d S qrY   )rK  rL  r@  rJ  rQ  r4   r4   r5   rO    s   

z_ServerSessionPool._clear_stale)rC  r   rD  r   r   )r*   rI  )r=  rI   r*   r7  )r   r7  r*   r+   )r=  rI   r*   r+   )r=   r>   r?   r@   r6   r   rN  r  rT  rO  __classcell__r4   r4   rF  r5   rB  X  s    


	
rB  )rS   rT   rD   rE   r*   rT   )r   r   r*   r	   )r   r   r*   r7   )r   r   r*   r7   )Pr@   
__future__r   collectionsr   r:  collections.abcr   r   typingr   r   r   r   r   r	   r
   r   r   bson.binaryr   
bson.int64r   bson.timestampr   pymongor   pymongo.errorsr   r   r   r   r   r   pymongo.helpers_sharedr   pymongo.operationsr   pymongo.read_concernr   pymongo.read_preferencesr   r   pymongo.server_typer   pymongo.synchronous.cursorr   pymongo.write_concernr   typesr   pymongo.synchronous.poolr    pymongo.synchronous.serverr!   pymongo.typingsr"   r#   _IS_SYNCr$   r.   rV   rW   rj   rw   r   r   r   r   __annotations__r   r   r    pymongo.synchronous.mongo_clientrz   rX   r  r7  dequerB  r4   r4   r4   r5   <module>   sf   y0 ?
\	
5

    E#