U
    ~fhTi                  
   @  s  U d 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 ddlmZ ddlmZ dd	l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! G dd deZ"e"e#d Z$e$j%e$j&fZ'de(d< eee gee f Z)G dd dZ*ej+e$j&ej,e$j-ej.e$j/ej0e$j/ej1e$j/iZ2ddddddZ3ddddddZ4ddddd d!d"d#d$Z5dddd%d&d'd(Z6dddd)d&d*d+Z7d,d%d-d.d/Z8d0S )1zRepresent a deployment of MongoDB servers.

.. seealso:: This module is compatible with both the synchronous and asynchronous PyMongo APIs.
    )annotations)sample)AnyCallableListMappingMutableMapping
NamedTupleOptionalcastMinKey)ObjectId)common)ConfigurationError)ReadPreference_AggWritePref_ServerModeServerDescription)	Selection)SERVER_TYPE)_Addressc                   @  s>   e Zd ZU ded< ded< ded< ded< ded< ded< dS )	_TopologyTypeintSingleReplicaSetNoPrimaryReplicaSetWithPrimaryShardedUnknownLoadBalancedN)__name__
__module____qualname____annotations__ r%   r%   @/tmp/pip-unpacked-wheel-36gvocj8/pymongo/topology_description.pyr   -   s   
r      ztuple[int, int]SRV_POLLING_TOPOLOGIESc                   @  s  e Zd Zddddddddd	d
ZddddZddddZdddddZdd dddZd dddZddddZ	e
ddddZe
ddddZe
ddd d!Ze
ddd"d#Ze
ddd$d%Ze
ddd&d'Ze
d(dd)d*Ze
ddd+d,Ze
d(dd-d.Ze
ddd/d0Ze
ddd1d2Ze
ddd3d4Zd5d(d6d7d8ZdGdd:d;d(d<d=d>Zejfd?dd@dAdBZdddCdDZdddEdFZd9S )HTopologyDescriptionr   z!dict[_Address, ServerDescription]Optional[str]Optional[int]Optional[ObjectId]r   None)topology_typeserver_descriptionsreplica_set_namemax_set_versionmax_election_idtopology_settingsreturnc                 C  s   || _ || _|| _|| _|| _|| _d| _| j tjkr>| 	  | j
}|sPd| _n.tdd |D rjd| _ntdd |D | _dS )a  Representation of a deployment of MongoDB servers.

        :param topology_type: initial type
        :param server_descriptions: dict of (address, ServerDescription) for
            all seeds
        :param replica_set_name: replica set name or None
        :param max_set_version: greatest setVersion seen from a primary, or None
        :param max_election_id: greatest electionId seen from a primary, or None
        :param topology_settings: a TopologySettings
        Nc                 s  s   | ]}|j d kV  qd S Nlogical_session_timeout_minutes.0sr%   r%   r&   	<genexpr>k   s     z/TopologyDescription.__init__.<locals>.<genexpr>c                 s  s   | ]}|j V  qd S r5   r6   r8   r%   r%   r&   r;   n   s    )_topology_type_replica_set_name_server_descriptions_max_set_version_max_election_id_topology_settings_incompatible_errTOPOLOGY_TYPEr    _init_incompatible_errreadable_servers_ls_timeout_minutesanymin)selfr.   r/   r0   r1   r2   r3   rE   r%   r%   r&   __init__@   s"    	zTopologyDescription.__init__)r4   c                 C  s   | j  D ]}|jsq
|jdk	o*|jtjk}|jdk	o@|jtjk }|rnd|jd |jd p\d|jtjf | _	q
|r
d|jd |jd pd|jtjtj
f | _	 qq
dS )z>Internal compatibility check for non-load balanced topologies.Nz]Server at %s:%d requires wire version %d, but this version of PyMongo only supports up to %d.r      zgServer at %s:%d reports wire version %d, but this version of PyMongo requires at least %d (MongoDB %s).)r>   valuesis_server_type_knownmin_wire_versionr   ZMAX_SUPPORTED_WIRE_VERSIONmax_wire_versionZMIN_SUPPORTED_WIRE_VERSIONaddressrB   ZMIN_SUPPORTED_SERVER_VERSION)rI   r:   Zserver_too_newZserver_too_oldr%   r%   r&   rD   r   s:    



z*TopologyDescription._init_incompatible_errc                 C  s   | j rt| j dS )zRaise ConfigurationError if any server is incompatible.

        A server is incompatible if its wire protocol version range does not
        overlap with PyMongo's.
        N)rB   r   rI   r%   r%   r&   check_compatible   s    z$TopologyDescription.check_compatibler   bool)rP   r4   c                 C  s
   || j kS r5   )r>   )rI   rP   r%   r%   r&   
