U
    ~fh                     @  s,  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	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 ddlmZmZ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!m"Z" ddl#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/m0Z0m1Z1 ddl2m3Z3m4Z4m5Z5m6Z6m7Z7 ddl8m9Z9 ddl:m;Z; ddl<m=Z=m>Z>m?Z?m@Z@mAZA ddlBmCZCmDZDmEZEmFZFmGZG erddlHmIZI ddlJmKZK ddlLmMZMmNZN dZOePeeQjRZSdddddZTG dd dZUG dd  d ZVd!d!dd"d#d$ZWd%d%dd&d'd(ZXd.d)d*d)d+d,d-ZYdS )/z<Internal class to monitor a topology of one or more servers.    )annotationsN)Path)TYPE_CHECKINGAnyCallableMappingOptionalcast)_csotcommonhelpers_shared)periodic_executor)_ServerSession_ServerSessionPool)
SrvMonitor)Pool)Server)ConnectionFailureInvalidOperationNetworkTimeoutNotPrimaryErrorOperationFailurePyMongoErrorServerSelectionTimeoutError
WriteError)Hello)_ACondition_ALock_create_lock)_SDAM_LOGGER_SERVER_SELECTION_LOGGER
_debug_log_SDAMStatusMessage_ServerSelectionStatusMessage)PoolOptions)ServerDescription)	Selectionany_server_selectorarbiter_server_selectorsecondary_server_selectorwritable_server_selector)SRV_POLLING_TOPOLOGIESTOPOLOGY_TYPETopologyDescription)_updated_topology_description_srv_pollingupdated_topology_description)ObjectId)TopologySettings)ClusterTime_AddressFz"weakref.ReferenceType[queue.Queue]bool)	queue_refreturnc                 C  sL   |  }|sdS z|  }W n tjk
r4   Y qHY qX |\}}||  qdS )NFT)
get_nowaitqueueEmpty)r5   qeventfnargs r>   A/tmp/pip-unpacked-wheel-36gvocj8/pymongo/asynchronous/topology.pyprocess_events_queueR   s    

r@   c                	   @  s  e Zd ZdZddddZdddd	Zd
dddZddddddddddZdd
dddddddZdddddddddddZ	dddddddddd d!Z
dd"ddddd#d$d%Zdd'd(d(dd)d*d+Zdd'd(d(dd)d,d-Zd.dd/d0d1Zd.dd/d2d3Zd"d4d5d6d7Zd"d(d5d8d9Zddd:d;Zdd<d=d>d?Zd<dd@dAZd<ddBdCZdDddEdFZdGddHdIdJZdGddHdKdLZddNddOdPdQZdddRdSZdddTdUZdddVdWZedXddYdZZd[dd\d]Zdd^d_d`daZ d^ddbdcddZ!deddfdgZ"dddhdiZ#d"djd(dkdldmZ$d"djddkdndoZ%d"djddkdpdqZ&dddrdsZ'dddtduZ(d"dvd5dwdxZ)d"dvd5dydzZ*ddd=d{d|Z+ddd}d~Z,ddddZ-dd(dddZ.dNdddZ/dS )Topologyz*Monitor a topology of one or more servers.r1   )topology_settingsc                   s  |j | _ |jj| _| jd k	o"| jj| _| jd k	o6| jj| _d | _d | _	| jsR| jr`t
jdd| _ttjr~tt| j tjd | jr| jd k	st| j| jj| j ff || _t| | |jd d |}|| _ttji d d d | j}| jr| jd k	st| j| jj|| j| j ff ttjrBtt| j || jtjd |j D ]d}| jr~| jd k	sdt| j| jj!|| j ff ttjrHtt| j |d |d tj"d qHt#|$ | _%d| _&d| _'t( }t)|| _*t+| j,|| _-i | _.d | _/d | _0t1 | _2| js| jrj| jd k	s$td	d
 fdd}t3j4t5j6t5j7|dd}t89| j|j: || _	|;  d | _<| jj=d k	r| jj>st?| | j| _<d S )Nd   )maxsize
