python3-commons 0.19.0__tar.gz → 0.20.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {python3_commons-0.19.0/src/python3_commons.egg-info → python3_commons-0.20.1}/PKG-INFO +2 -2
  2. {python3_commons-0.19.0 → python3_commons-0.20.1}/pyproject.toml +1 -1
  3. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/auth.py +37 -20
  4. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/conf.py +3 -1
  5. {python3_commons-0.19.0 → python3_commons-0.20.1/src/python3_commons.egg-info}/PKG-INFO +2 -2
  6. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons.egg-info/requires.txt +1 -1
  7. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/integration/test_auth.py +1 -1
  8. {python3_commons-0.19.0 → python3_commons-0.20.1}/uv.lock +19 -18
  9. {python3_commons-0.19.0 → python3_commons-0.20.1}/.coveragerc +0 -0
  10. {python3_commons-0.19.0 → python3_commons-0.20.1}/.devcontainer/Dockerfile +0 -0
  11. {python3_commons-0.19.0 → python3_commons-0.20.1}/.devcontainer/devcontainer.json +0 -0
  12. {python3_commons-0.19.0 → python3_commons-0.20.1}/.devcontainer/docker-compose.yml +0 -0
  13. {python3_commons-0.19.0 → python3_commons-0.20.1}/.env_template +0 -0
  14. {python3_commons-0.19.0 → python3_commons-0.20.1}/.github/workflows/checks.yml +0 -0
  15. {python3_commons-0.19.0 → python3_commons-0.20.1}/.github/workflows/python-publish.yaml +0 -0
  16. {python3_commons-0.19.0 → python3_commons-0.20.1}/.github/workflows/release-on-tag-push.yml +0 -0
  17. {python3_commons-0.19.0 → python3_commons-0.20.1}/.gitignore +0 -0
  18. {python3_commons-0.19.0 → python3_commons-0.20.1}/.pre-commit-config.yaml +0 -0
  19. {python3_commons-0.19.0 → python3_commons-0.20.1}/.python-version +0 -0
  20. {python3_commons-0.19.0 → python3_commons-0.20.1}/AUTHORS.rst +0 -0
  21. {python3_commons-0.19.0 → python3_commons-0.20.1}/CHANGELOG.rst +0 -0
  22. {python3_commons-0.19.0 → python3_commons-0.20.1}/LICENSE +0 -0
  23. {python3_commons-0.19.0 → python3_commons-0.20.1}/README.md +0 -0
  24. {python3_commons-0.19.0 → python3_commons-0.20.1}/README.rst +0 -0
  25. {python3_commons-0.19.0 → python3_commons-0.20.1}/docs/Makefile +0 -0
  26. {python3_commons-0.19.0 → python3_commons-0.20.1}/docs/_static/.gitignore +0 -0
  27. {python3_commons-0.19.0 → python3_commons-0.20.1}/docs/authors.rst +0 -0
  28. {python3_commons-0.19.0 → python3_commons-0.20.1}/docs/changelog.rst +0 -0
  29. {python3_commons-0.19.0 → python3_commons-0.20.1}/docs/conf.py +0 -0
  30. {python3_commons-0.19.0 → python3_commons-0.20.1}/docs/index.rst +0 -0
  31. {python3_commons-0.19.0 → python3_commons-0.20.1}/docs/license.rst +0 -0
  32. {python3_commons-0.19.0 → python3_commons-0.20.1}/setup.cfg +0 -0
  33. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/__init__.py +0 -0
  34. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/api_client.py +0 -0
  35. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/async_functools.py +0 -0
  36. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/audit.py +0 -0
  37. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/cache.py +0 -0
  38. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/db/__init__.py +0 -0
  39. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/db/helpers.py +0 -0
  40. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/db/models/__init__.py +0 -0
  41. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/db/models/auth.py +0 -0
  42. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/db/models/common.py +0 -0
  43. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/db/models/rbac.py +0 -0
  44. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/db/models/users.py +0 -0
  45. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/exceptions.py +0 -0
  46. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/fs.py +0 -0
  47. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/generators.py +0 -0
  48. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/helpers.py +0 -0
  49. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/log/__init__.py +0 -0
  50. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/log/filters.py +0 -0
  51. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/log/formatters.py +0 -0
  52. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/object_storage.py +0 -0
  53. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/permissions.py +0 -0
  54. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/serializers/__init__.py +0 -0
  55. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/serializers/common.py +0 -0
  56. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/serializers/json.py +0 -0
  57. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/serializers/msgpack.py +0 -0
  58. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/serializers/msgspec.py +0 -0
  59. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons/soap_client.py +0 -0
  60. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons.egg-info/SOURCES.txt +0 -0
  61. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons.egg-info/dependency_links.txt +0 -0
  62. {python3_commons-0.19.0 → python3_commons-0.20.1}/src/python3_commons.egg-info/top_level.txt +0 -0
  63. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/__init__.py +0 -0
  64. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/integration/__init__.py +0 -0
  65. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/integration/conftest.py +0 -0
  66. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/integration/test_cache.py +0 -0
  67. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/integration/test_osc.py +0 -0
  68. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/__init__.py +0 -0
  69. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/conftest.py +0 -0
  70. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/log/__init__.py +0 -0
  71. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/log/test_formatters.py +0 -0
  72. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/test_async_functools.py +0 -0
  73. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/test_audit.py +0 -0
  74. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/test_helpers.py +0 -0
  75. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/test_msgpack.py +0 -0
  76. {python3_commons-0.19.0 → python3_commons-0.20.1}/tests/unit/test_msgspec.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-commons