has_server   s    zTopologyDescription.has_serverc                 C  s   | j |  }t| |S )z;A copy of this description, with one server marked Unknown.)r>   
to_unknownupdated_topology_description)rI   rP   Z
unknown_sdr%   r%   r&   reset_server   s    z TopologyDescription.reset_serverc                 C  sD   | j tjkrtj}n| j }dd | jD }t||| j| j| j| j	S )z<A copy of this description, with all servers marked Unknown.c                 S  s   i | ]}|t |qS r%   r   )r9   rP   r%   r%   r&   
<dictcomp>   s      z-TopologyDescription.reset.<locals>.<dictcomp>)
r<   rC   r   r   r>   r)   r=   r?   r@   rA   )rI   r.   sdsr%   r%   r&   reset   s    zTopologyDescription.resetc                 C  s
   | j  S )z[dict of (address,
        :class:`~pymongo.server_description.ServerDescription`).
        )r>   copyrQ   r%   r%   r&   r/      s    z'TopologyDescription.server_descriptionsc                 C  s   | j S )zThe type of this topology.)r<   rQ   r%   r%   r&   r.      s    z!TopologyDescription.topology_typestrc                 C  s   t j| j S )zUThe topology type as a human readable string.

        .. versionadded:: 3.4
        )rC   _fieldsr<   rQ   r%   r%   r&   topology_type_name   s    z&TopologyDescription.topology_type_namec                 C  s   | j S )zThe replica set name.)r=   rQ   r%   r%   r&   r0      s    z$TopologyDescription.replica_set_namec                 C  s   | j S )z1Greatest setVersion seen from a primary, or None.)r?   rQ   r%   r%   r&   r1      s    z#TopologyDescription.max_set_versionc                 C  s   | j S )z1Greatest electionId seen from a primary, or None.)r@   rQ   r%   r%   r&   r2      s    z#TopologyDescription.max_election_idc                 C  s   | j S )z)Minimum logical session timeout, or None.)rF   rQ   r%   r%   r&   r7      s    z3TopologyDescription.logical_session_timeout_minuteszlist[ServerDescription]c                 C  s   dd | j  D S )z)List of Servers of types besides Unknown.c                 S  s   g | ]}|j r|qS r%   rM   r8   r%   r%   r&   
<listcomp>   s      z5TopologyDescription.known_servers.<locals>.<listcomp>r>   rL   rQ   r%   r%   r&   known_servers   s    z!TopologyDescription.known_serversc                 C  s   t dd | j D S )z7Whether there are any Servers of types besides Unknown.c                 s  s   | ]}|j r|V  qd S r5   r_   r8   r%   r%   r&   r;      s      z8TopologyDescription.has_known_servers.<locals>.<genexpr>)rG   r>   rL   rQ   r%   r%   r&   has_known_servers   s    z%TopologyDescription.has_known_serversc                 C  s   dd | j  D S )zList of readable Servers.c                 S  s   g | ]}|j r|qS r%   )Zis_readabler8   r%   r%   r&   r`      s      z8TopologyDescription.readable_servers.<locals>.<listcomp>ra   rQ   r%   r%   r&   rE      s    z$TopologyDescription.readable_serversc                 C  s"   | j }|rtdd | j D S dS )z3Minimum of all servers' max wire versions, or None.c                 s  s   | ]}|j V  qd S r5   )rO   r8   r%   r%   r&   r;      s     z:TopologyDescription.common_wire_version.<locals>.<genexpr>N)rb   rH   rI   Zserversr%   r%   r&   common_wire_version   s    z'TopologyDescription.common_wire_versionc                 C  s   | j jS r5   )rA   heartbeat_frequencyrQ   r%   r%   r&   rf     s    z'TopologyDescription.heartbeat_frequencyc                 C  s   | j jS r5   )rA   Z_srv_max_hostsrQ   r%   r%   r&   srv_max_hosts  s    z!TopologyDescription.srv_max_hostszOptional[Selection])	selectionr4   c                   sz   |sg S g }|j D ]<}|jd krBd|j d|  d|j  }t|||j qt| | jjd  fdd|j D S )Nzround_trip_time for server z is unexpectedly None: z, servers: g     @@c                   s$   g | ]}t t|j  kr|qS r%   )r   floatround_trip_timer8   Zfastest	thresholdr%   r&   r`     s   z>TopologyDescription._apply_local_threshold.<locals>.<listcomp>)r/   rj   rP   r   appendrH   rA   Zlocal_threshold_ms)rI   rh   Zround_trip_timesserverZconfig_err_msgr%   rk   r&   _apply_local_threshold  s    