topologyIdmessagerF   ZpreviousDescriptionZnewDescriptionrG   r      )rF   
serverHost
serverPortrG   Fr4   r6   c                     s   t  S N)r@   r>   weakr>   r?   target   s    z!Topology.__init__.<locals>.targetZpymongo_events_thread)intervalZmin_intervalrP   name)@_topology_idZ_pool_options_event_listeners
_listenersZenabled_for_server_publish_serverZenabled_for_topology_publish_tp_events_Topology__events_executorr8   Queuer   isEnabledForloggingDEBUGr!   r"   ZSTART_TOPOLOGYAssertionErrorputZpublish_topology_opened	_settingsr-   Zget_topology_typeZget_server_descriptionsreplica_set_name_descriptionr,   Unknown$publish_topology_description_changedTOPOLOGY_CHANGEseedsZpublish_server_openedZSTART_SERVERlistserver_descriptions_seed_addresses_opened_closedr   r   _lockr   Zcondition_class
_condition_servers_pid_max_cluster_timer   _session_poolr   ZPeriodicExecutorr   ZEVENTS_QUEUE_FREQUENCYMIN_HEARTBEAT_INTERVALweakrefrefcloseopen_srv_monitorfqdnload_balancedr   )selfrB   Ztopology_descriptionZ
initial_tdseedrl   rP   executorr>   rN   r?   __init__f   s    
	     

	

zTopology.__init__NonerL   c              
     s   t  }| jdkr|| _n|| jkr|| _tjdd dkrHdtfi}nddi}tjd| | j4 I dH . | j	
 D ]}| I dH  qv| j  W 5 Q I dH R X | j4 I dH  |  I dH  W 5 Q I dH R X dS )	a  Start monitoring, or restart after a fork.

        No effect if called multiple times.

        .. warning:: Topology is shared among multiple threads and is protected
          by mutual exclusion. Using Topology from a process other than the one
          that initialized it will emit a warning and may result in deadlock. To
          prevent this from happening, AsyncMongoClient must be created after any
          forking.

        N   )      Zskip_file_prefixes
stacklevel   AsyncMongoClient opened before fork. May not be entirely fork-safe, proceed with caution. See PyMongo's documentation for details: https://www.mongodb.com/docs/languages/python/pymongo-driver/current/faq/#is-pymongo-fork-safe-)r   )osgetpidro   sysversion_info_pymongo_dirwarningswarnrl   rn   valuesru   rq   reset_ensure_opened)rz   pidkwargsserverr>   r>   r?   rv      s&    

 zTopology.openfloatc                 C  s   t  }|d kr| jjS |S rM   )r
   	remainingr`   server_selection_timeout)rz   timeoutr>   r>   r?   get_server_selection_timeout   s    z%Topology.get_server_selection_timeoutNz Callable[[Selection], Selection]strzOptional[float]zOptional[_Address]zOptional[int]list[Server])selector	operationr   addressoperation_idr6   c                   sr   |dkr   }n|} j4 I dH >  |||||I dH } fdd|D W  5 Q I dH R  S Q I dH R X dS )a  Return a list of Servers matching selector, or time out.

        :param selector: function that takes a list of Servers and returns
            a subset of them.
        :param operation: The name of the operation that the server is being selected for.
        :param server_selection_timeout: maximum seconds to wait.
            If not provided, the default value common.SERVER_SELECTION_TIMEOUT
            is used.
        :param address: optional server address to select.

        Calls self.open() if needed.

        Raises exc:`ServerSelectionTimeoutError` after
        `server_selection_timeout` if no matching servers are found.
        Nc                   s   g | ]}t t |jqS r>   )r	   r   get_server_by_addressr   .0sdrz   r>   r?   
<listcomp>  s    z+Topology.select_servers.<locals>.<listcomp>)r   rl   _select_servers_loop)rz   r   r   r   r   r   Zserver_timeoutrh   r>   r   r?   select_servers   s    
    

zTopology.select_serverszlist[ServerDescription])r   r   r   r   r   r6   c           
        sX  t  }|| }d}ttjr@tttj|||| j	| j	j
jd | jj||| jjd}	|	sJ|dksl||krttjrtttj|||| j	| j	j
j| |d t| | d| d| j	|stttj|||| j	| j	j
jt|t   d d	}|  I d
H  |   | jtjI d
H  | j  t  }| jj||| jjd}	qV| j  |	S )z7select_servers() guts. Hold the lock when calling this.F)rG   r   r   operationIdtopologyDescriptionclientId)Zcustom_selectorr   )rG   r   r   r   r   r   Zfailurez, Timeout: zs, Topology Description: )rG   r   r   r   r   r   ZremainingTimeMSTN)time	monotonicr    r[   r\   r]   r!   r#   ZSTARTEDdescription_topology_settingsrS   rb   Zapply_selectorr`   Zserver_selectorZFAILED_error_messager   ZWAITINGintr   _request_check_allrm   waitr   rr   Zcheck_compatible)
rz   r   r   r   r   r   nowZend_timeZlogged_waitingrh   r>   r>   r?   r   #  st    	
  


  
zTopology._select_servers_loopOptional[list[Server]]r   )r   r   r   r   deprioritized_serversr   r6   c           
        sb   |  |||||I d H }t||}t|dkr6|d S t|d\}}	|jj|	jjkrZ|S |	S d S )NrI   r   r   )r   _filter_serverslenrandomsamplepoolZoperation_count)
