python3-commons 0.18.19__tar.gz → 0.18.20__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.
- {python3_commons-0.18.19/src/python3_commons.egg-info → python3_commons-0.18.20}/PKG-INFO +1 -1
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/auth.py +17 -7
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/conf.py +2 -2
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/helpers.py +17 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/object_storage.py +4 -4
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/soap_client.py +16 -14
- {python3_commons-0.18.19 → python3_commons-0.18.20/src/python3_commons.egg-info}/PKG-INFO +1 -1
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.coveragerc +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.devcontainer/Dockerfile +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.devcontainer/devcontainer.json +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.devcontainer/docker-compose.yml +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.env_template +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.github/workflows/checks.yml +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.github/workflows/python-publish.yaml +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.github/workflows/release-on-tag-push.yml +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.gitignore +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.pre-commit-config.yaml +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/.python-version +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/AUTHORS.rst +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/CHANGELOG.rst +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/LICENSE +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/README.md +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/README.rst +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/docs/Makefile +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/docs/_static/.gitignore +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/docs/authors.rst +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/docs/changelog.rst +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/docs/conf.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/docs/index.rst +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/docs/license.rst +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/pyproject.toml +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/setup.cfg +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/api_client.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/async_functools.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/audit.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/cache.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/db/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/db/helpers.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/db/models/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/db/models/auth.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/db/models/common.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/db/models/rbac.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/db/models/users.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/exceptions.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/fs.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/generators.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/log/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/log/filters.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/log/formatters.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/permissions.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/common.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/json.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/msgpack.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/msgspec.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons.egg-info/SOURCES.txt +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons.egg-info/dependency_links.txt +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons.egg-info/requires.txt +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons.egg-info/top_level.txt +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/integration/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/integration/test_cache.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/integration/test_osc.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/conftest.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/log/__init__.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/log/test_formatters.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/test_async_functools.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/test_audit.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/test_helpers.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/test_msgpack.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/tests/unit/test_msgspec.py +0 -0
- {python3_commons-0.18.19 → python3_commons-0.18.20}/uv.lock +0 -0
|
@@ -5,6 +5,10 @@ from collections.abc import Sequence
|
|
|
5
5
|
from http import HTTPStatus
|
|
6
6
|
from typing import Self, TypeVar
|
|
7
7
|
|
|
8
|
+
from pydantic import HttpUrl
|
|
9
|
+
|
|
10
|
+
from python3_commons.helpers import replace_origin
|
|
11
|
+
|
|
8
12
|
try:
|
|
9
13
|
import aiohttp
|
|
10
14
|
except ImportError as e:
|
|
@@ -45,9 +49,6 @@ class TokenData(msgspec.Struct):
|
|
|
45
49
|
|
|
46
50
|
|
|
47
51
|
T = TypeVar('T', bound=TokenData)
|
|
48
|
-
OIDC_CONFIG_URL = (
|
|
49
|
-
f'{oidc_settings.authority_internal_url or oidc_settings.authority_url}/.well-known/openid-configuration'
|
|
50
|
-
)
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
class OIDCTokenResponse(msgspec.Struct):
|
|
@@ -65,7 +66,16 @@ async def fetch_openid_config() -> dict:
|
|
|
65
66
|
"""
|
|
66
67
|
Fetch the OpenID configuration (including JWKS URI) from OIDC authority.
|
|
67
68
|
"""
|
|
68
|
-
|
|
69
|
+
if (authority_url := oidc_settings.authority_url) is None:
|
|
70
|
+
msg = 'OIDC authority URL is required'
|
|
71
|
+
raise ValueError(msg)
|
|
72
|
+
|
|
73
|
+
if oidc_settings.authority_internal_host:
|
|
74
|
+
authority_url = replace_origin(authority_url, oidc_settings.authority_internal_host)
|
|
75
|
+
|
|
76
|
+
oidc_config_url = f'{authority_url}/.well-known/openid-configuration'
|
|
77
|
+
|
|
78
|
+
async with aiohttp.ClientSession() as session, session.get(oidc_config_url) as response:
|
|
69
79
|
if response.status != HTTPStatus.OK:
|
|
70
80
|
_msg = 'Failed to fetch OpenID configuration'
|
|
71
81
|
|
|
@@ -78,10 +88,10 @@ async def fetch_jwks(jwks_uri: str) -> dict:
|
|
|
78
88
|
"""
|
|
79
89
|
Fetch the JSON Web Key Set (JWKS) for validating the token's signature.
|
|
80
90
|
"""
|
|
81
|
-
if oidc_settings.
|
|
91
|
+
if authority_internal_host := oidc_settings.authority_internal_host:
|
|
82
92
|
logger.debug('Received jwks_uri: %s', jwks_uri)
|
|
83
|
-
logger.debug('Replacing OIDC authority host with: %s',
|
|
84
|
-
jwks_uri =
|
|
93
|
+
logger.debug('Replacing OIDC authority host with: %s', authority_internal_host)
|
|
94
|
+
jwks_uri = str(replace_origin(HttpUrl(jwks_uri), authority_internal_host))
|
|
85
95
|
logger.debug('Modified jwks_uri: %s', jwks_uri)
|
|
86
96
|
|
|
87
97
|
async with aiohttp.ClientSession() as session, session.get(jwks_uri) as response:
|
|
@@ -18,8 +18,8 @@ class CommonSettings(BaseSettings):
|
|
|
18
18
|
class OIDCSettings(BaseSettings):
|
|
19
19
|
model_config = SettingsConfigDict(env_prefix='OIDC_')
|
|
20
20
|
|
|
21
|
-
authority_url: HttpUrl | None = None
|
|
22
|
-
|
|
21
|
+
authority_url: HttpUrl | None = None # https://login.externaldomain.com/realm/app
|
|
22
|
+
authority_internal_host: HttpUrl | None = None # http://localhost:8080/ which will substitute host in authority_url
|
|
23
23
|
client_id: str | None = None
|
|
24
24
|
client_secret: SecretStr = SecretStr('')
|
|
25
25
|
redirect_uri: str | None = None
|
|
@@ -15,6 +15,8 @@ from json import dumps
|
|
|
15
15
|
from typing import ClassVar, Literal
|
|
16
16
|
from urllib.parse import urlencode
|
|
17
17
|
|
|
18
|
+
from pydantic import HttpUrl
|
|
19
|
+
|
|
18
20
|
from python3_commons.serializers.json import CustomJSONEncoder
|
|
19
21
|
|
|
20
22
|
logger = logging.getLogger(__name__)
|
|
@@ -159,3 +161,18 @@ def parse_string_list(v: str | Sequence[str]) -> Sequence[str]:
|
|
|
159
161
|
return tuple(map(str.strip, v.split(',')))
|
|
160
162
|
|
|
161
163
|
return v
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def replace_origin(url: HttpUrl, host_url: HttpUrl) -> HttpUrl:
|
|
167
|
+
if host_url.host is None:
|
|
168
|
+
msg = 'Host URL must have a host'
|
|
169
|
+
raise ValueError(msg)
|
|
170
|
+
|
|
171
|
+
return HttpUrl.build(
|
|
172
|
+
scheme=host_url.scheme,
|
|
173
|
+
host=host_url.host,
|
|
174
|
+
port=host_url.port,
|
|
175
|
+
path=url.path,
|
|
176
|
+
query=url.query,
|
|
177
|
+
fragment=url.fragment,
|
|
178
|
+
)
|
|
@@ -140,7 +140,7 @@ async def list_objects(bucket_name: str, prefix: str, *, recursive: bool = True)
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
async def get_object_streams(
|
|
143
|
-
|
|
143
|
+
bucket_name: str, path: str, *, recursive: bool = True
|
|
144
144
|
) -> AsyncGenerator[tuple[str, datetime, StreamingBody]]:
|
|
145
145
|
async for obj in list_objects(bucket_name, path, recursive=recursive):
|
|
146
146
|
object_name = obj['Key']
|
|
@@ -151,7 +151,7 @@ async def get_object_streams(
|
|
|
151
151
|
|
|
152
152
|
|
|
153
153
|
async def get_objects(
|
|
154
|
-
|
|
154
|
+
bucket_name: str, path: str, *, recursive: bool = True
|
|
155
155
|
) -> AsyncGenerator[tuple[str, datetime, bytes]]:
|
|
156
156
|
async for object_name, last_modified, stream in get_object_streams(bucket_name, path, recursive=recursive):
|
|
157
157
|
data = await stream.read()
|
|
@@ -174,7 +174,7 @@ async def remove_object(bucket_name: str, path: str) -> None:
|
|
|
174
174
|
|
|
175
175
|
|
|
176
176
|
async def remove_objects(
|
|
177
|
-
|
|
177
|
+
bucket_name: str, prefix: str | None = None, object_names: Iterable[str] | None = None
|
|
178
178
|
) -> Sequence[Mapping] | None:
|
|
179
179
|
storage = ObjectStorage(s3_settings)
|
|
180
180
|
|
|
@@ -197,7 +197,7 @@ async def remove_objects(
|
|
|
197
197
|
chunk_size = 1000
|
|
198
198
|
|
|
199
199
|
for i in range(0, len(objects_to_delete), chunk_size):
|
|
200
|
-
chunk = objects_to_delete[i: i + chunk_size]
|
|
200
|
+
chunk = objects_to_delete[i : i + chunk_size]
|
|
201
201
|
|
|
202
202
|
response = await s3_client.delete_objects(Bucket=bucket_name, Delete={'Objects': chunk})
|
|
203
203
|
|
|
@@ -145,28 +145,30 @@ class AsyncTransport(Transport):
|
|
|
145
145
|
return b''
|
|
146
146
|
|
|
147
147
|
async def _fetch() -> bytes:
|
|
148
|
-
async with
|
|
148
|
+
async with (
|
|
149
|
+
ClientSession(
|
|
149
150
|
connector=TCPConnector(ssl=_make_ssl_context(verify=self._config.verify_ssl)),
|
|
150
151
|
timeout=ClientTimeout(total=self._config.timeout),
|
|
151
152
|
headers={'User-Agent': f'Zeep/{get_version()} (www.python-zeep.org)'},
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
)
|
|
160
|
-
|
|
153
|
+
) as session,
|
|
154
|
+
session.get(url, proxy=self._config.proxy) as resp,
|
|
155
|
+
):
|
|
156
|
+
body = await resp.read()
|
|
157
|
+
if resp.status >= 400:
|
|
158
|
+
raise TransportError(
|
|
159
|
+
status_code=resp.status,
|
|
160
|
+
message=body.decode(errors='ignore'),
|
|
161
|
+
)
|
|
162
|
+
return body
|
|
161
163
|
|
|
162
164
|
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
|
|
163
165
|
return pool.submit(asyncio.run, _fetch()).result()
|
|
164
166
|
|
|
165
167
|
async def post_xml(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
self,
|
|
169
|
+
address: str,
|
|
170
|
+
envelope: Any,
|
|
171
|
+
headers: dict[str, str],
|
|
170
172
|
) -> Response:
|
|
171
173
|
return await self.post(address, etree_to_string(envelope), headers)
|
|
172
174
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/.github/workflows/release-on-tag-push.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/db/models/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/__init__.py
RENAMED
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/common.py
RENAMED
|
File without changes
|
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/msgpack.py
RENAMED
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons/serializers/msgspec.py
RENAMED
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons.egg-info/requires.txt
RENAMED
|
File without changes
|
{python3_commons-0.18.19 → python3_commons-0.18.20}/src/python3_commons.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|