@@ -742,13 +742,15 @@ def __init__(
742
742
** kwargs ,
743
743
}
744
744
745
- if host is None :
746
- host = self .HOST
747
- if isinstance (host , str ):
748
- host = [host ]
749
- if port is None :
750
- port = self .PORT
751
- if not isinstance (port , int ):
745
+ self ._host = host
746
+ self ._port = port
747
+ if self ._host is None :
748
+ self ._host = self .HOST
749
+ if isinstance (self ._host , str ):
750
+ self ._host = [self ._host ]
751
+ if self ._port is None :
752
+ self ._port = self .PORT
753
+ if not isinstance (self ._port , int ):
752
754
raise TypeError (f"port must be an instance of int, not { type (port )} " )
753
755
754
756
# _pool_class, _monitor_class, and _condition_class are for deep
@@ -769,26 +771,19 @@ def __init__(
769
771
fqdn = None
770
772
srv_service_name = keyword_opts .get ("srvservicename" )
771
773
srv_max_hosts = keyword_opts .get ("srvmaxhosts" )
772
- if len ([h for h in host if "/" in h ]) > 1 :
774
+ if len ([h for h in self . _host if "/" in h ]) > 1 :
773
775
raise ConfigurationError ("host must not contain multiple MongoDB URIs" )
774
- for entity in host :
776
+ for entity in self . _host :
775
777
# A hostname can only include a-z, 0-9, '-' and '.'. If we find a '/'
776
778
# it must be a URI,
777
779
# https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names
778
780
if "/" in entity :
779
- # Determine connection timeout from kwargs.
780
- timeout = keyword_opts .get ("connecttimeoutms" )
781
- if timeout is not None :
782
- timeout = common .validate_timeout_or_none_or_zero (
783
- keyword_opts .cased_key ("connecttimeoutms" ), timeout
784
- )
785
781
res = uri_parser .parse_uri (
786
782
entity ,
787
783
port ,
788
784
validate = True ,
789
785
warn = True ,
790
786
normalize = False ,
791
- connect_timeout = timeout ,
792
787
srv_service_name = srv_service_name ,
793
788
srv_max_hosts = srv_max_hosts ,
794
789
)
@@ -799,7 +794,7 @@ def __init__(
799
794
opts = res ["options" ]
800
795
fqdn = res ["fqdn" ]
801
796
else :
802
- seeds .update (uri_parser .split_hosts (entity , port ))
797
+ seeds .update (uri_parser .split_hosts (entity , self . _port ))
803
798
if not seeds :
804
799
raise ConfigurationError ("need to specify at least one host" )
805
800
@@ -895,6 +890,134 @@ def __init__(
895
890
# This will be used later if we fork.
896
891
AsyncMongoClient ._clients [self ._topology ._topology_id ] = self
897
892
893
+ self ._for_resolve_uri = {
894
+ "username" : username ,
895
+ "password" : password ,
896
+ "srv_service_name" : srv_service_name ,
897
+ "srv_max_hosts" : srv_max_hosts ,
898
+ "fqdn" : fqdn ,
899
+ "pool_class" : pool_class ,
900
+ "monitor_class" : monitor_class ,
901
+ "condition_class" : condition_class ,
902
+ }
903
+
904
+ def _resolve_uri (self ):
905
+ keyword_opts = common ._CaseInsensitiveDictionary (self ._init_kwargs )
906
+ for i in [
907
+ "_pool_class" ,
908
+ "_monitor_class" ,
909
+ "_condition_class" ,
910
+ "host" ,
911
+ "port" ,
912
+ "type_registry" ,
913
+ ]:
914
+ keyword_opts .pop (i , None )
915
+ seeds = set ()
916
+ opts = common ._CaseInsensitiveDictionary ()
917
+ srv_service_name = keyword_opts .get ("srvservicename" )
918
+ srv_max_hosts = keyword_opts .get ("srvmaxhosts" )
919
+ for entity in self ._host :
920
+ # A hostname can only include a-z, 0-9, '-' and '.'. If we find a '/'
921
+ # it must be a URI,
922
+ # https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names
923
+ if "/" in entity :
924
+ # Determine connection timeout from kwargs.
925
+ timeout = keyword_opts .get ("connecttimeoutms" )
926
+ if timeout is not None :
927
+ timeout = common .validate_timeout_or_none_or_zero (
928
+ keyword_opts .cased_key ("connecttimeoutms" ), timeout
929
+ )
930
+ res = uri_parser .parse_uri_lookups (
931
+ entity ,
932
+ self ._port ,
933
+ validate = True ,
934
+ warn = True ,
935
+ normalize = False ,
936
+ connect_timeout = timeout ,
937
+ srv_service_name = srv_service_name ,
938
+ srv_max_hosts = srv_max_hosts ,
939
+ )
940
+ seeds .update (res ["nodelist" ])
941
+ opts = res ["options" ]
942
+ else :
943
+ seeds .update (uri_parser .split_hosts (entity , self ._port ))
944
+
945
+ if not seeds :
946
+ raise ConfigurationError ("need to specify at least one host" )
947
+
948
+ for hostname in [node [0 ] for node in seeds ]:
949
+ if _detect_external_db (hostname ):
950
+ break
951
+
952
+ # Add options with named keyword arguments to the parsed kwarg options.
953
+ tz_aware = keyword_opts ["tz_aware" ]
954
+ connect = keyword_opts ["connect" ]
955
+ if tz_aware is None :
956
+ tz_aware = opts .get ("tz_aware" , False )
957
+ if connect is None :
958
+ # Default to connect=True unless on a FaaS system, which might use fork.
959
+ from pymongo .pool_options import _is_faas
960
+
961
+ connect = opts .get ("connect" , not _is_faas ())
962
+ keyword_opts ["tz_aware" ] = tz_aware
963
+ keyword_opts ["connect" ] = connect
964
+
965
+ # Handle deprecated options in kwarg options.
966
+ keyword_opts = _handle_option_deprecations (keyword_opts )
967
+ # Validate kwarg options.
968
+ keyword_opts = common ._CaseInsensitiveDictionary (
969
+ dict (common .validate (keyword_opts .cased_key (k ), v ) for k , v in keyword_opts .items ())
970
+ )
971
+
972
+ # Override connection string options with kwarg options.
973
+ opts .update (keyword_opts )
974
+
975
+ if srv_service_name is None :
976
+ srv_service_name = opts .get ("srvServiceName" , common .SRV_SERVICE_NAME )
977
+
978
+ srv_max_hosts = srv_max_hosts or opts .get ("srvmaxhosts" )
979
+ # Handle security-option conflicts in combined options.
980
+ opts = _handle_security_options (opts )
981
+ # Normalize combined options.
982
+ opts = _normalize_options (opts )
983
+ _check_options (seeds , opts )
984
+
985
+ # Username and password passed as kwargs override user info in URI.
986
+ username = opts .get ("username" , self ._for_resolve_uri ["username" ])
987
+ password = opts .get ("password" , self ._for_resolve_uri ["password" ])
988
+ self ._options = ClientOptions (
989
+ username , password , self ._default_database_name , opts , _IS_SYNC
990
+ )
991
+
992
+ self ._event_listeners = self ._options .pool_options ._event_listeners
993
+ super ().__init__ (
994
+ self ._options .codec_options ,
995
+ self ._options .read_preference ,
996
+ self ._options .write_concern ,
997
+ self ._options .read_concern ,
998
+ )
999
+
1000
+ self ._topology_settings = TopologySettings (
1001
+ seeds = seeds ,
1002
+ replica_set_name = self ._options .replica_set_name ,
1003
+ pool_class = self ._for_resolve_uri ["pool_class" ],
1004
+ pool_options = self ._options .pool_options ,
1005
+ monitor_class = self ._for_resolve_uri ["monitor_class" ],
1006
+ condition_class = self ._for_resolve_uri ["condition_class" ],
1007
+ local_threshold_ms = self ._options .local_threshold_ms ,
1008
+ server_selection_timeout = self ._options .server_selection_timeout ,
1009
+ server_selector = self ._options .server_selector ,
1010
+ heartbeat_frequency = self ._options .heartbeat_frequency ,
1011
+ fqdn = self ._for_resolve_uri ["fqdn" ],
1012
+ direct_connection = self ._options .direct_connection ,
1013
+ load_balanced = self ._options .load_balanced ,
1014
+ srv_service_name = srv_service_name ,
1015
+ srv_max_hosts = srv_max_hosts ,
1016
+ server_monitoring_mode = self ._options .server_monitoring_mode ,
1017
+ )
1018
+
1019
+ self ._topology = Topology (self ._topology_settings )
1020
+
898
1021
async def aconnect (self ) -> None :
899
1022
"""Explicitly connect to MongoDB asynchronously instead of on the first operation."""
900
1023
await self ._get_topology ()
@@ -1582,6 +1705,7 @@ async def _get_topology(self) -> Topology:
1582
1705
launches the connection process in the background.
1583
1706
"""
1584
1707
if not self ._opened :
1708
+ self ._resolve_uri ()
1585
1709
await self ._topology .open ()
1586
1710
async with self ._lock :
1587
1711
self ._kill_cursors_executor .open ()
0 commit comments