rz   r   r   r   r   r   r   serversZserver1Zserver2r>   r>   r?   _select_servero  s    	    

zTopology._select_serverc                   sv   | j ||||||dI dH }t r2t|jj ttj	rrt
ttj|||| j| jjj|jjd |jjd d	 |S )zALike select_servers, but choose a random server if several match.r   Nr   rI   )rG   r   r   r   r   r   rJ   rK   )r   r
   Zget_timeoutZset_rttr   Zmin_round_trip_timer    r[   r\   r]   r!   r#   Z	SUCCEEDEDr   rS   r   )rz   r   r   r   r   r   r   r   r>   r>   r?   select_server  s.    


zTopology.select_serverr3   )r   r   r   r   r6   c                   s   | j t||||dI dH S )a=  Return a Server for "address", reconnecting if necessary.

        If the server's type is not known, request an immediate check of all
        servers. Time out after "server_selection_timeout" if the server
        cannot be reached.

        :param address: A (host, port) pair.
        :param operation: The name of the operation that the server is being selected for.
        :param server_selection_timeout: maximum seconds to wait.
            If not provided, the default value
            common.SERVER_SELECTION_TIMEOUT is used.
        :param operation_id: The unique id of the current operation being performed. Defaults to None if not provided.

        Calls self.open() if needed.

        Raises exc:`ServerSelectionTimeoutError` after
        `server_selection_timeout` if no matching servers are found.
        r   N)r   r'   )rz   r   r   r   r   r>   r>   r?   select_server_by_address  s    z!Topology.select_server_by_addressFr%   r4   )server_description
reset_poolinterrupt_connectionsr6   c           	        s  | j }|j|j }t||r dS t| j |}|jsD|jrf|jtj	krf| j
|j}|rf|j I dH  ||k}| jr|s| jdk	st| j| jj|||j| jff || _ |  I dH  | |j | jr|s| jdk	st| j| jj|| j | jff ttjr(|s(tt| j|| j tj d | j!r\|jtj"kr\| j jt#kr\| j!$ I dH  |r| j
|j}|r|jj%|dI dH  | j&'  dS )ziProcess a new ServerDescription on an opened topology.

        Hold the lock when calling this.
        NrH   )r   )(rb   Z_server_descriptionsr   _is_stale_server_descriptionr/   Zis_readableZis_server_type_knowntopology_typer,   Singlern   getr   readyrV   rX   r^   r_   rU   Z"publish_server_description_changedrS   _update_servers_receive_cluster_time_no_lockcluster_timerW   rd   r   r[   r\   r]   r!   r"   re   rw   rc   r+   ru   r   rm   
notify_all)	rz   r   r   r   td_oldZsd_oldZnew_tdr   Zsuppress_eventr>   r>   r?   _process_change  sd    






