API refactor
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-10-07 16:25:52 +09:00
parent 76d0d86211
commit 91c7e04474
1171 changed files with 81940 additions and 44117 deletions

View File

@@ -1,5 +1,5 @@
# engine/url.py
# Copyright (C) 2005-2023 the SQLAlchemy authors and contributors
# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
@@ -32,6 +32,7 @@ from typing import Tuple
from typing import Type
from typing import Union
from urllib.parse import parse_qsl
from urllib.parse import quote
from urllib.parse import quote_plus
from urllib.parse import unquote
@@ -121,7 +122,9 @@ class URL(NamedTuple):
for keys and either strings or tuples of strings for values, e.g.::
>>> from sqlalchemy.engine import make_url
>>> url = make_url("postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
>>> url = make_url(
... "postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt"
... )
>>> url.query
immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': '/path/to/crt'})
@@ -170,6 +173,11 @@ class URL(NamedTuple):
:param password: database password. Is typically a string, but may
also be an object that can be stringified with ``str()``.
.. note:: The password string should **not** be URL encoded when
passed as an argument to :meth:`_engine.URL.create`; the string
should contain the password characters exactly as they would be
typed.
.. note:: A password-producing object will be stringified only
**once** per :class:`_engine.Engine` object. For dynamic password
generation per connect, see :ref:`engines_dynamic_tokens`.
@@ -247,14 +255,12 @@ class URL(NamedTuple):
@overload
def _assert_value(
val: str,
) -> str:
...
) -> str: ...
@overload
def _assert_value(
val: Sequence[str],
) -> Union[str, Tuple[str, ...]]:
...
) -> Union[str, Tuple[str, ...]]: ...
def _assert_value(
val: Union[str, Sequence[str]],
@@ -367,7 +373,9 @@ class URL(NamedTuple):
>>> from sqlalchemy.engine import make_url
>>> url = make_url("postgresql+psycopg2://user:pass@host/dbname")
>>> url = url.update_query_string("alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
>>> url = url.update_query_string(
... "alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt"
... )
>>> str(url)
'postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
@@ -403,7 +411,13 @@ class URL(NamedTuple):
>>> from sqlalchemy.engine import make_url
>>> url = make_url("postgresql+psycopg2://user:pass@host/dbname")
>>> url = url.update_query_pairs([("alt_host", "host1"), ("alt_host", "host2"), ("ssl_cipher", "/path/to/crt")])
>>> url = url.update_query_pairs(
... [
... ("alt_host", "host1"),
... ("alt_host", "host2"),
... ("ssl_cipher", "/path/to/crt"),
... ]
... )
>>> str(url)
'postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
@@ -485,7 +499,9 @@ class URL(NamedTuple):
>>> from sqlalchemy.engine import make_url
>>> url = make_url("postgresql+psycopg2://user:pass@host/dbname")
>>> url = url.update_query_dict({"alt_host": ["host1", "host2"], "ssl_cipher": "/path/to/crt"})
>>> url = url.update_query_dict(
... {"alt_host": ["host1", "host2"], "ssl_cipher": "/path/to/crt"}
... )
>>> str(url)
'postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
@@ -523,14 +539,14 @@ class URL(NamedTuple):
E.g.::
url = url.difference_update_query(['foo', 'bar'])
url = url.difference_update_query(["foo", "bar"])
Equivalent to using :meth:`_engine.URL.set` as follows::
url = url.set(
query={
key: url.query[key]
for key in set(url.query).difference(['foo', 'bar'])
for key in set(url.query).difference(["foo", "bar"])
}
)
@@ -579,7 +595,9 @@ class URL(NamedTuple):
>>> from sqlalchemy.engine import make_url
>>> url = make_url("postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
>>> url = make_url(
... "postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt"
... )
>>> url.query
immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': '/path/to/crt'})
>>> url.normalized_query
@@ -621,17 +639,17 @@ class URL(NamedTuple):
"""
s = self.drivername + "://"
if self.username is not None:
s += _sqla_url_quote(self.username)
s += quote(self.username, safe=" +")
if self.password is not None:
s += ":" + (
"***"
if hide_password
else _sqla_url_quote(str(self.password))
else quote(str(self.password), safe=" +")
)
s += "@"
if self.host is not None:
if ":" in self.host:
s += "[%s]" % self.host
s += f"[{self.host}]"
else:
s += self.host
if self.port is not None:
@@ -642,7 +660,7 @@ class URL(NamedTuple):
keys = list(self.query)
keys.sort()
s += "?" + "&".join(
"%s=%s" % (quote_plus(k), quote_plus(element))
f"{quote_plus(k)}={quote_plus(element)}"
for k in keys
for element in util.to_list(self.query[k])
)
@@ -885,10 +903,10 @@ def _parse_url(name: str) -> URL:
components["query"] = query
if components["username"] is not None:
components["username"] = _sqla_url_unquote(components["username"])
components["username"] = unquote(components["username"])
if components["password"] is not None:
components["password"] = _sqla_url_unquote(components["password"])
components["password"] = unquote(components["password"])
ipv4host = components.pop("ipv4host")
ipv6host = components.pop("ipv6host")
@@ -902,12 +920,5 @@ def _parse_url(name: str) -> URL:
else:
raise exc.ArgumentError(
"Could not parse SQLAlchemy URL from string '%s'" % name
"Could not parse SQLAlchemy URL from given URL string"
)
def _sqla_url_quote(text: str) -> str:
return re.sub(r"[:@/]", lambda m: "%%%X" % ord(m.group(0)), text)
_sqla_url_unquote = unquote