z*TopologyDescription._apply_local_thresholdNzOptional[_Address]zOptional[_ServerSelector])selectorrP   custom_selectorr4   c                 C  s   t |ddr4| j}|r4||jk r4td||j|f t|trH||  | jtj	krXg S | jtj
tjfkrp| jS |r|  |}|r|gS g S t| }| jtjkr||}|dk	r|r|||j}| |S )a  List of servers matching the provided selector(s).

        :param selector: a callable that takes a Selection as input and returns
            a Selection as output. For example, an instance of a read
            preference from :mod:`~pymongo.read_preferences`.
        :param address: A server address to select.
        :param custom_selector: A callable that augments server
            selection rules. Accepts a list of
            :class:`~pymongo.server_description.ServerDescription` objects and
            return a list of server descriptions that should be considered
            suitable for the desired operation.

        .. versionadded:: 3.4
        rN   r   zF%s requires min wire version %d, but topology's min wire version is %dN)getattrre   rN   r   
isinstancer   Zselection_hookr.   rC   r   r   r    rb   r/   getr   Zfrom_topology_descriptionr   Zwith_server_descriptionsro   )rI   rp   rP   rq   Z	common_wvdescriptionrh   r%   r%   r&   apply_selector  s2    



z"TopologyDescription.apply_selectorr   )read_preferencer4   c                 C  s   t d| t| |S )a  Does this topology have any readable servers available matching the
        given read preference?

        :param read_preference: an instance of a read preference from
            :mod:`~pymongo.read_preferences`. Defaults to
            :attr:`~pymongo.read_preferences.ReadPreference.PRIMARY`.

        .. note:: When connected directly to a single server this method
          always returns ``True``.

        .. versionadded:: 3.4
        rw   )r   Zvalidate_read_preferencerG   rv   )rI   rw   r%   r%   r&   has_readable_serverS  s    z'TopologyDescription.has_readable_serverc                 C  s   |  tjS )zDoes this topology have a writable server available?

        .. note:: When connected directly to a single server this method
          always returns ``True``.

        .. versionadded:: 3.4
        )rx   r   PRIMARYrQ   r%   r%   r&   has_writable_serverc  s    z'TopologyDescription.has_writable_serverc                 C  s0   t | j dd d}d| jj| jj| j|S )Nc                 S  s   | j S r5   )rP   )sdr%   r%   r&   <lambda>o      z.TopologyDescription.__repr__.<locals>.<lambda>)keyz-<{} id: {}, topology_type: {}, servers: {!r}>)	sortedr>   rL   format	__class__r!   rA   Z_topology_idr^   rd   r%   r%   r&   __repr__m  s    zTopologyDescription.__repr__)NN)r!   r"   r#   rJ   rD   rR   rT   rW   rZ   r/   propertyr.   r^   r0   r1   r2   r7   rb   rc   rE   re   rf   rg   ro   rv   r   ry   rx   rz   r   r%   r%   r%   r&   r)   ?   sL   2/	  5
r)   r   )topology_descriptionserver_descriptionr4   c           
      C  s  |j }| j}| j}| j}| j}|j}|  }|||< |tjkr|dk	rr||jkrrt	d
||j}	|j|	d||< ttj||||| jS |tjkr|tjtjfkrt| jjdkrtj}q|| n|tjtjfkrt| }|tjkr|tjtjfkr|| n|tjkr|tjtjfkr2|| nL|tjkrXt|||||\}}}}n&|tjtjtjfkrt|||\}}n|tj kr|tjtjfkr|| t!|}nR|tjkrt|||||\}}}}n,|tjtjtjfkrt"|||}nt!|}t|||||| jS )an  Return an updated copy of a TopologyDescription.

    :param topology_description: the current TopologyDescription
    :param server_description: a new ServerDescription that resulted from
        a hello call

    Called after attempting (successfully or not) to call hello on the
    server at server_description.address. Does not modify topology_description.
    Nzeclient is configured to connect to a replica set named '{}' but this node belongs to a set named '{}')errorrK   )#rP   r.   r0   r1   r2   server_typer/   rC   r   r   r   rU   r)   rA   r   r   Z
