fairagro-middleware-api-client 10.0.3.dev26__tar.gz → 11.0.1.dev27__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 (22) hide show
  1. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/.gitignore +0 -3
  2. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/PKG-INFO +1 -1
  3. fairagro_middleware_api_client-10.0.3.dev26/spec/harvest-client/design.md +0 -72
  4. fairagro_middleware_api_client-10.0.3.dev26/spec/harvest-client/spec.md +0 -50
  5. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/README.md +0 -0
  6. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/example_client_config.yaml +0 -0
  7. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/pyproject.toml +0 -0
  8. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/__init__.py +0 -0
  9. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/api_client.py +0 -0
  10. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/config.py +0 -0
  11. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/models.py +0 -0
  12. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/src/middleware/api_client/py.typed +0 -0
  13. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/client_test_support.py +0 -0
  14. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/conftest.py +0 -0
  15. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/integration/conftest.py +0 -0
  16. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/integration/test_create_arcs.py +0 -0
  17. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/conftest.py +0 -0
  18. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_api_client_config.py +0 -0
  19. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_client.py +0 -0
  20. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_client_config.py +0 -0
  21. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_harvest_arcs.py +0 -0
  22. {fairagro_middleware_api_client-10.0.3.dev26 → fairagro_middleware_api_client-11.0.1.dev27}/tests/unit/test_retry_logic.py +0 -0
@@ -228,6 +228,3 @@ helmchart/**/client_ext.conf
228
228
  .cache_ggshield
229
229
 
230
230
  docker/Dockerfile.api.bak