zTopology._process_changec              
     sL   | j 4 I dH . | jr8| j|jr8| |||I dH  W 5 Q I dH R X dS )z>Process a new ServerDescription after an hello call completes.N)rl   rj   rb   
has_serverr   r   )rz   r   r   r   r>   r>   r?   	on_change  s    	zTopology.on_changezlist[tuple[str, Any]])seedlistr6   c                   s   | j }|jtkrdS t| j || _ |  I dH  | jrb| jdk	sDt| j| j	j
|| j | jff ttjrtt| j|| j tjd dS )z_Process a new seedlist on an opened topology.
        Hold the lock when calling this.
        NrH   )rb   r   r+   r.   r   rW   rX   r^   r_   rU   rd   rS   r   r[   r\   r]   r!   r"   re   )rz   r   r   r>   r>   r?   _process_srv_update%  s(    
zTopology._process_srv_updatec              
     s:   | j 4 I dH  | jr&| |I dH  W 5 Q I dH R X dS )z?Process a new list of nodes obtained from scanning SRV records.N)rl   rj   r   )rz   r   r>   r>   r?   on_srv_updateA  s    zTopology.on_srv_updatezOptional[Server])r   r6   c                 C  s   | j |S )aJ  Get a Server or None.

        Returns the current version of the server immediately, even if it's
        Unknown or absent from the topology. Only use this in unittests.
        In driver code, use select_server_by_address, since then you're
        assured a recent view of the server's type and wire protocol version.
        )rn   r   rz   r   r>   r>   r?   r   H  s    zTopology.get_server_by_addressc                 C  s
   || j kS rM   )rn   r   r>   r>   r?   r   R  s    zTopology.has_serverc                   sj   | j 4 I dH L | jj}|tjkr6W 5 Q I dH R  dS t|  d jW  5 Q I dH R  S Q I dH R X dS )z!Return primary's address or None.Nr   )rl   rb   r   r,   ReplicaSetWithPrimaryr*   _new_selectionr   )rz   r   r>   r>   r?   get_primaryU  s
    
zTopology.get_primaryzset[_Address])r   r6   c                   s|   | j 4 I dH ^ | jj}|tjtjfkr@t W  5 Q I dH R  S dd t||  D W  5 Q I dH R  S Q I dH R X dS )z+Return set of replica set member addresses.Nc                 S  s   h | ]
}|j qS r>   )r   r   r>   r>   r?   	<setcomp>l  s     z4Topology._get_replica_set_members.<locals>.<setcomp>)	rl   rb   r   r,   r   ReplicaSetNoPrimarysetiterr   )rz   r   r   r>   r>   r?   _get_replica_set_members_  s    z!Topology._get_replica_set_membersc                   s   |  tI dH S )z"Return set of secondary addresses.N)r   r)   r   r>   r>   r?   get_secondariesn  s    zTopology.get_secondariesc                   s   |  tI dH S )z Return set of arbiter addresses.N)r   r(   r   r>   r>   r?   get_arbitersr  s    zTopology.get_arbiterszOptional[ClusterTime]c                 C  s   | j S )z1Return a document, the highest seen $clusterTime.rp   r   r>   r>   r?   max_cluster_timev  s    zTopology.max_cluster_timeOptional[Mapping[str, Any]])r   r6   c                 C  s&   |r"| j r|d | j d kr"|| _ d S )NZclusterTimer   rz   r   r>   r>   r?   r   z  s    z&Topology._receive_cluster_time_no_lockc              
     s.   | j 4 I d H  | | W 5 Q I d H R X d S rM   )rl   r   r   r>   r>   r?   receive_cluster_time  s    zTopology.receive_cluster_time   r   )	wait_timer6   c              
     s>   | j 4 I dH   |   | j|I dH  W 5 Q I dH R X dS )z=Wake all monitors, wait for at least one to check its server.N)rl   r   rm   r   )rz   r   r>   r>   r?   request_check_all  s    zTopology.request_check_allc                 C  s   | j jtjkr| j jS | j jS )z~Return a list of all data-bearing servers.

        This includes any server that might be selected for an operation.
        )rb   r   r,   r   known_serversZreadable_serversr   r>   r>   r?   data_bearing_servers  s    zTopology.data_bearing_serversc                   s   g }| j 4 I d H 6 |  D ]&}| j|j }|||jj f qW 5 Q I d H R X |D ]j\}}z|j|I d H  W qX t	k