3
- Version: 0.19.0
3
+ Version: 0.20.1
4
4
  Summary: Re-usable Python3 code
5
5
  Author-email: Oleg Korsak <kamikaze.is.waiting.you@gmail.com>
6
6
  License-Expression: GPL-3.0
@@ -36,7 +36,7 @@ Provides-Extra: cache
36
36
  Requires-Dist: valkey[libvalkey]~=6.1.1; extra == "cache"
37
37
  Provides-Extra: database
38
38
  Requires-Dist: asyncpg~=0.31.0; extra == "database"
39
- Requires-Dist: SQLAlchemy[asyncio]~=2.0.49; extra == "database"
39
+ Requires-Dist: SQLAlchemy[asyncio]~=2.0.50; extra == "database"
40
40
  Provides-Extra: object-storage
41
41
  Requires-Dist: aiobotocore~=3.7.0; extra == "object-storage"
42
42
  Requires-Dist: object-storage-client==0.0.30; extra == "object-storage"
@@ -51,7 +51,7 @@ cache = [
51
51
  ]
52
52
  database = [
53
53
  "asyncpg~=0.31.0",
54
- "SQLAlchemy[asyncio]~=2.0.49"
54
+ "SQLAlchemy[asyncio]~=2.0.50"
55
55
  ]
56
56
  object-storage = [
57
57
  "aiobotocore~=3.7.0",
@@ -16,8 +16,6 @@ except ImportError as e:
16
16
 
17
17
  import msgspec
18
18
 
19
- from python3_commons.conf import oidc_settings
20
-
21
19
  logger = logging.getLogger(__name__)
22
20
  _OIDC_LOCK = threading.Lock()
23
21
 
@@ -79,21 +77,25 @@ class OIDCClient:
79
77
  client_secret: str | None = None,
80
78
  *,
81
79
  timeout: float = 10.0,
82
- verify_ssl: bool = True,
80
+ verify_cert: bool = True,
83
81
  connection_limit: int = 100,
82
+ authority_internal_host: HttpUrl | None = None,
84
83
  ) -> None:
85
- if oidc_settings.authority_internal_host:
86
- authority_url = replace_origin(authority_url, oidc_settings.authority_internal_host)
84
+ if authority_internal_host:
85
+ authority_url = replace_origin(authority_url, authority_internal_host)
87
86
 
88
87
  self._authority_url = authority_url
