fairagro-middleware-api-client 8.6.2__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.
@@ -0,0 +1,229 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Allow encrypted .env.integration.enc but ignore any unencrypted .env files
148
+ !.env.integration.enc
149
+
150
+ # Spyder project settings
151
+ .spyderproject
152
+ .spyproject
153
+
154
+ # Rope project settings
155
+ .ropeproject
156
+
157
+ # mkdocs documentation
158
+ /site
159
+
160
+ # mypy
161
+ .mypy_cache/
162
+ .dmypy.json
163
+ dmypy.json
164
+
165
+ # Pyre type checker
166
+ .pyre/
167
+
168
+ # pytype static type analyzer
169
+ .pytype/
170
+
171
+ # Cython debug symbols
172
+ cython_debug/
173
+
174
+ # PyCharm
175
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
176
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
177
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
178
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
179
+ #.idea/
180
+
181
+ # Abstra
182
+ # Abstra is an AI-powered process automation framework.
183
+ # Ignore directories containing user credentials, local state, and settings.
184
+ # Learn more at https://abstra.io/docs
185
+ .abstra/
186
+
187
+ # Visual Studio Code
188
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
189
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
190
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
191
+ # you could uncomment the following to ignore the entire vscode folder
192
+ # .vscode/
193
+
194
+ # Ruff stuff:
195
+ .ruff_cache/
196
+
197
+ # PyPI configuration file
198
+ .pypirc
199
+
200
+ # Cursor
201
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
202
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
203
+ # refer to https://docs.cursor.com/context/ignore-files
204
+ .cursorignore
205
+ .cursorindexingignore
206
+
207
+ # Marimo
208
+ marimo/_static/
209
+ marimo/_lsp/
210
+ __marimo__/
211
+
212
+ scratch/
213
+ **/*.csv
214
+ **/*.stats
215
+
216
+ **/*.decrypted.*
217
+
218
+ # Cryptographic keys and certificates for testing that are not meant to be committed
219
+ helmchart/**/*.crt
220
+ helmchart/**/*.key
221
+ helmchart/**/*.csr
222
+ helmchart/**/*.srl
223
+ helmchart/**/server.conf
224
+ helmchart/**/client_ext.conf
225
+
226
+ # ggshield cache
227
+ .cache_ggshield
228
+
229
+ docker/Dockerfile.api.bak
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: fairagro-middleware-api-client
3
+ Version: 8.6.2
4
+ Summary: The FAIRagro advanced middleware API client
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: httpx>=0.28.1
7
+ Requires-Dist: pydantic>=2.12.5
8
+ Description-Content-Type: text/markdown
9
+
10
+ # Middleware API Client
11
+
12
+ Python client for the FAIRagro Middleware API with certificate-based authentication (mTLS).
13
+
14
+ ## Features
15
+
16
+ - ✅ Certificate-based authentication (mutual TLS)
17
+ - ✅ Configuration via YAML files, environment variables, or Docker secrets
18
+ - ✅ Async context manager support
19
+ - ✅ Comprehensive error handling
20
+ - ✅ Type-safe with Pydantic models
21
+
22
+ ## Installation
23
+
24
+ This package is part of the FAIRagro Advanced Middleware project and uses local dependencies.
25
+
26
+ ## Quick Start
27
+
28
+ ### 1. Create Configuration File
29
+
30
+ ```yaml
31
+ # config.yaml
32
+ log_level: INFO
33
+ api_url: https://your-api-server:8000
34
+ client_cert_path: /path/to/client-cert.pem
35
+ client_key_path: /path/to/client-key.pem
36
+ ca_cert_path: /path/to/ca-cert.pem # optional
37
+ timeout: 30.0
38
+ verify_ssl: true
39
+ ```
40
+
41
+ ### 2. Use the Client
42
+
43
+ ```python
44
+ import asyncio
45
+ from pathlib import Path
46
+ from arctrl import ARC, ArcInvestigation
47
+ from middleware.api_client import Config, ApiClient
48
+
49
+
50
+ async def main():
51
+ # Load configuration
52
+ config = Config.from_yaml_file(Path("config.yaml"))
53
+
54
+ # Create ARC object
55
+ inv = ArcInvestigation.create(identifier="my-arc", title="My ARC")
56
+ arc = ARC.from_arc_investigation(inv)
57
+
58
+ # Use client with context manager
59
+ async with ApiClient(config) as client:
60
+ # Send a single ARC
61
+ response = await client.create_or_update_arc(
62
+ rdi="my-rdi",
63
+ arc=arc,
64
+ )
65
+ print(f"ARC status: {response.status}")
66
+
67
+ # Or run a harvest workflow
68
+ async def arc_stream():
69
+ yield arc
70
+
71
+ harvest = await client.harvest_arcs(
72
+ rdi="my-rdi",
73
+ arcs=arc_stream(),
74
+ expected_datasets=1,
75
+ )
76
+ print(f"Harvest status: {harvest.status}")
77
+
78
+
79
+ asyncio.run(main())
80
+ ```
81
+
82
+ ## Configuration Options
83
+
84
+ | Option | Type | Required | Default | Description |
85
+ | ------ | ---- | -------- | ------- | ----------- |
86
+ | `log_level` | string | No | INFO | Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
87
+ | `api_url` | string | Yes | - | Base URL of the Middleware API |
88
+ | `client_cert_path` | string | No | null | Path to client certificate (PEM format) |
89
+ | `client_key_path` | string | No | null | Path to client private key (PEM format) |
90
+ | `ca_cert_path` | string | No | null | Path to CA certificate for server verification |
91
+ | `timeout` | float | No | 30.0 | Request timeout in seconds |
92
+ | `verify_ssl` | bool | No | true | Enable SSL certificate verification |
93
+ | `max_concurrency` | int | No | 10 | Maximum concurrent API requests (also default for `harvest_arcs`) |
94
+
95
+ ## API Methods
96
+
97
+ ### `create_or_update_arc(rdi: str, arc: ARC | dict) -> ArcResult`
98
+
99
+ Create or update one ARC in the Middleware API.
100
+
101
+ **Parameters:**
102
+
103
+ - `rdi` (str): The RDI identifier (e.g., "edaphobase").
104
+ - `arc` (ARC | dict): ARC object from arctrl or pre-serialised RO-Crate dict.
105
+
106
+ **Returns:**
107
+
108
+ - `ArcResult`: Contains the result of the operation.
109
+
110
+ **Raises:**
111
+
112
+ - `ApiClientError`: If the request fails due to HTTP errors or network issues.
113
+
114
+ **Example:**
115
+
116
+ ```python
117
+ from arctrl import ARC, ArcInvestigation
118
+
119
+ inv = ArcInvestigation.create(identifier="my-arc-001", title="My ARC")
120
+ arc = ARC.from_arc_investigation(inv)
121
+
122
+ response = await client.create_or_update_arc(
123
+ rdi="edaphobase",
124
+ arc=arc,
125
+ )
126
+ ```
127
+
128
+ ### `harvest_arcs(rdi: str, arcs: AsyncIterator[ARC | dict], expected_datasets: int | None = None) -> HarvestResult`
129
+
130
+ Convenience workflow to create a harvest, upload all ARCs from an async iterator, and complete the harvest.
131
+
132
+ - Uses `config.max_concurrency` by default.
133
+ - Continues on item-level submission errors and skips failed items.
134
+ - Cancels the harvest only for catastrophic errors.
135
+
136
+ All errors are raised as `ApiClientError` exceptions:
137
+
138
+ ```python
139
+ from middleware.api_client import ApiClientError
140
+
141
+ try:
142
+ response = await client.create_or_update_arc(
143
+ rdi="my-rdi",
144
+ arc=arc,
145
+ )
146
+ except ApiClientError as e:
147
+ print(f"API Error: {e}")
148
+ ```
149
+
150
+ ## Configuration via Environment Variables
151
+
152
+ You can override configuration values using environment variables:
153
+
154
+ ```bash
155
+ export API_URL="https://production-api:8000"
156
+ export CLIENT_CERT_PATH="/secure/certs/prod-cert.pem"
157
+ export CLIENT_KEY_PATH="/secure/certs/prod-key.pem"
158
+ ```
159
+
160
+ Or use Docker secrets in `/run/secrets/`.
161
+
162
+ ## License
163
+
164
+ This is part of the FAIRagro Advanced Middleware project.
@@ -0,0 +1,155 @@
1
+ # Middleware API Client
2
+
3
+ Python client for the FAIRagro Middleware API with certificate-based authentication (mTLS).
4
+
5
+ ## Features
6
+
7
+ - ✅ Certificate-based authentication (mutual TLS)
8
+ - ✅ Configuration via YAML files, environment variables, or Docker secrets
9
+ - ✅ Async context manager support
10
+ - ✅ Comprehensive error handling
11
+ - ✅ Type-safe with Pydantic models
12
+
13
+ ## Installation
14
+
15
+ This package is part of the FAIRagro Advanced Middleware project and uses local dependencies.
16
+
17
+ ## Quick Start
18
+
19
+ ### 1. Create Configuration File
20
+
21
+ ```yaml
22
+ # config.yaml
23
+ log_level: INFO
24
+ api_url: https://your-api-server:8000
25
+ client_cert_path: /path/to/client-cert.pem
26
+ client_key_path: /path/to/client-key.pem
27
+ ca_cert_path: /path/to/ca-cert.pem # optional
28
+ timeout: 30.0
29
+ verify_ssl: true
30
+ ```
31
+
32
+ ### 2. Use the Client
33
+
34
+ ```python
35
+ import asyncio
36
+ from pathlib import Path
37
+ from arctrl import ARC, ArcInvestigation
38
+ from middleware.api_client import Config, ApiClient
39
+
40
+
41
+ async def main():
42
+ # Load configuration
43
+ config = Config.from_yaml_file(Path("config.yaml"))
44
+
45
+ # Create ARC object
46
+ inv = ArcInvestigation.create(identifier="my-arc", title="My ARC")
47
+ arc = ARC.from_arc_investigation(inv)
48
+
49
+ # Use client with context manager
50
+ async with ApiClient(config) as client:
51
+ # Send a single ARC
52
+ response = await client.create_or_update_arc(
53
+ rdi="my-rdi",
54
+ arc=arc,
55
+ )
56
+ print(f"ARC status: {response.status}")
57
+
58
+ # Or run a harvest workflow
59
+ async def arc_stream():
60
+ yield arc
61
+
62
+ harvest = await client.harvest_arcs(
63
+ rdi="my-rdi",
64
+ arcs=arc_stream(),
65
+ expected_datasets=1,
66
+ )
67
+ print(f"Harvest status: {harvest.status}")
68
+
69
+
70
+ asyncio.run(main())
71
+ ```
72
+
73
+ ## Configuration Options
74
+
75
+ | Option | Type | Required | Default | Description |
76
+ | ------ | ---- | -------- | ------- | ----------- |
77
+ | `log_level` | string | No | INFO | Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL) |
78
+ | `api_url` | string | Yes | - | Base URL of the Middleware API |
79
+ | `client_cert_path` | string | No | null | Path to client certificate (PEM format) |
80
+ | `client_key_path` | string | No | null | Path to client private key (PEM format) |
81
+ | `ca_cert_path` | string | No | null | Path to CA certificate for server verification |
82
+ | `timeout` | float | No | 30.0 | Request timeout in seconds |
83
+ | `verify_ssl` | bool | No | true | Enable SSL certificate verification |
84
+ | `max_concurrency` | int | No | 10 | Maximum concurrent API requests (also default for `harvest_arcs`) |
85
+
86
+ ## API Methods
87
+
88
+ ### `create_or_update_arc(rdi: str, arc: ARC | dict) -> ArcResult`
89
+
90
+ Create or update one ARC in the Middleware API.
91
+
92
+ **Parameters:**
93
+
94
+ - `rdi` (str): The RDI identifier (e.g., "edaphobase").
95
+ - `arc` (ARC | dict): ARC object from arctrl or pre-serialised RO-Crate dict.
96
+
97
+ **Returns:**
98
+
99
+ - `ArcResult`: Contains the result of the operation.
100
+
101
+ **Raises:**
102
+
103
+ - `ApiClientError`: If the request fails due to HTTP errors or network issues.
104
+
105
+ **Example:**
106
+
107
+ ```python
108
+ from arctrl import ARC, ArcInvestigation
109
+
110
+ inv = ArcInvestigation.create(identifier="my-arc-001", title="My ARC")
111
+ arc = ARC.from_arc_investigation(inv)
112
+
113
+ response = await client.create_or_update_arc(
114
+ rdi="edaphobase",
115
+ arc=arc,
116
+ )
117
+ ```
118
+
119
+ ### `harvest_arcs(rdi: str, arcs: AsyncIterator[ARC | dict], expected_datasets: int | None = None) -> HarvestResult`
120
+
121
+ Convenience workflow to create a harvest, upload all ARCs from an async iterator, and complete the harvest.
122
+
123
+ - Uses `config.max_concurrency` by default.
124
+ - Continues on item-level submission errors and skips failed items.
125
+ - Cancels the harvest only for catastrophic errors.
126
+
127
+ All errors are raised as `ApiClientError` exceptions:
128
+
129
+ ```python
130
+ from middleware.api_client import ApiClientError
131
+
132
+ try:
133
+ response = await client.create_or_update_arc(
134
+ rdi="my-rdi",
135
+ arc=arc,
136
+ )
137
+ except ApiClientError as e:
138
+ print(f"API Error: {e}")
139
+ ```
140
+
141
+ ## Configuration via Environment Variables
142
+
143
+ You can override configuration values using environment variables:
144
+
145
+ ```bash
146
+ export API_URL="https://production-api:8000"
147
+ export CLIENT_CERT_PATH="/secure/certs/prod-cert.pem"
148
+ export CLIENT_KEY_PATH="/secure/certs/prod-key.pem"
149
+ ```
150
+
151
+ Or use Docker secrets in `/run/secrets/`.
152
+
153
+ ## License
154
+
155
+ This is part of the FAIRagro Advanced Middleware project.
@@ -0,0 +1,23 @@
1
+ # Example Configuration for Middleware API Client
2
+
3
+ # Logging level (CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET)
4
+ log_level: INFO
5
+
6
+ # Base URL of the Middleware API
7
+ api_url: https://localhost:8000
8
+
9
+ # Path to the client certificate file (PEM format)
10
+ client_cert_path: /path/to/client-cert.pem
11
+
12
+ # Path to the client private key file (PEM format)
13
+ client_key_path: /path/to/client-key.pem
14
+
15
+ # Path to the CA certificate file for server verification (optional)
16
+ # Set to null or omit if not needed
17
+ ca_cert_path: /path/to/ca-cert.pem
18
+
19
+ # Request timeout in seconds
20
+ timeout: "30.0"
21
+
22
+ # Enable SSL certificate verification
23
+ verify_ssl: true
@@ -0,0 +1,48 @@
1
+ [project]
2
+ name = "fairagro-middleware-api-client"
3
+ dynamic = ["version"]
4
+ description = "The FAIRagro advanced middleware API client"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "httpx>=0.28.1",
9
+ "pydantic>=2.12.5",
10
+ ]
11
+
12
+ [dependency-groups]
13
+ dev = [
14
+ "pytest>=9.0.2",
15
+ "pytest-asyncio>=1.1.0",
16
+ "pytest-mock>=3.10.0",
17
+ "respx>=0.20.0",
18
+ "cryptography>=45.0.6",
19
+ "types-pyyaml>=6.0.12.20240917",
20
+ ]
21
+
22
+ [tool.uv.sources]
23
+ shared = { path = "../shared", editable = true }
24
+
25
+ [tool.pytest.ini_options]
26
+ asyncio_mode = "auto"
27
+ testpaths = ["tests"]
28
+ python_files = ["test_*.py"]
29
+ python_classes = ["Test*"]
30
+ python_functions = ["test_*"]
31
+ addopts = "-v --strict-markers --tb=short"
32
+ markers = [
33
+ "asyncio: marks tests as async (deselect with '-m \"not asyncio\"')",
34
+ ]
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["src/middleware"]
38
+
39
+ [tool.ruff]
40
+ extend = "../../pyproject.toml"
41
+
42
+ [tool.hatch.version]
43
+ source = "vcs"
44
+ raw-options = { root = "../..", fallback_version = "0.0.0", tag_regex = "^(?:v|.*-(?:chart|docker)-v)(?P<version>\\d+\\.\\d+\\.\\d+)(?:$|[-+].*)" }
45
+
46
+ [build-system]
47
+ requires = ["hatchling", "hatch-vcs"]
48
+ build-backend = "hatchling.build"
@@ -0,0 +1,18 @@
1
+ """The FAIRagro Middleware API Client package."""
2
+
3
+ from .api_client import ApiClient, ApiClientError
4
+ from .config import Config
5
+ from .models import ArcEventSummary, ArcLifecycleStatus, ArcMetadata, ArcResult, ArcStatus, HarvestResult, HarvestStatus
6
+
7
+ __all__ = [
8
+ "Config",
9
+ "ApiClient",
10
+ "ApiClientError",
11
+ "ArcResult",
12
+ "ArcStatus",
13
+ "ArcLifecycleStatus",
14
+ "ArcMetadata",
15
+ "ArcEventSummary",
16
+ "HarvestResult",
17
+ "HarvestStatus",
18
+ ]