StandaloneZLoadBalancerlenZseedspopZRSGhost_SERVER_TYPE_TO_TOPOLOGY_TYPEr   Mongosr   	RSPrimary_update_rs_from_primaryRSSecondary	RSArbiterRSOther!_update_rs_no_primary_from_memberr   _check_has_primary#_update_rs_with_primary_from_member)
r   r   rP   r.   set_namer1   r2   r   rY   r   r%   r%   r&   rV     s    
 	
      


    rV   zlist[tuple[str, Any]])r   seedlistr4   c                 C  s   | j tkst|  }t| t|kr.| S t| D ]}||kr:|| q:| jdkrt|t|  }| jt	| }|dkrt
t|t|t	|}ng }|D ]}||krt|||< qt| j || j| j| j| jS )zReturn an updated copy of a TopologyDescription.

    :param topology_description: the current TopologyDescription
    :param seedlist: a list of new seeds new ServerDescription that resulted from
        a hello call
    r   )r.   r(   AssertionErrorr/   setkeyslistr   rg   r   r   r   rH   r   r)   r0   r1   r2   rA   )r   r   rY   rP   Z	new_hostsZn_to_addr%   r%   r&   )_updated_topology_description_srv_polling  s0    	
r   z+MutableMapping[_Address, ServerDescription]r*   r+   r,   z<tuple[int, Optional[str], Optional[int], Optional[ObjectId]])rY   r0   r   r1   r2   r4   c                 C  s  |dkr|j }n&||j kr6| |j t| |||fS |jdksJ|jdk r|j|jf}||f}d|krd|kr||k r| | |j< t| |||fS |j}|jdk	r|dks|j|kr|j}nl|j|jf}||f}tdd |D }tdd |D }||k r| | |j< t| |||fS |j}|j}| 	 D ]6}	|	j
tjkr2|	j|jkr2|	 | |	j<  qjq2|jD ]}
|
| krpt|
| |
< qpt| |j D ]}| | qt| |||fS )ag  Update topology description from a primary's hello response.

    Pass in a dict of ServerDescriptions, current replica set name, the
    ServerDescription we are processing, and the TopologyDescription's
    max_set_version and max_election_id if any.

    Returns (new topology type, new replica_set_name, new max_set_version,
    new max_election_id).
    N   c                 s  s    | ]}|d krt  n|V  qd S r5   r   r9   ir%   r%   r&   r;   A  s     z*_update_rs_from_primary.<locals>.<genexpr>c                 s  s    | ]}|d krt  n|V  qd S r5   r   r   r%   r%   r&   r;   B  s     )r0   r   rP   r   rO   Zset_versionZelection_idrU   tuplerL   r   r   r   	all_hostsr   r   )rY   r0   r   r1   r2   Znew_election_tupleZmax_election_tupleZnew_election_safeZmax_election_safern   Znew_addressaddrr%   r%   r&   r     sR    







r   r   )rY   r0   r   r4   c                 C  sJ   |dk	st ||jkr$| |j n|jrB|j|jkrB| |j t| S )zRS with known primary. Process a response from a non-primary.

    Pass in a dict of ServerDescriptions, current replica set name, and the
    ServerDescription we are processing.

    Returns new topology type.
    N)r   r0   r   rP   mer   )rY   r0   r   r%   r%   r&   r   e  s    
r   ztuple[int, Optional[str]]c                 C  sz   t j}|dkr|j}n||jkr4| |j ||fS |jD ]}|| kr:t|| |< q:|jrr|j|jkrr| |j ||fS )zRS without known primary. Update from a non-primary's response.

    Pass in a dict of ServerDescriptions, current replica set name, and the
    ServerDescription we are processing.

    Returns (new topology type, new replica_set_name).
    N)rC   r   r0   r   rP   r   r   r   )rY   r0   r   r.   rP   r%   r%   r&   r   |  s    

r   z$Mapping[_Address, ServerDescription])rY   r4   c                 C  s*   |   D ]}|jtjkrtj  S qtjS )zCurrent topology type is ReplicaSetWithPrimary. Is primary still known?

    Pass in a dict of ServerDescriptions.

    Returns new topology type.
    N)rL   r   r   r   rC   r   r   )rY   r:   r%   r%   r&   r     s    r   N)9__doc__
__future__r   randomr   typingr   r   r   r   r   r	   r
   r   Zbson.min_keyr   Zbson.objectidr   Zpymongor   Zpymongo.errorsr   Zpymongo.read_preferencesr   r   r   Zpymongo.server_descriptionr   Zpymongo.server_selectorsr   Zpymongo.server_typer   Zpymongo.typingsr   r   rangerC   r   r   r(   r$   _ServerSelectorr)   r   r   r   r   r   r   r   r   rV   r   r   r   r   r   r%   r%   r%   r&   <module>   sH   (	  >     
h+N 