r } z,t
|d|dd }| |jj|I d H   W 5 d }~X Y qXX qXd S )Nr   F)rl   r   rn   r   appendr   genZget_overallZremove_stale_socketsr   _ErrorContexthandle_errorr   )rz   r   r   r   Z
generationexcctxr>   r>   r?   update_pool  s    (zTopology.update_poolc              
     s  | j 4 I dH  | j}| j D ]}| I dH  q | j | _| j  D ]\}}|| jkrN|| j| _qN| j	r| j	 I dH  d| _
d| _W 5 Q I dH R X | jr| jdk	stttji | jj| jj| jj| jj| _| j| jj|| j| jff | j| jj| jff ttjrJtt| j|| jt j!d tt| jt j"d | j#sZ| jr| j$  | j$%d t&t'(| j dS )zClear pools and terminate monitors. Topology does not reopen on
        demand. Any further operations will raise
        :exc:`~.errors.InvalidOperation`.
        NFTrH   rE   rI   ))rl   rb   rn   r   ru   r   rh   itemsr   rw   rj   rk   rW   rX   r^   r-   r,   rc   ra   Zmax_set_versionZmax_election_idr   r_   rU   rd   rS   Zpublish_topology_closedr   r[   r\   r]   r!   r"   re   ZSTOP_TOPOLOGYrV   rY   joinr@   rs   rt   )rz   Zold_tdr   r   r   r>   r>   r?   ru     s`    

  
zTopology.closer-   c                 C  s   | j S rM   )rb   r   r>   r>   r?   r     s    zTopology.descriptionzlist[_ServerSession]c                 C  s
   | j  S )z"Pop all session ids from the pool.)rq   pop_allr   r>   r>   r?   pop_all_sessions  s    zTopology.pop_all_sessionsr   )session_timeout_minutesr6   c                 C  s   | j |S )z>Start or resume a server session, or raise ConfigurationError.)rq   get_server_session)rz   r   r>   r>   r?   r     s    zTopology.get_server_session)server_sessionr6   c                 C  s   | j | d S rM   )rq   return_server_session)rz   r   r>   r>   r?   r     s    zTopology.return_server_sessionr&   c                 C  s   t | jS )zmA Selection object, initially including all known servers.

        Hold the lock when calling this.
        )r&   Zfrom_topology_descriptionrb   r   r>   r>   r?   r     s    zTopology._new_selectionc              	     s   | j rtd| jsd| _|  I dH  | js4| jr>| j  | jrZ| j	j