231
- # Docker DinD: ignore runtime state in docker-config, keep minimal config.json tracked
232
- .devcontainer/docker-config/*
233
- !.devcontainer/docker-config/config.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fairagro-middleware-api-client
3
- Version: 10.0.3.dev26
3
+ Version: 11.0.1.dev27
4
4
  Summary: The FAIRagro advanced middleware API client
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: httpx>=0.28.1
@@ -1,72 +0,0 @@
1
- # Harvest Client — Design
2
-
3
- ## Module Overview
4
-
5
- `ApiClient` (`api_client.py`) orchestrates the harvest lifecycle.
6
- `HarvestResult`, `HarvestStatistics`, `HarvestError`, and `HarvestErrorType`
7
- (`models.py`) are the stable public types exposed to harvesters.
8
-
9
- ```text
10
- harvester
11
- └─→ ApiClient.harvest_arcs(rdi, arcs)
12
- ├─→ create_harvest → HarvestResult (RUNNING)
13
- ├─→ _submit_arcs_parallel
14
- │ ├─→ duplicate check (client-side) → HarvestError(DUPLICATE)
15
- │ └─→ POST v3/harvests/{id}/arcs → HarvestError(SUBMISSION_FAILED) on error
16
- └─→ complete_harvest → HarvestResult (COMPLETED)
17
- └─→ inject client_errors via model_copy → HarvestResult.errors
18
- ```
19
-
20
- ## Key Decisions
21
-
22
- 1. **`HarvestStatistics` is a typed Pydantic model, not `dict`**
23
- — The server serializes its internal `HarvestStatistics` via `model_dump()`
24
- before sending it over the wire. The field names and types are stable and
25
- known. A typed model gives consumers validated, IDE-navigable fields rather
26
- than requiring dict key lookups with no type safety.
27
-
28
- 2. **`HarvestError` is a client-facing type in `models.py`, independent of any server model**
29
- — Per-item errors are currently generated client-side. When the server
30
- persists them natively (issue #240), `_parse_harvest_response` will
31
- populate `HarvestResult.errors` from the server response automatically —
32
- the type and consumer interface remain unchanged.
33
-
34
- 3. **`arc_id: str | None` in `HarvestError`**
35
- — The `DUPLICATE` and `SUBMISSION_FAILED` categories always have a
36
- known ARC identifier (when one is extractable from the RO-Crate). Future
37
- error categories — such as harvest-level timeouts or config failures —
38
- may not be associated with any specific ARC. `None` is the semantically
39
- correct representation; an empty string would be an invisible sentinel
40
- value that callers would need to treat specially.
41
-
42
- 4. **Client-side error collection as compatibility shim until issue #240**
43
- — `harvest_arcs()` collects errors from `_submit_arcs_parallel()` and
44
- merges them into the server response via `model_copy(update=...)`.
45
- This shim is removed once the server persists and returns per-item errors
46
- natively. The `model_copy` merge is additive: if the server already
47
- returns errors in its response (post-#240), client-side errors are
48
- appended rather than overwriting.
49
-
50
- 5. **Duplicate detection is performed client-side before the HTTP request**
51
- — Within one harvest batch, two different ARC payloads that share an
52
- identifier are a harvester bug. Detecting them client-side yields an
53
- explicit `DUPLICATE` error and avoids the round-trip. The server still
54
- enforces harvest-local identity: identical re-submits (e.g. transport
55
- retries) return `200`; conflicting content for the same identifier returns
56
- `409` (see `harvest-arc-upload/`). Client-side detection therefore covers
57
- *intra-batch* duplicates; server idempotency covers *retry* duplicates.
58
-
59
- 6. **Item-level failures are non-fatal; harvest-level failures are fatal**
60
- — A submission failure for one ARC (e.g. server 422 on bad content) must
61
- not abort the entire harvest because the remaining ARCs may be valid. A
62
- catastrophic failure (e.g. 401 Unauthorized, harvest already closed) means
63
- no further submissions will succeed, so the harvest is aborted, marked
64
- `FAILED`, and the exception propagates to the caller.
65
-
66
- 7. **POST ARC endpoints retry transport failures**
67
- — `POST /v3/arcs` and `POST /v3/harvests/{id}/arcs` are server-idempotent for
68
- identical bodies, so the client retries `ConnectError` and transient gateway
69
- statuses (`502`/`503`/`504`) on those paths without risking a second object.
70
- Other POSTs (create/complete harvest) are not retried. Conflicting `409`
71
- (same identifier, different content in one harvest) remains a real conflict
72
- and is not treated as success.
@@ -1,50 +0,0 @@
1
- # Harvest Client
2
-
3
- Manage the full lifecycle of a harvest run — creation, parallel ARC
4
- submission, error collection, and finalization — on behalf of a harvester
5
- process. The client returns a typed result that captures both statistics
6
- and per-item errors so harvesters can produce complete reports.
7
-
8
- ## Requirements
9
-
10
- - [ ] Create a harvest run for a given RDI, submit all ARCs from an async
11
- source in bounded parallelism, and return the completed harvest result
12
- as a single operation.
13
- - [ ] Accept an optional expected-dataset count at the start of a harvest to
14
- enable progress tracking on the server side.
15
- - [ ] Return typed harvest statistics (submitted, new, updated, unchanged,
16
- missing counts, and optional expected-dataset count) as structured
17
- fields rather than an opaque mapping.
18
- - [ ] Record per-item errors encountered during submission and include them
19
- in the returned harvest result.
20
- - [ ] Classify each per-item error into one of the following categories:
21
- `duplicate` (two ARCs share the same identifier) or `submission_failed`
22
- (the server rejected or could not process the ARC).
23
- - [ ] Each per-item error carries: the error category, a human-readable
24
- message, and an ISO 8601 timestamp of when the error occurred.
25
- - [ ] Optionally associate a per-item error with an ARC identifier; errors
26
- that do not relate to a specific ARC (e.g. harvest-level failures) may
27
- omit the identifier.
28
- - [ ] Detect duplicate ARC identifiers before submission and record them as
29
- `duplicate` errors; do not submit the duplicate.
30
- - [ ] Skip individual ARC submission failures and continue the harvest with
31
- remaining items; record each failure as a `submission_failed` error.
32
- - [ ] Abort the entire harvest on catastrophic errors (e.g. authentication
33
- failure, invalid harvest state) and mark the harvest as failed before
34
- propagating the exception to the caller.
35
-
36
- ## Edge Cases
37
-
38
- ARC with no extractable RO-Crate identifier → submitted normally; any
39
- resulting error records no ARC identifier (`null`).
40
-
41
- Two ARCs share the same identifier → the second is skipped; a `duplicate`
42
- error is recorded for it; the first continues to be submitted normally.
43
-
44
- Catastrophic error during submission → remaining tasks are cancelled; the
45
- harvest is transitioned to `FAILED`; the exception propagates to the caller.
46
-
47
- No per-item errors → the returned result contains an empty errors list.
48
-
49
- `expected_datasets` not provided → harvest is created without a progress
50
- denominator; statistics show raw counts only.