hexkit 7.0.0__tar.gz → 7.1.0__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.
- {hexkit-7.0.0/src/hexkit.egg-info → hexkit-7.1.0}/PKG-INFO +21 -22
- {hexkit-7.0.0 → hexkit-7.1.0}/pyproject.toml +26 -28
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/config.py +5 -4
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/custom_types.py +12 -14
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/log.py +3 -3
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/protocols/dao.py +5 -5
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/protocols/daopub.py +5 -6
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/protocols/eventpub.py +2 -3
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/protocols/objstorage.py +20 -24
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/config.py +2 -2
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/provider/daosub.py +1 -2
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/provider/eventpub.py +4 -4
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/provider/eventsub.py +11 -11
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/provider/utils.py +1 -2
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/testcontainer.py +6 -6
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/testutils.py +14 -14
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongodb/migrations/_manager.py +2 -2
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongodb/migrations/_utils.py +5 -5
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongodb/migrations/helpers.py +2 -3
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongodb/provider.py +4 -4
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongodb/testutils.py +2 -3
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongokafka/provider/daopub.py +5 -5
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongokafka/provider/persistent_pub.py +3 -4
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/provider.py +47 -46
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/testutils/_fixtures.py +6 -6
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/testing/eventpub.py +2 -2
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/utils.py +2 -2
- {hexkit-7.0.0 → hexkit-7.1.0/src/hexkit.egg-info}/PKG-INFO +21 -22
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit.egg-info/requires.txt +19 -19
- {hexkit-7.0.0 → hexkit-7.1.0}/LICENSE +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/MANIFEST.in +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/README.md +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/setup.cfg +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/__main__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/base.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/correlation.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/opentelemetry.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/protocols/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/protocols/daosub.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/protocols/eventsub.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/akafka/provider/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongodb/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongodb/migrations/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongokafka/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongokafka/provider/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongokafka/provider/config.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/mongokafka/testutils.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/test_files/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/test_files/test_file1.yaml +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/test_files/test_file2.yaml +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/test_files/test_file3.yaml +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/test_files/test_file4.yaml +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/testutils/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/testutils/_typical_workflow.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/s3/testutils/_utils.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/providers/testing/__init__.py +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit/py.typed +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit.egg-info/SOURCES.txt +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit.egg-info/dependency_links.txt +0 -0
- {hexkit-7.0.0 → hexkit-7.1.0}/src/hexkit.egg-info/top_level.txt +0 -0
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hexkit
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.1.0
|
|
4
4
|
Summary: A Toolkit for Building Microservices using the Hexagonal Architecture
|
|
5
5
|
Author-email: "German Human Genome Phenome Archive (GHGA)" <contact@ghga.de>
|
|
6
6
|
License: Apache 2.0
|
|
7
7
|
Project-URL: Repository, https://github.com/ghga-de/hexkit
|
|
8
8
|
Classifier: Development Status :: 5 - Production/Stable
|
|
9
9
|
Classifier: Operating System :: POSIX :: Linux
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
11
10
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -16,42 +15,42 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
16
15
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
17
16
|
Classifier: Topic :: Software Development :: Libraries
|
|
18
17
|
Classifier: Intended Audience :: Developers
|
|
19
|
-
Requires-Python: >=3.
|
|
18
|
+
Requires-Python: >=3.10
|
|
20
19
|
Description-Content-Type: text/markdown
|
|
21
20
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: opentelemetry-api<2,>=1.
|
|
23
|
-
Requires-Dist: pydantic<3,>=2.
|
|
24
|
-
Requires-Dist: pydantic_settings<3,>=2.
|
|
21
|
+
Requires-Dist: opentelemetry-api<2,>=1.37
|
|
22
|
+
Requires-Dist: pydantic<3,>=2.11
|
|
23
|
+
Requires-Dist: pydantic_settings<3,>=2.10
|
|
25
24
|
Requires-Dist: PyYAML<7,>=6
|
|
26
25
|
Provides-Extra: akafka
|
|
27
26
|
Requires-Dist: aiokafka[lz4,snappy,zstd]~=0.12.0; extra == "akafka"
|
|
28
|
-
Requires-Dist: jsonschema<5,>=4.
|
|
27
|
+
Requires-Dist: jsonschema<5,>=4.25; extra == "akafka"
|
|
29
28
|
Provides-Extra: s3
|
|
30
|
-
Requires-Dist: boto3<2,>=1.
|
|
31
|
-
Requires-Dist: botocore<2,>=1.
|
|
29
|
+
Requires-Dist: boto3<2,>=1.40; extra == "s3"
|
|
30
|
+
Requires-Dist: botocore<2,>=1.40; extra == "s3"
|
|
32
31
|
Provides-Extra: mongodb
|
|
33
|
-
Requires-Dist: pymongo<5,>=4.
|
|
32
|
+
Requires-Dist: pymongo<5,>=4.15; extra == "mongodb"
|
|
34
33
|
Provides-Extra: opentelemetry-base
|
|
35
|
-
Requires-Dist: opentelemetry-sdk<2,>=1.
|
|
36
|
-
Requires-Dist: opentelemetry-exporter-otlp<2,>=1.
|
|
37
|
-
Requires-Dist: opentelemetry-instrumentation>=0.
|
|
38
|
-
Requires-Dist: opentelemetry-instrumentation-httpx>=0.
|
|
39
|
-
Requires-Dist: opentelemetry-distro>=0.
|
|
34
|
+
Requires-Dist: opentelemetry-sdk<2,>=1.37.0; extra == "opentelemetry-base"
|
|
35
|
+
Requires-Dist: opentelemetry-exporter-otlp<2,>=1.37.0; extra == "opentelemetry-base"
|
|
36
|
+
Requires-Dist: opentelemetry-instrumentation>=0.58b0; extra == "opentelemetry-base"
|
|
37
|
+
Requires-Dist: opentelemetry-instrumentation-httpx>=0.58b0; extra == "opentelemetry-base"
|
|
38
|
+
Requires-Dist: opentelemetry-distro>=0.58b0; extra == "opentelemetry-base"
|
|
40
39
|
Provides-Extra: opentelemetry-akafka
|
|
41
40
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-akafka"
|
|
42
41
|
Requires-Dist: hexkit[akafka]; extra == "opentelemetry-akafka"
|
|
43
|
-
Requires-Dist: opentelemetry-instrumentation-aiokafka>=0.
|
|
42
|
+
Requires-Dist: opentelemetry-instrumentation-aiokafka>=0.58b0; extra == "opentelemetry-akafka"
|
|
44
43
|
Provides-Extra: opentelemetry-mongodb
|
|
45
44
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-mongodb"
|
|
46
45
|
Requires-Dist: hexkit[mongodb]; extra == "opentelemetry-mongodb"
|
|
47
|
-
Requires-Dist: opentelemetry-instrumentation-pymongo>=0.
|
|
46
|
+
Requires-Dist: opentelemetry-instrumentation-pymongo>=0.58b0; extra == "opentelemetry-mongodb"
|
|
48
47
|
Provides-Extra: opentelemetry-fastapi
|
|
49
48
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-fastapi"
|
|
50
|
-
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.
|
|
49
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.58b0; extra == "opentelemetry-fastapi"
|
|
51
50
|
Provides-Extra: opentelemetry-s3
|
|
52
51
|
Requires-Dist: hexkit[opentelemetry-base]; extra == "opentelemetry-s3"
|
|
53
52
|
Requires-Dist: hexkit[s3]; extra == "opentelemetry-s3"
|
|
54
|
-
Requires-Dist: opentelemetry-instrumentation-botocore>=0.
|
|
53
|
+
Requires-Dist: opentelemetry-instrumentation-botocore>=0.58b0; extra == "opentelemetry-s3"
|
|
55
54
|
Provides-Extra: opentelemetry
|
|
56
55
|
Requires-Dist: hexkit[opentelemetry-akafka]; extra == "opentelemetry"
|
|
57
56
|
Requires-Dist: hexkit[opentelemetry-mongodb]; extra == "opentelemetry"
|
|
@@ -59,13 +58,13 @@ Requires-Dist: hexkit[opentelemetry-fastapi]; extra == "opentelemetry"
|
|
|
59
58
|
Requires-Dist: hexkit[opentelemetry-s3]; extra == "opentelemetry"
|
|
60
59
|
Provides-Extra: test-akafka
|
|
61
60
|
Requires-Dist: hexkit[akafka]; extra == "test-akafka"
|
|
62
|
-
Requires-Dist: testcontainers[kafka]<5,>=4.
|
|
61
|
+
Requires-Dist: testcontainers[kafka]<5,>=4.13; extra == "test-akafka"
|
|
63
62
|
Provides-Extra: test-s3
|
|
64
63
|
Requires-Dist: hexkit[s3]; extra == "test-s3"
|
|
65
|
-
Requires-Dist: testcontainers<5,>=4.
|
|
64
|
+
Requires-Dist: testcontainers<5,>=4.13; extra == "test-s3"
|
|
66
65
|
Provides-Extra: test-mongodb
|
|
67
66
|
Requires-Dist: hexkit[mongodb]; extra == "test-mongodb"
|
|
68
|
-
Requires-Dist: testcontainers[mongo]<5,>=4.
|
|
67
|
+
Requires-Dist: testcontainers[mongo]<5,>=4.13; extra == "test-mongodb"
|
|
69
68
|
Provides-Extra: test
|
|
70
69
|
Requires-Dist: hexkit[test-akafka,test-mongodb,test-s3]; extra == "test"
|
|
71
70
|
Provides-Extra: all
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[build-system]
|
|
2
2
|
requires = [
|
|
3
|
-
"setuptools>=80.
|
|
3
|
+
"setuptools>=80.9",
|
|
4
4
|
]
|
|
5
5
|
build-backend = "setuptools.build_meta"
|
|
6
6
|
|
|
@@ -9,11 +9,10 @@ readme = "README.md"
|
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "German Human Genome Phenome Archive (GHGA)", email = "contact@ghga.de" },
|
|
11
11
|
]
|
|
12
|
-
requires-python = ">=3.
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
13
|
classifiers = [
|
|
14
14
|
"Development Status :: 5 - Production/Stable",
|
|
15
15
|
"Operating System :: POSIX :: Linux",
|
|
16
|
-
"Programming Language :: Python :: 3.9",
|
|
17
16
|
"Programming Language :: Python :: 3.10",
|
|
18
17
|
"Programming Language :: Python :: 3.11",
|
|
19
18
|
"Programming Language :: Python :: 3.12",
|
|
@@ -24,12 +23,12 @@ classifiers = [
|
|
|
24
23
|
"Intended Audience :: Developers",
|
|
25
24
|
]
|
|
26
25
|
name = "hexkit"
|
|
27
|
-
version = "7.
|
|
26
|
+
version = "7.1.0"
|
|
28
27
|
description = "A Toolkit for Building Microservices using the Hexagonal Architecture"
|
|
29
28
|
dependencies = [
|
|
30
|
-
"opentelemetry-api >=1.
|
|
31
|
-
"pydantic >=2.
|
|
32
|
-
"pydantic_settings >=2.
|
|
29
|
+
"opentelemetry-api >=1.37, <2",
|
|
30
|
+
"pydantic >=2.11, <3",
|
|
31
|
+
"pydantic_settings >=2.10, <3",
|
|
33
32
|
"PyYAML >=6, <7",
|
|
34
33
|
]
|
|
35
34
|
|
|
@@ -39,40 +38,40 @@ text = "Apache 2.0"
|
|
|
39
38
|
[project.optional-dependencies]
|
|
40
39
|
akafka = [
|
|
41
40
|
"aiokafka[zstd,lz4,snappy]~=0.12.0",
|
|
42
|
-
"jsonschema >=4.
|
|
41
|
+
"jsonschema >=4.25, <5",
|
|
43
42
|
]
|
|
44
43
|
s3 = [
|
|
45
|
-
"boto3 >=1.
|
|
46
|
-
"botocore >=1.
|
|
44
|
+
"boto3 >=1.40, <2",
|
|
45
|
+
"botocore >=1.40, <2",
|
|
47
46
|
]
|
|
48
47
|
mongodb = [
|
|
49
|
-
"pymongo >=4.
|
|
48
|
+
"pymongo >=4.15, <5",
|
|
50
49
|
]
|
|
51
50
|
opentelemetry-base = [
|
|
52
|
-
"opentelemetry-sdk >=1.
|
|
53
|
-
"opentelemetry-exporter-otlp >=1.
|
|
54
|
-
"opentelemetry-instrumentation >=0.
|
|
55
|
-
"opentelemetry-instrumentation-httpx >=0.
|
|
56
|
-
"opentelemetry-distro >=0.
|
|
51
|
+
"opentelemetry-sdk >=1.37.0, <2",
|
|
52
|
+
"opentelemetry-exporter-otlp >=1.37.0, <2",
|
|
53
|
+
"opentelemetry-instrumentation >=0.58b0",
|
|
54
|
+
"opentelemetry-instrumentation-httpx >=0.58b0",
|
|
55
|
+
"opentelemetry-distro >=0.58b0",
|
|
57
56
|
]
|
|
58
57
|
opentelemetry-akafka = [
|
|
59
58
|
"hexkit[opentelemetry-base]",
|
|
60
59
|
"hexkit[akafka]",
|
|
61
|
-
"opentelemetry-instrumentation-aiokafka >=0.
|
|
60
|
+
"opentelemetry-instrumentation-aiokafka >=0.58b0",
|
|
62
61
|
]
|
|
63
62
|
opentelemetry-mongodb = [
|
|
64
63
|
"hexkit[opentelemetry-base]",
|
|
65
64
|
"hexkit[mongodb]",
|
|
66
|
-
"opentelemetry-instrumentation-pymongo >=0.
|
|
65
|
+
"opentelemetry-instrumentation-pymongo >=0.58b0",
|
|
67
66
|
]
|
|
68
67
|
opentelemetry-fastapi = [
|
|
69
68
|
"hexkit[opentelemetry-base]",
|
|
70
|
-
"opentelemetry-instrumentation-fastapi >=0.
|
|
69
|
+
"opentelemetry-instrumentation-fastapi >=0.58b0",
|
|
71
70
|
]
|
|
72
71
|
opentelemetry-s3 = [
|
|
73
72
|
"hexkit[opentelemetry-base]",
|
|
74
73
|
"hexkit[s3]",
|
|
75
|
-
"opentelemetry-instrumentation-botocore >=0.
|
|
74
|
+
"opentelemetry-instrumentation-botocore >=0.58b0",
|
|
76
75
|
]
|
|
77
76
|
opentelemetry = [
|
|
78
77
|
"hexkit[opentelemetry-akafka]",
|
|
@@ -82,15 +81,15 @@ opentelemetry = [
|
|
|
82
81
|
]
|
|
83
82
|
test-akafka = [
|
|
84
83
|
"hexkit[akafka]",
|
|
85
|
-
"testcontainers[kafka] >=4.
|
|
84
|
+
"testcontainers[kafka] >=4.13, <5",
|
|
86
85
|
]
|
|
87
86
|
test-s3 = [
|
|
88
87
|
"hexkit[s3]",
|
|
89
|
-
"testcontainers >=4.
|
|
88
|
+
"testcontainers >=4.13, <5",
|
|
90
89
|
]
|
|
91
90
|
test-mongodb = [
|
|
92
91
|
"hexkit[mongodb]",
|
|
93
|
-
"testcontainers[mongo] >=4.
|
|
92
|
+
"testcontainers[mongo] >=4.13, <5",
|
|
94
93
|
]
|
|
95
94
|
test = [
|
|
96
95
|
"hexkit[test-akafka,test-s3,test-mongodb]",
|
|
@@ -123,7 +122,7 @@ src = [
|
|
|
123
122
|
"examples",
|
|
124
123
|
"scripts",
|
|
125
124
|
]
|
|
126
|
-
target-version = "
|
|
125
|
+
target-version = "py310"
|
|
127
126
|
|
|
128
127
|
[tool.ruff.lint]
|
|
129
128
|
fixable = [
|
|
@@ -210,7 +209,7 @@ check_untyped_defs = true
|
|
|
210
209
|
no_site_packages = false
|
|
211
210
|
|
|
212
211
|
[tool.pytest.ini_options]
|
|
213
|
-
minversion = "8.
|
|
212
|
+
minversion = "8.4"
|
|
214
213
|
asyncio_mode = "strict"
|
|
215
214
|
asyncio_default_fixture_loop_scope = "function"
|
|
216
215
|
|
|
@@ -224,11 +223,10 @@ source = [
|
|
|
224
223
|
[tool.tox]
|
|
225
224
|
legacy_tox_ini = """
|
|
226
225
|
[tox]
|
|
227
|
-
env_list = py3{
|
|
226
|
+
env_list = py3{10,11,12,13}
|
|
228
227
|
|
|
229
228
|
[gh-actions]
|
|
230
229
|
python =
|
|
231
|
-
3.9: py39
|
|
232
230
|
3.10: py310
|
|
233
231
|
3.11: py311
|
|
234
232
|
3.12: py312
|
|
@@ -241,6 +239,6 @@ legacy_tox_ini = """
|
|
|
241
239
|
deps =
|
|
242
240
|
--no-deps -r ./lock/requirements-dev.txt
|
|
243
241
|
commands =
|
|
244
|
-
|
|
242
|
+
py310: pip install --no-deps backports.asyncio.runner==1.2.0 exceptiongroup==1.3.0 tomli==2.2.1
|
|
245
243
|
pytest {posargs}
|
|
246
244
|
"""
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
"""Config parsing functionality based on pydantic's BaseSettings"""
|
|
17
17
|
|
|
18
18
|
import os
|
|
19
|
+
from collections.abc import Callable
|
|
19
20
|
from pathlib import Path
|
|
20
|
-
from typing import
|
|
21
|
+
from typing import Final
|
|
21
22
|
|
|
22
23
|
from pydantic_settings import (
|
|
23
24
|
BaseSettings,
|
|
@@ -33,7 +34,7 @@ DEFAULT_CONFIG_PREFIX: Final = "ghga_services"
|
|
|
33
34
|
class ConfigYamlDoesNotExist(RuntimeError):
|
|
34
35
|
"""Thrown when the context manager is used out of context."""
|
|
35
36
|
|
|
36
|
-
def __init__(self, path: Path, specified_via:
|
|
37
|
+
def __init__(self, path: Path, specified_via: str | None = None):
|
|
37
38
|
message = (
|
|
38
39
|
"The config yaml " + ""
|
|
39
40
|
if specified_via is None
|
|
@@ -42,7 +43,7 @@ class ConfigYamlDoesNotExist(RuntimeError):
|
|
|
42
43
|
super().__init__(message)
|
|
43
44
|
|
|
44
45
|
|
|
45
|
-
def get_default_config_yaml(prefix: str) ->
|
|
46
|
+
def get_default_config_yaml(prefix: str) -> Path | None:
|
|
46
47
|
"""Get the path to the default config function.
|
|
47
48
|
|
|
48
49
|
Args:
|
|
@@ -122,7 +123,7 @@ def config_from_yaml(
|
|
|
122
123
|
)
|
|
123
124
|
|
|
124
125
|
def constructor_wrapper(
|
|
125
|
-
config_yaml:
|
|
126
|
+
config_yaml: Path | None = None,
|
|
126
127
|
**kwargs,
|
|
127
128
|
):
|
|
128
129
|
"""A wrapper for constructing a pydantic BaseSetting with modified sources
|
|
@@ -18,29 +18,27 @@
|
|
|
18
18
|
|
|
19
19
|
from collections.abc import Mapping, Sequence
|
|
20
20
|
from datetime import date, datetime
|
|
21
|
-
from typing import Any, Literal
|
|
21
|
+
from typing import Any, Literal
|
|
22
22
|
from uuid import UUID
|
|
23
23
|
|
|
24
24
|
# A type for fields that can be used as identifiers (primary keys).
|
|
25
|
-
ID =
|
|
25
|
+
ID = int | str | UUID
|
|
26
26
|
|
|
27
27
|
# This is intended to type objects that are assumed to be JSON serializable.
|
|
28
28
|
# (Scalar types as well as arrays are excluded from the above assumption,
|
|
29
29
|
# and we serialize date, datetime and UUID objects to JSON as strings.)
|
|
30
30
|
JsonObject = Mapping[
|
|
31
31
|
str,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
None,
|
|
43
|
-
],
|
|
32
|
+
int
|
|
33
|
+
| float
|
|
34
|
+
| str
|
|
35
|
+
| bool
|
|
36
|
+
| date
|
|
37
|
+
| datetime
|
|
38
|
+
| UUID
|
|
39
|
+
| Sequence[Any]
|
|
40
|
+
| Mapping[str, Any]
|
|
41
|
+
| None,
|
|
44
42
|
]
|
|
45
43
|
|
|
46
44
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import json
|
|
20
20
|
from datetime import datetime, timezone
|
|
21
21
|
from logging import Formatter, Logger, LogRecord, StreamHandler, addLevelName, getLogger
|
|
22
|
-
from typing import Any, Literal
|
|
22
|
+
from typing import Any, Literal
|
|
23
23
|
|
|
24
24
|
from pydantic import Field
|
|
25
25
|
from pydantic_settings import BaseSettings
|
|
@@ -61,7 +61,7 @@ class LoggingConfig(BaseSettings):
|
|
|
61
61
|
+ " this service. This is included in log messages."
|
|
62
62
|
),
|
|
63
63
|
)
|
|
64
|
-
log_format:
|
|
64
|
+
log_format: str | None = Field(
|
|
65
65
|
default=None,
|
|
66
66
|
examples=[
|
|
67
67
|
"%(timestamp)s - %(service)s - %(level)s - %(message)s",
|
|
@@ -166,7 +166,7 @@ class RecordCompiler(StreamHandler):
|
|
|
166
166
|
return super().handle(record)
|
|
167
167
|
|
|
168
168
|
|
|
169
|
-
def configure_logging(*, config: LoggingConfig, logger:
|
|
169
|
+
def configure_logging(*, config: LoggingConfig, logger: Logger | None = None):
|
|
170
170
|
"""Set up logging.
|
|
171
171
|
|
|
172
172
|
Configures the root logger by default, but can be used to configure a specific
|
|
@@ -23,7 +23,7 @@ from abc import ABC, abstractmethod
|
|
|
23
23
|
from collections.abc import AsyncIterator, Collection, Mapping
|
|
24
24
|
from contextlib import AbstractAsyncContextManager
|
|
25
25
|
from functools import partial
|
|
26
|
-
from typing import Any,
|
|
26
|
+
from typing import Any, TypeVar
|
|
27
27
|
from uuid import uuid4
|
|
28
28
|
|
|
29
29
|
from pydantic import BaseModel, Field
|
|
@@ -268,7 +268,7 @@ class DaoFactoryBase:
|
|
|
268
268
|
cls,
|
|
269
269
|
*,
|
|
270
270
|
dto_model: type[Dto],
|
|
271
|
-
fields_to_index:
|
|
271
|
+
fields_to_index: Collection[str] | None,
|
|
272
272
|
) -> None:
|
|
273
273
|
"""Checks that all provided fields are present in the dto_model.
|
|
274
274
|
Raises IndexFieldsInvalidError otherwise.
|
|
@@ -289,7 +289,7 @@ class DaoFactoryBase:
|
|
|
289
289
|
*,
|
|
290
290
|
dto_model: type[Dto],
|
|
291
291
|
id_field: str,
|
|
292
|
-
fields_to_index:
|
|
292
|
+
fields_to_index: Collection[str] | None,
|
|
293
293
|
) -> None:
|
|
294
294
|
"""Validates the input parameters of the get_dao method."""
|
|
295
295
|
cls._validate_dto_model_id(dto_model=dto_model, id_field=id_field)
|
|
@@ -309,7 +309,7 @@ class DaoFactoryProtocol(DaoFactoryBase, ABC):
|
|
|
309
309
|
name: str,
|
|
310
310
|
dto_model: type[Dto],
|
|
311
311
|
id_field: str,
|
|
312
|
-
fields_to_index:
|
|
312
|
+
fields_to_index: Collection[str] | None = None,
|
|
313
313
|
) -> Dao[Dto]:
|
|
314
314
|
"""Constructs a DAO for interacting with resources in a database.
|
|
315
315
|
|
|
@@ -354,7 +354,7 @@ class DaoFactoryProtocol(DaoFactoryBase, ABC):
|
|
|
354
354
|
name: str,
|
|
355
355
|
dto_model: type[Dto],
|
|
356
356
|
id_field: str,
|
|
357
|
-
fields_to_index:
|
|
357
|
+
fields_to_index: Collection[str] | None,
|
|
358
358
|
) -> Dao[Dto]:
|
|
359
359
|
"""*To be implemented by the provider. Input validation is done outside of this
|
|
360
360
|
method.*
|
|
@@ -23,8 +23,7 @@ of the outbox pattern.
|
|
|
23
23
|
|
|
24
24
|
import typing
|
|
25
25
|
from abc import ABC, abstractmethod
|
|
26
|
-
from collections.abc import Collection
|
|
27
|
-
from typing import Callable, Optional
|
|
26
|
+
from collections.abc import Callable, Collection
|
|
28
27
|
|
|
29
28
|
from hexkit.custom_types import JsonObject
|
|
30
29
|
from hexkit.protocols.dao import (
|
|
@@ -61,8 +60,8 @@ class DaoPublisherFactoryProtocol(DaoFactoryBase, ABC):
|
|
|
61
60
|
name: str,
|
|
62
61
|
dto_model: type[Dto],
|
|
63
62
|
id_field: str,
|
|
64
|
-
fields_to_index:
|
|
65
|
-
dto_to_event: Callable[[Dto],
|
|
63
|
+
fields_to_index: Collection[str] | None = None,
|
|
64
|
+
dto_to_event: Callable[[Dto], JsonObject | None],
|
|
66
65
|
event_topic: str,
|
|
67
66
|
autopublish: bool = True,
|
|
68
67
|
) -> DaoPublisher[Dto]:
|
|
@@ -121,8 +120,8 @@ class DaoPublisherFactoryProtocol(DaoFactoryBase, ABC):
|
|
|
121
120
|
name: str,
|
|
122
121
|
dto_model: type[Dto],
|
|
123
122
|
id_field: str,
|
|
124
|
-
fields_to_index:
|
|
125
|
-
dto_to_event: Callable[[Dto],
|
|
123
|
+
fields_to_index: Collection[str] | None,
|
|
124
|
+
dto_to_event: Callable[[Dto], JsonObject | None],
|
|
126
125
|
event_topic: str,
|
|
127
126
|
autopublish: bool,
|
|
128
127
|
) -> DaoPublisher[Dto]:
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
|
|
19
19
|
from abc import ABC, abstractmethod
|
|
20
20
|
from collections.abc import Mapping
|
|
21
|
-
from typing import Optional
|
|
22
21
|
from uuid import UUID, uuid4
|
|
23
22
|
|
|
24
23
|
from pydantic import UUID4
|
|
@@ -37,8 +36,8 @@ class EventPublisherProtocol(ABC):
|
|
|
37
36
|
type_: Ascii,
|
|
38
37
|
key: Ascii,
|
|
39
38
|
topic: Ascii,
|
|
40
|
-
event_id:
|
|
41
|
-
headers:
|
|
39
|
+
event_id: UUID4 | None = None,
|
|
40
|
+
headers: Mapping[str, str] | None = None,
|
|
42
41
|
) -> None:
|
|
43
42
|
"""Publish an event.
|
|
44
43
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import re
|
|
22
22
|
from abc import ABC, abstractmethod
|
|
23
|
-
from typing import NamedTuple
|
|
23
|
+
from typing import NamedTuple
|
|
24
24
|
|
|
25
25
|
__all__ = ["ObjectStorageProtocol", "PresignedPostURL"]
|
|
26
26
|
|
|
@@ -85,7 +85,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
85
85
|
bucket_id: str,
|
|
86
86
|
object_id: str,
|
|
87
87
|
expires_after: int = DEFAULT_URL_EXPIRATION_PERIOD,
|
|
88
|
-
max_upload_size:
|
|
88
|
+
max_upload_size: int | None = None,
|
|
89
89
|
) -> PresignedPostURL:
|
|
90
90
|
"""Generates and returns an HTTP URL to upload a new file object with the given
|
|
91
91
|
id (`object_id`) to the bucket with the specified id (`bucket_id`).
|
|
@@ -122,7 +122,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
122
122
|
object_id: str,
|
|
123
123
|
part_number: int,
|
|
124
124
|
expires_after: int = 3600,
|
|
125
|
-
part_md5:
|
|
125
|
+
part_md5: str | None = None,
|
|
126
126
|
) -> str:
|
|
127
127
|
"""Given a id of an instantiated multipart upload along with the corresponding
|
|
128
128
|
bucket and object ID, it returns a presigned URL for uploading a file part with the
|
|
@@ -163,8 +163,8 @@ class ObjectStorageProtocol(ABC):
|
|
|
163
163
|
upload_id: str,
|
|
164
164
|
bucket_id: str,
|
|
165
165
|
object_id: str,
|
|
166
|
-
anticipated_part_quantity:
|
|
167
|
-
anticipated_part_size:
|
|
166
|
+
anticipated_part_quantity: int | None = None,
|
|
167
|
+
anticipated_part_size: int | None = None,
|
|
168
168
|
) -> None:
|
|
169
169
|
"""Completes a multipart upload with the specified ID. In addition to the
|
|
170
170
|
corresponding bucket and object id, you also specify an anticipated part size
|
|
@@ -196,7 +196,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
196
196
|
)
|
|
197
197
|
|
|
198
198
|
async def does_object_exist(
|
|
199
|
-
self, *, bucket_id: str, object_id: str, object_md5sum:
|
|
199
|
+
self, *, bucket_id: str, object_id: str, object_md5sum: str | None = None
|
|
200
200
|
) -> bool:
|
|
201
201
|
"""Check whether an object with specified ID (`object_id`) exists in the bucket
|
|
202
202
|
with the specified id (`bucket_id`). Optionally, a md5 checksum (`object_md5sum`)
|
|
@@ -314,7 +314,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
314
314
|
bucket_id: str,
|
|
315
315
|
object_id: str,
|
|
316
316
|
expires_after: int = 86400,
|
|
317
|
-
max_upload_size:
|
|
317
|
+
max_upload_size: int | None = None,
|
|
318
318
|
) -> PresignedPostURL:
|
|
319
319
|
"""
|
|
320
320
|
Generates and returns an HTTP URL to upload a new file object with the given
|
|
@@ -351,7 +351,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
351
351
|
object_id: str,
|
|
352
352
|
part_number: int,
|
|
353
353
|
expires_after: int = 3600,
|
|
354
|
-
part_md5:
|
|
354
|
+
part_md5: str | None = None,
|
|
355
355
|
) -> str:
|
|
356
356
|
"""
|
|
357
357
|
Given a id of an instantiated multipart upload along with the corresponding
|
|
@@ -389,8 +389,8 @@ class ObjectStorageProtocol(ABC):
|
|
|
389
389
|
upload_id: str,
|
|
390
390
|
bucket_id: str,
|
|
391
391
|
object_id: str,
|
|
392
|
-
anticipated_part_quantity:
|
|
393
|
-
anticipated_part_size:
|
|
392
|
+
anticipated_part_quantity: int | None = None,
|
|
393
|
+
anticipated_part_size: int | None = None,
|
|
394
394
|
) -> None:
|
|
395
395
|
"""
|
|
396
396
|
Completes a multipart upload with the specified ID. In addition to the
|
|
@@ -438,7 +438,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
438
438
|
|
|
439
439
|
@abstractmethod
|
|
440
440
|
async def _does_object_exist(
|
|
441
|
-
self, *, bucket_id: str, object_id: str, object_md5sum:
|
|
441
|
+
self, *, bucket_id: str, object_id: str, object_md5sum: str | None = None
|
|
442
442
|
) -> bool:
|
|
443
443
|
"""
|
|
444
444
|
Check whether an object with specified ID (`object_id`) exists in the bucket
|
|
@@ -549,7 +549,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
549
549
|
class BucketNotFoundError(BucketError):
|
|
550
550
|
"""Thrown when trying to access a bucket with an ID that doesn't exist."""
|
|
551
551
|
|
|
552
|
-
def __init__(self, bucket_id:
|
|
552
|
+
def __init__(self, bucket_id: str | None):
|
|
553
553
|
with_id = f" with ID '{bucket_id}'" if bucket_id else ""
|
|
554
554
|
message = f"The bucket{with_id} does not exist."
|
|
555
555
|
super().__init__(message)
|
|
@@ -557,7 +557,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
557
557
|
class BucketAlreadyExistsError(BucketError):
|
|
558
558
|
"""Thrown when trying to create a bucket with an ID that already exists."""
|
|
559
559
|
|
|
560
|
-
def __init__(self, bucket_id:
|
|
560
|
+
def __init__(self, bucket_id: str | None):
|
|
561
561
|
with_id = f" with ID '{bucket_id}'" if bucket_id else ""
|
|
562
562
|
message = f"The bucket{with_id} already exists."
|
|
563
563
|
super().__init__(message)
|
|
@@ -565,7 +565,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
565
565
|
class BucketNotEmptyError(BucketError):
|
|
566
566
|
"""Thrown when trying to delete a bucket that is not empty."""
|
|
567
567
|
|
|
568
|
-
def __init__(self, bucket_id:
|
|
568
|
+
def __init__(self, bucket_id: str | None):
|
|
569
569
|
with_id = f" with ID '{bucket_id}'" if bucket_id else ""
|
|
570
570
|
super().__init__(f"The bucket{with_id} is not empty.")
|
|
571
571
|
|
|
@@ -575,9 +575,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
575
575
|
class ObjectNotFoundError(ObjectError):
|
|
576
576
|
"""Thrown when trying to access a bucket with an ID that doesn't exist."""
|
|
577
577
|
|
|
578
|
-
def __init__(
|
|
579
|
-
self, bucket_id: Optional[str] = None, object_id: Optional[str] = None
|
|
580
|
-
):
|
|
578
|
+
def __init__(self, bucket_id: str | None = None, object_id: str | None = None):
|
|
581
579
|
with_id = f" with ID '{object_id}'" if object_id else ""
|
|
582
580
|
in_bucket = f" in bucket with ID '{bucket_id}'" if bucket_id else ""
|
|
583
581
|
message = f"The object{with_id}{in_bucket} does not exist."
|
|
@@ -586,9 +584,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
586
584
|
class ObjectAlreadyExistsError(ObjectError):
|
|
587
585
|
"""Thrown when trying to access a file with an ID that doesn't exist."""
|
|
588
586
|
|
|
589
|
-
def __init__(
|
|
590
|
-
self, bucket_id: Optional[str] = None, object_id: Optional[str] = None
|
|
591
|
-
):
|
|
587
|
+
def __init__(self, bucket_id: str | None = None, object_id: str | None = None):
|
|
592
588
|
with_id = f" with ID '{object_id}'" if object_id else ""
|
|
593
589
|
in_bucket = f" in bucket with ID '{bucket_id}'" if bucket_id else ""
|
|
594
590
|
message = f"The object{with_id}{in_bucket} already exists."
|
|
@@ -597,7 +593,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
597
593
|
class BucketIdValidationError(BucketError):
|
|
598
594
|
"""Thrown when a bucket ID is not valid."""
|
|
599
595
|
|
|
600
|
-
def __init__(self, bucket_id: str, reason:
|
|
596
|
+
def __init__(self, bucket_id: str, reason: str | None):
|
|
601
597
|
with_reason = f": {reason}." if reason else "."
|
|
602
598
|
message = f"The specified bucket ID '{bucket_id}' is not valid{with_reason}"
|
|
603
599
|
super().__init__(message)
|
|
@@ -605,7 +601,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
605
601
|
class ObjectIdValidationError(ObjectError):
|
|
606
602
|
"""Thrown when an object ID is not valid."""
|
|
607
603
|
|
|
608
|
-
def __init__(self, object_id: str, reason:
|
|
604
|
+
def __init__(self, object_id: str, reason: str | None):
|
|
609
605
|
with_reason = f": {reason}." if reason else "."
|
|
610
606
|
message = f"The specified object ID '{object_id}' is not valid{with_reason}"
|
|
611
607
|
super().__init__(message)
|
|
@@ -644,7 +640,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
644
640
|
upload_id: str,
|
|
645
641
|
bucket_id: str,
|
|
646
642
|
object_id: str,
|
|
647
|
-
details:
|
|
643
|
+
details: str | None = None,
|
|
648
644
|
):
|
|
649
645
|
with_details = f": {details}." if details else "."
|
|
650
646
|
message = (
|
|
@@ -661,7 +657,7 @@ class ObjectStorageProtocol(ABC):
|
|
|
661
657
|
upload_id: str,
|
|
662
658
|
bucket_id: str,
|
|
663
659
|
object_id: str,
|
|
664
|
-
reason:
|
|
660
|
+
reason: str | None = None,
|
|
665
661
|
):
|
|
666
662
|
with_reason = f": {reason}." if reason else "."
|
|
667
663
|
message = (
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
"""Apache Kafka specific configuration."""
|
|
18
18
|
|
|
19
|
-
from typing import Literal
|
|
19
|
+
from typing import Literal
|
|
20
20
|
|
|
21
21
|
from pydantic import Field, NonNegativeInt, PositiveInt, SecretStr
|
|
22
22
|
from pydantic_settings import BaseSettings
|
|
@@ -87,7 +87,7 @@ class KafkaConfig(BaseSettings):
|
|
|
87
87
|
+ " field, which effectively concerns the compressed message size.",
|
|
88
88
|
examples=[1024 * 1024, 16 * 1024 * 1024],
|
|
89
89
|
)
|
|
90
|
-
kafka_compression_type:
|
|
90
|
+
kafka_compression_type: KafkaCompressionType | None = Field(
|
|
91
91
|
default=None,
|
|
92
92
|
description=(
|
|
93
93
|
"The compression type used for messages. Valid values are: None, gzip,"
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
import logging
|
|
22
22
|
from collections.abc import Sequence
|
|
23
23
|
from contextlib import asynccontextmanager
|
|
24
|
-
from typing import Optional
|
|
25
24
|
|
|
26
25
|
from aiokafka import AIOKafkaConsumer
|
|
27
26
|
|
|
@@ -56,7 +55,7 @@ class KafkaOutboxSubscriber(InboundProviderBase):
|
|
|
56
55
|
*,
|
|
57
56
|
config: KafkaConfig,
|
|
58
57
|
translators: Sequence[DaoSubscriberProtocol],
|
|
59
|
-
dlq_publisher:
|
|
58
|
+
dlq_publisher: EventPublisherProtocol | None = None,
|
|
60
59
|
kafka_consumer_cls: type[KafkaConsumerCompatible] = AIOKafkaConsumer,
|
|
61
60
|
):
|
|
62
61
|
"""Setup and teardown an instance of the provider.
|