tkrZ| j  | jjr| t| jd td| jddI dH  | j D ]}| I dH  qdS )z[Start monitors, or restart after a fork.

        Hold the lock when calling this.
        z'Cannot use AsyncMongoClient after closeTNr   rI      )okZ	serviceIdZmaxWireVersion)rk   r   rj   r   rW   rV   rY   rv   rw   r   r   r+   r`   ry   r   r%   ri   r   rS   rn   r   rz   r   r>   r>   r?   r     s$    


zTopology._ensure_openedr   )r   err_ctxr6   c                 C  sp   | j |}|d krdS |j|j|jr.dS |jj}|j}d }|rft	|drft
|jtrf|jd}t||S )NTdetailsZtopologyVersion)rn   r   _poolZstale_generationsock_generation
service_idr   topology_versionerrorhasattr
isinstancer   dict _is_stale_error_topology_version)rz   r   r   r   Zcur_tvr   error_tvr>   r>   r?   _is_stale_error#  s    zTopology._is_stale_errorc           	        s  |  ||rd S | j| }|j}|j}| jjr<|s<|js<d S t|trP|jrPd S t|t	r^d S t|t
tfr:t|dr|j}n t|t
rdnd }|jd|}|tjk r|tjk}| jjs| t||dI d H  |s|jdkr||I d H  |  n:|js| jjs(| t||dI d H  ||I d H  nHt|tr| jjsh| t||dI d H  ||I d H  |j  d S )Ncodei{'  r      )r  rn   r   r   r`   ry   completed_handshaker   r   r   r   r   r   r  r   r   r   Z_NOT_PRIMARY_CODESZ_SHUTDOWN_CODESr   r%   max_wire_versionr   request_checkr   _monitorZcancel_check)	rz   r   r   r   r   r   Zerr_codedefaultZis_shutting_downr>   r>   r?   _handle_error7  s@    

	




zTopology._handle_errorc              
     s6   | j 4 I dH  | ||I dH  W 5 Q I dH R X dS )zHandle an application error.

        May reset the server to Unknown, clear the pool, and request an
        immediate check depending on the error and the context.
        N)rl   r  )rz   r   r   r>   r>   r?   r   y  s    zTopology.handle_errorc                 C  s   | j  D ]}|  q
dS )z3Wake all monitors. Hold the lock when calling this.N)rn   r   r	  r   r>   r>   r?   r     s    zTopology._request_check_allc              	     s  | j   D ]\}}|| jkr| jj|| | || jd}d}| jr\| jdk	r\t	
| j}t|| ||| j| j|d}|| j|< | I dH  q| j| jj}|| j| _||jkr| j| j|jI dH  qt| j D ].\}}| j |s| I dH  | j| qdS )zrSync our Servers from TopologyDescription.server_descriptions.

        Hold the lock while calling this.
        )r   Ztopologyr   rB   N)r   r   monitorZtopology_idZ	listenersevents)rb   rh   r   rn   r`   Zmonitor_class_create_pool_for_monitorrV   rX   rs   rt   r   _create_pool_for_serverrS   rU   rv   r   is_writabler   Zupdate_is_writablerg   r   ru   pop)rz   r   r   r  rO   r   Zwas_writabler>   r>   r?   r     s:    
	

zTopology._update_serversr   c                 C  s   | j j|| j j| jdS )N)	client_id)r`   
pool_classpool_optionsrS   r   r>   r>   r?   r    s
      z Topology._create_pool_for_serverc                 C  sH   | j j}t|j|j|j|j|j|j|jd|j	d	}| j j
||d| jdS )NF)	connect_timeoutsocket_timeoutssl_contexttls_allow_invalid_hostnamesZevent_listenersappnamedriverZpause_enabled
server_api)Z	handshaker  )r`   r  r$   r  Z_ssl_contextr  rT   r  r  r  r  rS   )rz   r   optionsZmonitor_pool_optionsr>   r>   r?   r    s$       z!Topology._create_pool_for_monitorc                   s*  | j jtjtjfk}|rd}n| j jtjkr2d}nd}| j jrl|tkrX|rNdS d| S nd| d| dS nt| j 	 }t| j 	 
 }|s|rd	|| jjS d
| S |d j t fdd|dd D }|r dkrd| S |r
t|| js
d| S t S ddd |D S dS )zeFormat an error message if server selection fails.

        Hold the lock when calling this.
        zreplica set membersZmongosesr   zNo primary available for writeszNo %s available for writeszNo z match selector ""z)No {} available for replica set name "{}"zNo %s availabler   c                 3  s   | ]}|j  kV  qd S rM   r  r   r   r  r>   r?   	<genexpr>  s     z*Topology._error_message.<locals>.<genexpr>rI   NzNo %s found yetz\Could not reach any servers in %s. Replica set is configured with internal hostnames or IPs?,c                 s  s   | ]}|j rt|j V  qd S rM   )r   r   r  r>   r>   r?   r     s      )rb   r   r,   r   r   ZShardedr   r*   rg   rh   r   formatr`   ra   r   allr   intersectionri   r   r   )rz   r   Zis_replica_setZserver_plural	addressesr   Zsamer>   r  r?   r     sH    