88
+ self._authority_internal_host = authority_internal_host
89
89
  self._client_id = client_id
90
90
  self._client_secret = client_secret
91
- self._oidc_config: Mapping[str, Any] | None = None
92
91
 
93
92
  self._connection_limit = connection_limit
94
93
  self._session: aiohttp.ClientSession | None = None
95
94
  self._timeout = timeout
96
- self._verify_ssl = verify_ssl
95
+ self._verify_cert = verify_cert
96
+
97
+ self._config: Mapping[str, Any] | None = None
98
+ self._jwks: Mapping[str, Any] | None = None
97
99
 
98
100
  def get_session(self) -> aiohttp.ClientSession:
99
101
  if self._session:
@@ -103,7 +105,7 @@ class OIDCClient:
103
105
  if self._session:
104
106
  return self._session
105
107
 
106
- connector = aiohttp.TCPConnector(verify_ssl=self._verify_ssl, limit=self._connection_limit)
108
+ connector = aiohttp.TCPConnector(verify_ssl=self._verify_cert, limit=self._connection_limit)
107
109
  timeout = aiohttp.ClientTimeout(total=self._timeout)
108
110
  session = aiohttp.ClientSession(connector=connector, timeout=timeout)
109
111
  self._session = session
@@ -119,7 +121,7 @@ class OIDCClient:
119
121
  if self._session:
120
122
  await self._session.close()
121
123
 
122
- async def _fetch_openid_config(self) -> dict:
124
+ async def _fetch_config(self) -> dict:
123
125
  """
124
126
  Fetch the OpenID configuration (including JWKS URI) from OIDC authority.
125
127
  """
@@ -139,7 +141,20 @@ class OIDCClient:
139
141
 
140
142
  return await response.json()
141
143
 
142
- async def fetch_jwks(self, jwks_uri: str) -> dict:
144
+ async def get_config(self) -> Mapping[str, Any]:
145
+ if self._config:
146
+ return self._config
147
+
148
+ with _OIDC_LOCK:
149
+ if self._config:
150
+ return self._config
151
+
152
+ config = await self._fetch_config()
153
+ self._config = config
154
+
155
+ return config
156
+
157
+ async def _fetch_jwks(self, jwks_uri: str) -> dict:
143
158
  """
144
159
  Fetch the JSON Web Key Set (JWKS) for validating the token's signature.
145
160
  """
@@ -147,7 +162,7 @@ class OIDCClient:
147
162
  msg = 'ClientSession not initialized'
148
163
  raise RuntimeError(msg)
149
164
 
150
- if authority_internal_host := oidc_settings.authority_internal_host:
165
+ if authority_internal_host := self._authority_internal_host:
151
166
  logger.debug('Received jwks_uri: %s', jwks_uri)
152
167
  logger.debug('Replacing OIDC authority host with: %s', authority_internal_host)
153
168
  jwks_uri = str(replace_origin(HttpUrl(jwks_uri), authority_internal_host))
@@ -161,18 +176,20 @@ class OIDCClient:
161
176
 
162
177
  return await response.json()
163
178
 
164
- async def get_openid_config(self) -> Mapping[str, Any]:
165
- if self._oidc_config:
166
- return self._oidc_config
179
+ async def get_jwks(self) -> Mapping[str, Any]:
180
+ if self._jwks:
181
+ return self._jwks
167
182
 
168
183
  with _OIDC_LOCK:
169
- if self._oidc_config:
170
- return self._oidc_config
184
+ if self._jwks:
185
+ return self._jwks
186
+
187
+ oidc_config = await self.get_config()
171
188
 
172
- oidc_config = await self._fetch_openid_config()
173
- self._oidc_config = oidc_config
189
+ jwks = await self._fetch_jwks(oidc_config['jwks_uri'])
190
+ self._jwks = jwks
174
191
 
175
- return oidc_config
192
+ return jwks
176
193
 
