PYTHON-5421 Make parse_uri() return "options" as a dict rather than _CaseInsensitiveDictionary (#2413)
This commit is contained in:
parent
2eb18f18b2
commit
947fbe33ee
@ -29,6 +29,7 @@ from pymongo.uri_parser_shared import (
|
||||
SCHEME_LEN,
|
||||
SRV_SCHEME_LEN,
|
||||
_check_options,
|
||||
_make_options_case_sensitive,
|
||||
_validate_uri,
|
||||
split_hosts,
|
||||
split_options,
|
||||
@ -113,6 +114,7 @@ async def parse_uri(
|
||||
srv_max_hosts,
|
||||
)
|
||||
)
|
||||
result["options"] = _make_options_case_sensitive(result["options"])
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ from pymongo.uri_parser_shared import (
|
||||
SCHEME_LEN,
|
||||
SRV_SCHEME_LEN,
|
||||
_check_options,
|
||||
_make_options_case_sensitive,
|
||||
_validate_uri,
|
||||
split_hosts,
|
||||
split_options,
|
||||
@ -113,6 +114,7 @@ def parse_uri(
|
||||
srv_max_hosts,
|
||||
)
|
||||
)
|
||||
result["options"] = _make_options_case_sensitive(result["options"])
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@ -54,6 +54,57 @@ SRV_SCHEME = "mongodb+srv://"
|
||||
SRV_SCHEME_LEN = len(SRV_SCHEME)
|
||||
DEFAULT_PORT = 27017
|
||||
|
||||
URI_OPTIONS = frozenset(
|
||||
[
|
||||
"appname",
|
||||
"authMechanism",
|
||||
"authMechanismProperties",
|
||||
"authSource",
|
||||
"compressors",
|
||||
"connectTimeoutMS",
|
||||
"directConnection",
|
||||
"heartbeatFrequencyMS",
|
||||
"journal",
|
||||
"loadBalanced",
|
||||
"localThresholdMS",
|
||||
"maxIdleTimeMS",
|
||||
"maxPoolSize",
|
||||
"maxConnecting",
|
||||
"maxStalenessSeconds",
|
||||
"minPoolSize",
|
||||
"proxyHost",
|
||||
"proxyPort",
|
||||
"proxyUsername",
|
||||
"proxyPassword",
|
||||
"readConcernLevel",
|
||||
"readPreference",
|
||||
"readPreferenceTags",
|
||||
"replicaSet",
|
||||
"retryReads",
|
||||
"retryWrites",
|
||||
"serverMonitoringMode",
|
||||
"serverSelectionTimeoutMS",
|
||||
"serverSelectionTryOnce",
|
||||
"socketTimeoutMS",
|
||||
"srvMaxHosts",
|
||||
"srvServiceName",
|
||||
"ssl",
|
||||
"tls",
|
||||
"tlsAllowInvalidCertificates",
|
||||
"tlsAllowInvalidHostnames",
|
||||
"tlsCAFile",
|
||||
"tlsCertificateKeyFile",
|
||||
"tlsCertificateKeyFilePassword",
|
||||
"tlsDisableCertificateRevocationCheck",
|
||||
"tlsDisableOCSPEndpointCheck",
|
||||
"tlsInsecure",
|
||||
"w",
|
||||
"waitQueueTimeoutMS",
|
||||
"wTimeoutMS",
|
||||
"zlibCompressionLevel",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _unquoted_percent(s: str) -> bool:
|
||||
"""Check for unescaped percent signs.
|
||||
@ -550,3 +601,14 @@ def _validate_uri(
|
||||
"options": options,
|
||||
"fqdn": fqdn,
|
||||
}
|
||||
|
||||
|
||||
def _make_options_case_sensitive(options: _CaseInsensitiveDictionary) -> dict[str, Any]:
|
||||
case_sensitive = {}
|
||||
for option in URI_OPTIONS:
|
||||
if option.lower() in options:
|
||||
case_sensitive[option] = options[option]
|
||||
options.pop(option)
|
||||
for k, v in options.items():
|
||||
case_sensitive[k] = v
|
||||
return case_sensitive
|
||||
|
||||
@ -91,8 +91,8 @@ async def create_mock_topology(uri, monitor_class=DummyMonitor):
|
||||
replica_set_name = None
|
||||
direct_connection = None
|
||||
load_balanced = None
|
||||
if "replicaset" in parsed_uri["options"]:
|
||||
replica_set_name = parsed_uri["options"]["replicaset"]
|
||||
if "replicaSet" in parsed_uri["options"]:
|
||||
replica_set_name = parsed_uri["options"]["replicaSet"]
|
||||
if "directConnection" in parsed_uri["options"]:
|
||||
direct_connection = parsed_uri["options"]["directConnection"]
|
||||
if "loadBalanced" in parsed_uri["options"]:
|
||||
|
||||
@ -91,8 +91,8 @@ def create_mock_topology(uri, monitor_class=DummyMonitor):
|
||||
replica_set_name = None
|
||||
direct_connection = None
|
||||
load_balanced = None
|
||||
if "replicaset" in parsed_uri["options"]:
|
||||
replica_set_name = parsed_uri["options"]["replicaset"]
|
||||
if "replicaSet" in parsed_uri["options"]:
|
||||
replica_set_name = parsed_uri["options"]["replicaSet"]
|
||||
if "directConnection" in parsed_uri["options"]:
|
||||
direct_connection = parsed_uri["options"]["directConnection"]
|
||||
if "loadBalanced" in parsed_uri["options"]:
|
||||
|
||||
@ -142,9 +142,9 @@ class TestURI(unittest.TestCase):
|
||||
self.assertTrue(split_options("wtimeoutms=500"))
|
||||
self.assertEqual({"fsync": True}, split_options("fsync=true"))
|
||||
self.assertEqual({"fsync": False}, split_options("fsync=false"))
|
||||
self.assertEqual({"authmechanism": "GSSAPI"}, split_options("authMechanism=GSSAPI"))
|
||||
self.assertEqual({"authMechanism": "GSSAPI"}, split_options("authMechanism=GSSAPI"))
|
||||
self.assertEqual(
|
||||
{"authmechanism": "SCRAM-SHA-1"}, split_options("authMechanism=SCRAM-SHA-1")
|
||||
{"authMechanism": "SCRAM-SHA-1"}, split_options("authMechanism=SCRAM-SHA-1")
|
||||
)
|
||||
self.assertEqual({"authsource": "foobar"}, split_options("authSource=foobar"))
|
||||
self.assertEqual({"maxpoolsize": 50}, split_options("maxpoolsize=50"))
|
||||
@ -290,12 +290,12 @@ class TestURI(unittest.TestCase):
|
||||
self.assertEqual(res, parse_uri('mongodb://localhost/test.name/with "delimiters'))
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res["options"] = {"readpreference": ReadPreference.SECONDARY.mongos_mode}
|
||||
res["options"] = {"readPreference": ReadPreference.SECONDARY.mongos_mode}
|
||||
self.assertEqual(res, parse_uri("mongodb://localhost/?readPreference=secondary"))
|
||||
|
||||
# Various authentication tests
|
||||
res = copy.deepcopy(orig)
|
||||
res["options"] = {"authmechanism": "SCRAM-SHA-256"}
|
||||
res["options"] = {"authMechanism": "SCRAM-SHA-256"}
|
||||
res["username"] = "user"
|
||||
res["password"] = "password"
|
||||
self.assertEqual(
|
||||
@ -303,7 +303,7 @@ class TestURI(unittest.TestCase):
|
||||
)
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res["options"] = {"authmechanism": "SCRAM-SHA-256", "authsource": "bar"}
|
||||
res["options"] = {"authMechanism": "SCRAM-SHA-256", "authSource": "bar"}
|
||||
res["username"] = "user"
|
||||
res["password"] = "password"
|
||||
res["database"] = "foo"
|
||||
@ -315,7 +315,7 @@ class TestURI(unittest.TestCase):
|
||||
)
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res["options"] = {"authmechanism": "SCRAM-SHA-256"}
|
||||
res["options"] = {"authMechanism": "SCRAM-SHA-256"}
|
||||
res["username"] = "user"
|
||||
res["password"] = ""
|
||||
self.assertEqual(res, parse_uri("mongodb://user:@localhost/?authMechanism=SCRAM-SHA-256"))
|
||||
@ -327,7 +327,7 @@ class TestURI(unittest.TestCase):
|
||||
self.assertEqual(res, parse_uri("mongodb://user%40domain.com:password@localhost/foo"))
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res["options"] = {"authmechanism": "GSSAPI"}
|
||||
res["options"] = {"authMechanism": "GSSAPI"}
|
||||
res["username"] = "user@domain.com"
|
||||
res["password"] = "password"
|
||||
res["database"] = "foo"
|
||||
@ -337,7 +337,7 @@ class TestURI(unittest.TestCase):
|
||||
)
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res["options"] = {"authmechanism": "GSSAPI"}
|
||||
res["options"] = {"authMechanism": "GSSAPI"}
|
||||
res["username"] = "user@domain.com"
|
||||
res["password"] = ""
|
||||
res["database"] = "foo"
|
||||
@ -347,8 +347,8 @@ class TestURI(unittest.TestCase):
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res["options"] = {
|
||||
"readpreference": ReadPreference.SECONDARY.mongos_mode,
|
||||
"readpreferencetags": [
|
||||
"readPreference": ReadPreference.SECONDARY.mongos_mode,
|
||||
"readPreferenceTags": [
|
||||
{"dc": "west", "use": "website"},
|
||||
{"dc": "east", "use": "website"},
|
||||
],
|
||||
@ -368,8 +368,8 @@ class TestURI(unittest.TestCase):
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res["options"] = {
|
||||
"readpreference": ReadPreference.SECONDARY.mongos_mode,
|
||||
"readpreferencetags": [
|
||||
"readPreference": ReadPreference.SECONDARY.mongos_mode,
|
||||
"readPreferenceTags": [
|
||||
{"dc": "west", "use": "website"},
|
||||
{"dc": "east", "use": "website"},
|
||||
{},
|
||||
@ -462,6 +462,7 @@ class TestURI(unittest.TestCase):
|
||||
"tlsInsecure": True,
|
||||
"tlsDisableOCSPEndpointCheck": True,
|
||||
}
|
||||
print(parse_uri(uri)["options"])
|
||||
self.assertEqual(res, parse_uri(uri)["options"])
|
||||
|
||||
def test_normalize_options(self):
|
||||
@ -479,8 +480,8 @@ class TestURI(unittest.TestCase):
|
||||
)
|
||||
res = parse_uri(uri)
|
||||
options: dict[str, Any] = {
|
||||
"authmechanism": "MONGODB-AWS",
|
||||
"authmechanismproperties": {"AWS_SESSION_TOKEN": unquoted_val},
|
||||
"authMechanism": "MONGODB-AWS",
|
||||
"authMechanismProperties": {"AWS_SESSION_TOKEN": unquoted_val},
|
||||
}
|
||||
self.assertEqual(options, res["options"])
|
||||
|
||||
@ -491,8 +492,8 @@ class TestURI(unittest.TestCase):
|
||||
)
|
||||
res = parse_uri(uri)
|
||||
options = {
|
||||
"readpreference": ReadPreference.SECONDARY.mongos_mode,
|
||||
"readpreferencetags": [
|
||||
"readPreference": ReadPreference.SECONDARY.mongos_mode,
|
||||
"readPreferenceTags": [
|
||||
{"dc": "west", unquoted_val: unquoted_val},
|
||||
{"dc": "east", "use": unquoted_val},
|
||||
],
|
||||
@ -519,7 +520,7 @@ class TestURI(unittest.TestCase):
|
||||
)
|
||||
res = parse_uri(uri)
|
||||
options = {
|
||||
"authmechanism": "MONGODB-AWS",
|
||||
"authMechanism": "MONGODB-AWS",
|
||||
"authMechanismProperties": {"AWS_SESSION_TOKEN": token},
|
||||
}
|
||||
self.assertEqual(options, res["options"])
|
||||
|
||||
@ -27,7 +27,7 @@ sys.path[0:0] = [""]
|
||||
from test import unittest
|
||||
from test.helpers import clear_warning_registry
|
||||
|
||||
from pymongo.common import INTERNAL_URI_OPTION_NAME_MAP, validate
|
||||
from pymongo.common import INTERNAL_URI_OPTION_NAME_MAP, _CaseInsensitiveDictionary, validate
|
||||
from pymongo.compression_support import _have_snappy
|
||||
from pymongo.synchronous.uri_parser import parse_uri
|
||||
|
||||
@ -169,7 +169,8 @@ def create_test(test, test_workdir):
|
||||
# Compare URI options.
|
||||
err_msg = "For option %s expected %s but got %s"
|
||||
if test["options"]:
|
||||
opts = options["options"]
|
||||
opts = _CaseInsensitiveDictionary()
|
||||
opts.update(options["options"])
|
||||
for opt in test["options"]:
|
||||
lopt = opt.lower()
|
||||
optname = INTERNAL_URI_OPTION_NAME_MAP.get(lopt, lopt)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user