zTopology._error_messagec                 C  s*   d}| j sd}d| jj d| | jdS )N zCLOSED < >)rj   	__class____name__rb   )rz   msgr>   r>   r?   __repr__  s    zTopology.__repr__z>tuple[tuple[_Address, ...], Optional[str], Optional[str], str]c                 C  s"   | j }tt|j|j|j|jfS )zDThe properties to use for AsyncMongoClient/Topology equality checks.)r`   tuplesortedrf   ra   rx   Zsrv_service_name)rz   tsr>   r>   r?   eq_props  s    zTopology.eq_propsobject)otherr6   c                 C  s    t || jr|  | kS tS rM   )r   r*  r1  NotImplemented)rz   r3  r>   r>   r?   __eq__  s    zTopology.__eq__c                 C  s   t |  S rM   )hashr1  r   r>   r>   r?   __hash__  s    zTopology.__hash__)NNN)NNNN)NNNN)NN)FF)FF)r   )0r+  
__module____qualname____doc__r}   rv   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ru   propertyr   r   r   r   r   r   r  r  r   r   r   r  r  r   r-  r1  r5  r7  r>   r>   r>   r?   rA   c   s|   h)   %P        &  $  M  

	?!B	*:rA   c                   @  s&   e Zd ZdZddddddddZd	S )
r   z.An error with context for SDAM error handling.BaseExceptionr   r4   zOptional[ObjectId]r   r  r   r  r   c                 C  s"   || _ || _|| _|| _|| _d S rM   r=  )rz   r   r  r   r  r   r>   r>   r?   r}     s
    z_ErrorContext.__init__N)r+  r8  r9  r:  r}   r>   r>   r>   r?   r     s   r   r   )
current_tvr  r6   c                 C  s8   | dks|dkrdS | d |d kr(dS | d |d kS )z9Return True if the error's topologyVersion is <= current.NF	processIdcounterr>   )r>  r  r>   r>   r?   r  ,  s
    r  r%   )
current_sdnew_sdr6   c                 C  sF   | j |j  }}|dks|dkr"dS |d |d kr6dS |d |d kS )z4Return True if the new topologyVersion is < current.NFr?  r@  )r   )rA  rB  r>  Znew_tvr>   r>   r?   r   7  s    r   r   r   )
candidatesr   r6   c                   s"    s| S  fdd| D }|p | S )zBFilter out deprioritized servers from a list of server candidates.c                   s   g | ]}| kr|qS r>   r>   r  r   r>   r?   r   H  s      z#_filter_servers.<locals>.<listcomp>r>   )rC  r   filteredr>   rD  r?   r   A  s    r   )N)Zr:  
__future__r   r\   r   r8   r   r   r   r   rs   pathlibr   typingr   r   r   r   r   r	   Zpymongor
   r   r   Zpymongo.asynchronousr   Z#pymongo.asynchronous.client_sessionr   r   Zpymongo.asynchronous.monitorr   Zpymongo.asynchronous.poolr   Zpymongo.asynchronous.serverr   Zpymongo.errorsr   r   r   r   r   r   r   r   Zpymongo.hellor   Zpymongo.lockr   r   r   Zpymongo.loggerr   r    r!   r"   r#   Zpymongo.pool_optionsr$   Zpymongo.server_descriptionr%   Zpymongo.server_selectorsr&   r'   r(   r)   r*   Zpymongo.topology_descriptionr+   r,   r-   r.   r/   Zbsonr0   Zpymongo.asynchronous.settingsr1   Zpymongo.typingsr2   r3   Z_IS_SYNCr   __file__parentr   r@   rA   r   r  r   r   r>   r>   r>   r?   <module>   sZ    (
       > 