177
194
  async def fetch_token(
178
195
  self,
@@ -196,7 +213,7 @@ class OIDCClient:
196
213
  if self._client_secret:
197
214
  data['client_secret'] = self._client_secret
198
215
 
199
- openid_config = await self.get_openid_config()
216
+ openid_config = await self.get_config()
200
217
 
201
218
  try:
202
219
  async with self._session.post(
@@ -29,6 +29,9 @@ class OIDCSettings(BaseSettings):
29
29
  'email',
30
30
  )
31
31
  audience: StringSeq | str | None = None
32
+ verify_cert: bool = True
33
+ timeout: float = 10
34
+ connection_limit: int = 100
32
35
 
33
36
 
34
37
  class ValkeySettings(BaseSettings):
@@ -91,7 +94,6 @@ class S3Settings(BaseSettings):
91
94
 
92
95
 
93
96
  settings = CommonSettings()
94
- oidc_settings = OIDCSettings()
95
97
  valkey_settings = ValkeySettings()
96
98
  db_settings = DBSettings()
97
99
  s3_settings = S3Settings()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-commons
3
- Version: 0.19.0
3
+ Version: 0.20.1
4
4
  Summary: Re-usable Python3 code
5
5
  Author-email: Oleg Korsak <kamikaze.is.waiting.you@gmail.com>
6
6
  License-Expression: GPL-3.0
@@ -36,7 +36,7 @@ Provides-Extra: cache
36
36
  Requires-Dist: valkey[libvalkey]~=6.1.1; extra == "cache"
37
37
  Provides-Extra: database
38
38
  Requires-Dist: asyncpg~=0.31.0; extra == "database"
39
- Requires-Dist: SQLAlchemy[asyncio]~=2.0.49; extra == "database"
39
+ Requires-Dist: SQLAlchemy[asyncio]~=2.0.50; extra == "database"
40
40
  Provides-Extra: object-storage
41
41
  Requires-Dist: aiobotocore~=3.7.0; extra == "object-storage"
42
42
  Requires-Dist: object-storage-client==0.0.30; extra == "object-storage"
@@ -29,7 +29,7 @@ valkey[libvalkey]~=6.1.1
29
29
 
30
30
  [database]
31
31
  asyncpg~=0.31.0
32
- SQLAlchemy[asyncio]~=2.0.49
32
+ SQLAlchemy[asyncio]~=2.0.50
33
33
 
34
34
  [object-storage]
35
35
  aiobotocore~=3.7.0
@@ -17,7 +17,7 @@ async def test_get_token_cognito(
17
17
  authority_url=authority_url,
18
18
  client_id=client_id,
19
19
  client_secret=client_secret,
20
- verify_ssl=False,
20
+ verify_cert=False,
21
21
  timeout=10,
22
22
  ) as client,
23
23
  ):
@@ -1171,7 +1171,7 @@ requires-dist = [
1171
1171
  { name = "python3-commons", extras = ["database"], marker = "extra == 'authz'" },
1172
1172
  { name = "python3-commons", extras = ["object-storage"], marker = "extra == 'audit'" },
1173
1173
  { name = "requests", marker = "extra == 'soap-client'", specifier = "~=2.34.2" },
1174
- { name = "sqlalchemy", extras = ["asyncio"], marker = "extra == 'database'", specifier = "~=2.0.49" },
1174
+ { name = "sqlalchemy", extras = ["asyncio"], marker = "extra == 'database'", specifier = "~=2.0.50" },
1175
1175
  { name = "valkey", extras = ["libvalkey"], marker = "extra == 'cache'", specifier = "~=6.1.1" },
1176
1176
  { name = "zeep", extras = ["async"], marker = "extra == 'audit'", specifier = "~=4.3.2" },
1177
1177
  { name = "zeep", extras = ["async"], marker = "extra == 'soap-client'", specifier = "~=4.3.2" },
@@ -1331,28 +1331,29 @@ wheels = [
1331
1331
 
1332
1332
  [[package]]
1333
1333
  name = "sqlalchemy"
1334
- version = "2.0.49"
1334
+ version = "2.0.50"
1335
1335
  source = { registry = "https://pypi.org/simple" }
1336
1336
  dependencies = [
1337
1337
  { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
1338
1338
  { name = "typing-extensions" },
1339
1339
  ]
1340
- sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" }
1341
- wheels = [
1342
- { url = "https://files.pythonhosted.org/packages/55/33/bf28f618c0a9597d14e0b9ee7d1e0622faff738d44fe986ee287cdf1b8d0/sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:233088b4b99ebcbc5258c755a097aa52fbf90727a03a5a80781c4b9c54347a2e", size = 2156356, upload-time = "2026-04-03T16:53:09.914Z" },
1343
- { url = "https://files.pythonhosted.org/packages/d1/a7/5f476227576cb8644650eff68cc35fa837d3802b997465c96b8340ced1e2/sqlalchemy-2.0.49-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57ca426a48eb2c682dae8204cd89ea8ab7031e2675120a47924fabc7caacbc2a", size = 3276486, upload-time = "2026-04-03T17:07:46.9Z" },
1344
- { url = "https://files.pythonhosted.org/packages/2e/84/efc7c0bf3a1c5eef81d397f6fddac855becdbb11cb38ff957888603014a7/sqlalchemy-2.0.49-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:685e93e9c8f399b0c96a624799820176312f5ceef958c0f88215af4013d29066", size = 3281479, upload-time = "2026-04-03T17:12:32.226Z" },
1345
- { url = "https://files.pythonhosted.org/packages/91/68/bb406fa4257099c67bd75f3f2261b129c63204b9155de0d450b37f004698/sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e0400fa22f79acc334d9a6b185dc00a44a8e6578aa7e12d0ddcd8434152b187", size = 3226269, upload-time = "2026-04-03T17:07:48.678Z" },
1346
- { url = "https://files.pythonhosted.org/packages/67/84/acb56c00cca9f251f437cb49e718e14f7687505749ea9255d7bd8158a6df/sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a05977bffe9bffd2229f477fa75eabe3192b1b05f408961d1bebff8d1cd4d401", size = 3248260, upload-time = "2026-04-03T17:12:34.381Z" },
1347
- { url = "https://files.pythonhosted.org/packages/56/19/6a20ea25606d1efd7bd1862149bb2a22d1451c3f851d23d887969201633f/sqlalchemy-2.0.49-cp314-cp314-win32.whl", hash = "sha256:0f2fa354ba106eafff2c14b0cc51f22801d1e8b2e4149342023bd6f0955de5f5", size = 2118463, upload-time = "2026-04-03T17:05:47.093Z" },
1348
- { url = "https://files.pythonhosted.org/packages/cf/4f/8297e4ed88e80baa1f5aa3c484a0ee29ef3c69c7582f206c916973b75057/sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl", hash = "sha256:77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5", size = 2144204, upload-time = "2026-04-03T17:05:48.694Z" },
1349
- { url = "https://files.pythonhosted.org/packages/1f/33/95e7216df810c706e0cd3655a778604bbd319ed4f43333127d465a46862d/sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1dc3368794d522f43914e03312202523cc89692f5389c32bea0233924f8d977", size = 3565474, upload-time = "2026-04-03T16:58:35.128Z" },
1350
- { url = "https://files.pythonhosted.org/packages/0c/a4/ed7b18d8ccf7f954a83af6bb73866f5bc6f5636f44c7731fbb741f72cc4f/sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c821c47ecfe05cc32140dcf8dc6fd5d21971c86dbd56eabfe5ba07a64910c01", size = 3530567, upload-time = "2026-04-03T17:06:04.587Z" },
1351
- { url = "https://files.pythonhosted.org/packages/73/a3/20faa869c7e21a827c4a2a42b41353a54b0f9f5e96df5087629c306df71e/sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9c04bff9a5335eb95c6ecf1c117576a0aa560def274876fd156cfe5510fccc61", size = 3474282, upload-time = "2026-04-03T16:58:37.131Z" },
1352
- { url = "https://files.pythonhosted.org/packages/b7/50/276b9a007aa0764304ad467eceb70b04822dc32092492ee5f322d559a4dc/sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7f605a456948c35260e7b2a39f8952a26f077fd25653c37740ed186b90aaa68a", size = 3480406, upload-time = "2026-04-03T17:06:07.176Z" },
1353
- { url = "https://files.pythonhosted.org/packages/e5/c3/c80fcdb41905a2df650c2a3e0337198b6848876e63d66fe9188ef9003d24/sqlalchemy-2.0.49-cp314-cp314t-win32.whl", hash = "sha256:6270d717b11c5476b0cbb21eedc8d4dbb7d1a956fd6c15a23e96f197a6193158", size = 2149151, upload-time = "2026-04-03T17:02:07.281Z" },
1354
- { url = "https://files.pythonhosted.org/packages/05/52/9f1a62feab6ed368aff068524ff414f26a6daebc7361861035ae00b05530/sqlalchemy-2.0.49-cp314-cp314t-win_amd64.whl", hash = "sha256:275424295f4256fd301744b8f335cff367825d270f155d522b30c7bf49903ee7", size = 2184178, upload-time = "2026-04-03T17:02:08.623Z" },
1355
- { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" },
1340
+ sdist = { url = "https://files.pythonhosted.org/packages/57/da/6fbf010c8ebb347679d0d100b22fe9ba5e13fd04046c5df7280d2f0bf706/sqlalchemy-2.0.50.tar.gz", hash = "sha256:af5607d11ef90fd6a5c0549fe0045dce1663d427426bcfb506dcb5346a85a3b9", size = 9907424, upload-time = "2026-05-24T19:20:04.018Z" }
1341
+ wheels = [
1342
+ { url = "https://files.pythonhosted.org/packages/df/32/10ac51b4be7cdecd7e93d069251c86dfbf70b7adbd7c67b48ccea6c49e1c/sqlalchemy-2.0.50-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c966932507a4d7d0a37314927dbfcd89720e3f37d2a1e3352e7ae7939fa8e8a0", size = 2158519, upload-time = "2026-05-24T19:27:56.472Z" },
1343
+ { url = "https://files.pythonhosted.org/packages/5a/76/e703d2f7681d7d66c4c891af3f07c7ccf4c76ad7f18351de035b5eda007a/sqlalchemy-2.0.50-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:faffef4bcc20a1892e65e155293d99d60855bbbc79250ab712819cfd56a8e6bb", size = 3282063, upload-time = "2026-05-24T20:09:38.57Z" },
1344
+ { url = "https://files.pythonhosted.org/packages/31/26/ef168b184a25701f9995e8fb7e503fafd7a99c1c77cda1bc1a26ea2ed486/sqlalchemy-2.0.50-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c206aec519a2e7bd08abbfb33436e325fd22c632d9c21a9047e376ce241646e", size = 3287069, upload-time = "2026-05-24T20:17:21.942Z" },
1345
+ { url = "https://files.pythonhosted.org/packages/c2/15/765acc2bc693bccc43ca4a95d5b69750da8aaf6db1b5c616536e087f8920/sqlalchemy-2.0.50-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bef4ac756363227ef6402a75fee025a4bc690f92328e825868939b3b3a446a6d", size = 3230453, upload-time = "2026-05-24T20:09:40.398Z" },
1346
+ { url = "https://files.pythonhosted.org/packages/63/61/08e03c3adbf5db0087a0b6816746fec8f3032fb2f7fc899a9bb9b2a48ce4/sqlalchemy-2.0.50-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:96fbee6b19c19cd1556c8bf9419447cf2ec149ffcab7ab64348c23e54ef8547f", size = 3252413, upload-time = "2026-05-24T20:17:24.067Z" },
1347
+ { url = "https://files.pythonhosted.org/packages/03/0c/370a1f2db38436c615e10134c8a37de3688e74084792380695f3f5083860/sqlalchemy-2.0.50-cp314-cp314-win32.whl", hash = "sha256:8f00e3eb43ba30eb1b238ee03a8a62309486d1321eda3328bb611e0340033ad8", size = 2120063, upload-time = "2026-05-24T19:50:11.08Z" },
1348
+ { url = "https://files.pythonhosted.org/packages/7f/a0/fe92bb9817863bc13ba093bda931979a26cc2ca69f8e8f26d07add3d7c6f/sqlalchemy-2.0.50-cp314-cp314-win_amd64.whl", hash = "sha256:15708c613cd5005b7dffe1f66ee6a63ee8f5e46799f71c70ebad74178c676a39", size = 2145830, upload-time = "2026-05-24T19:50:12.452Z" },
1349
+ { url = "https://files.pythonhosted.org/packages/cc/ff/e5640a98a0b2f491eb8fde10fb6c773621a2e44340de231fafcc9370f4a9/sqlalchemy-2.0.50-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3699dac4be410e97049a1658e9480da9cde956594aa0f3aebc60b88f21c5ba70", size = 2178435, upload-time = "2026-05-24T19:42:58.889Z" },
1350
+ { url = "https://files.pythonhosted.org/packages/b7/85/337116e186f1236375b5fb70c21cfac98e8e8ab0d3a47be838dc47a59e08/sqlalchemy-2.0.50-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f96233858e3df43932ac11589e22520da6e8aeb624b03fedfeebb0e8ea213086", size = 3566059, upload-time = "2026-05-24T20:01:20.848Z" },
1351
+ { url = "https://files.pythonhosted.org/packages/96/34/bb0e190e161c3c2c24314a65add57218be14a4a9486886b7f5047c1ff7c8/sqlalchemy-2.0.50-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c4e70c46fad30c3bcc6a4708bc0130a3173e11a5b25f0ea4a9d8911b450f1f52", size = 3535366, upload-time = "2026-05-24T20:03:56.768Z" },
1352
+ { url = "https://files.pythonhosted.org/packages/df/5a/a7f759f97e4fd499c5d4e4488c760d5a7fbecf3028b465a04274fcd52384/sqlalchemy-2.0.50-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1918a3cf564d16d95bca7301005f41ab2ad50b07cd3b9da50d3ed986db148d6a", size = 3474879, upload-time = "2026-05-24T20:01:23.058Z" },
1353
+ { url = "https://files.pythonhosted.org/packages/9d/d9/2907ea38eb60687d297bf9c39e5ee58053c87b57fe8a9cae97090cecbf10/sqlalchemy-2.0.50-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b00098cdbdbd38c7be3d568b0c9c3122b8c0ec62b911b57cd5e6e0254d60a76d", size = 3486117, upload-time = "2026-05-24T20:03:59.052Z" },
1354
+ { url = "https://files.pythonhosted.org/packages/f2/e3/5aa06f167559f8c0bdae487e297d23ba548150ab016a3418265d617a4985/sqlalchemy-2.0.50-cp314-cp314t-win32.whl", hash = "sha256:1fbd55a969d7ac44a98e3dec75016074f809fa08f871585ace58dde110d1bf3e", size = 2150823, upload-time = "2026-05-24T20:08:58.644Z" },
1355
+ { url = "https://files.pythonhosted.org/packages/65/9b/112fb8f977582d7489d036e409e3723948bcf5320b3ac465f3c481bbe8f9/sqlalchemy-2.0.50-cp314-cp314t-win_amd64.whl", hash = "sha256:c5c3cdb753a9004183e1ccb634b41611654c989e61bc68617ce878e46d6f1e51", size = 2185794, upload-time = "2026-05-24T20:09:00.319Z" },
1356
+ { url = "https://files.pythonhosted.org/packages/d0/10/f7220e9b784d295d241c86ed99aeb537f92afcd469a64861f2717e9bb077/sqlalchemy-2.0.50-py3-none-any.whl", hash = "sha256:92064363517a3ff8212b5a93b8c62876579d8dfd1ca5b561335f30152d884fa9", size = 1943861, upload-time = "2026-05-24T19:59:01.119Z" },
1356
1357
  ]
1357
1358
 
1358
1359
  [package.optional-dependencies]