reconify-python 1.0.0__tar.gz → 2.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.
Files changed (38) hide show
  1. reconify_python-2.1.0/.openapi-contract.json +4 -0
  2. {reconify_python-1.0.0 → reconify_python-2.1.0}/CHANGELOG.md +5 -0
  3. {reconify_python-1.0.0 → reconify_python-2.1.0}/PKG-INFO +8 -8
  4. {reconify_python-1.0.0 → reconify_python-2.1.0}/README.md +7 -7
  5. reconify_python-2.1.0/UPGRADING.md +36 -0
  6. {reconify_python-1.0.0 → reconify_python-2.1.0}/pyproject.toml +1 -1
  7. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/client.py +2 -2
  8. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/models.py +1 -0
  9. reconify_python-2.1.0/src/reconify/resources/__init__.py +71 -0
  10. {reconify_python-1.0.0 → reconify_python-2.1.0}/tests/test_client.py +7 -5
  11. {reconify_python-1.0.0 → reconify_python-2.1.0}/tests/test_openapi_coverage.py +5 -5
  12. {reconify_python-1.0.0 → reconify_python-2.1.0}/uv.lock +1 -1
  13. reconify_python-1.0.0/.openapi-contract.json +0 -4
  14. reconify_python-1.0.0/UPGRADING.md +0 -17
  15. reconify_python-1.0.0/src/reconify/resources/__init__.py +0 -54
  16. {reconify_python-1.0.0 → reconify_python-2.1.0}/.bumpversion.cfg +0 -0
  17. {reconify_python-1.0.0 → reconify_python-2.1.0}/.conductor/settings.toml +0 -0
  18. {reconify_python-1.0.0 → reconify_python-2.1.0}/.github/workflows/ci.yml +0 -0
  19. {reconify_python-1.0.0 → reconify_python-2.1.0}/.github/workflows/release.yml +0 -0
  20. {reconify_python-1.0.0 → reconify_python-2.1.0}/.github/workflows/sync-contract.yml +0 -0
  21. {reconify_python-1.0.0 → reconify_python-2.1.0}/.gitignore +0 -0
  22. {reconify_python-1.0.0 → reconify_python-2.1.0}/AGENTS.md +0 -0
  23. {reconify_python-1.0.0 → reconify_python-2.1.0}/LICENSE +0 -0
  24. {reconify_python-1.0.0 → reconify_python-2.1.0}/context7.json +0 -0
  25. {reconify_python-1.0.0 → reconify_python-2.1.0}/reports/api-error-data-report.md +0 -0
  26. {reconify_python-1.0.0 → reconify_python-2.1.0}/scripts/fetch_contract.py +0 -0
  27. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/__init__.py +0 -0
  28. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/errors.py +0 -0
  29. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/pagination.py +0 -0
  30. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/py.typed +0 -0
  31. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/resources/base.py +0 -0
  32. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/resources/events.py +0 -0
  33. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/resources/ingestion.py +0 -0
  34. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/resources/issues.py +0 -0
  35. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/resources/metadata.py +0 -0
  36. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/resources/organization.py +0 -0
  37. {reconify_python-1.0.0 → reconify_python-2.1.0}/src/reconify/transport.py +0 -0
  38. {reconify_python-1.0.0 → reconify_python-2.1.0}/tests/test_pagination.py +0 -0
@@ -0,0 +1,4 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "sha256": "5cccdf920a62fb325c7fcf9410728889858d156831a78760e41e3f98774db7f2"
4
+ }
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.1.0
4
+
5
+ - Added optional `correlation_id` support to the typed monitoring event request
6
+ model and ingestion serialization.
7
+
3
8
  ## 1.0.0
4
9
 
5
10
  - Rebuilt the client for the current 13-operation public monitoring API.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: reconify-python
3
- Version: 1.0.0
3
+ Version: 2.1.0
4
4
  Summary: Typed Python client for the Reconify Public API
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -18,7 +18,7 @@ Description-Content-Type: text/markdown
18
18
 
19
19
  # Reconify Python SDK
20
20
 
21
- Typed synchronous and asynchronous clients for the public Reconify v1 API.
21
+ Typed synchronous and asynchronous clients for the public Reconify v2 API.
22
22
 
23
23
  ## Installation and quickstart
24
24
 
@@ -36,8 +36,8 @@ with Reconify(api_key="rk_...") as client:
36
36
  ```
37
37
 
38
38
  The API key may also come from `RECONIFY_API_KEY`. The default endpoint is
39
- `https://api.reconifyhq.com/v1`. `RECONIFY_API_URL` or `base_url` can select a
40
- staging or self-hosted endpoint, and URLs with or without `/v1` are accepted.
39
+ `https://api.reconifyhq.com/v2`. `RECONIFY_API_URL` or `base_url` can select a
40
+ staging or self-hosted endpoint, and URLs with or without `/v2` are accepted.
41
41
 
42
42
  ## Public resources
43
43
 
@@ -74,11 +74,11 @@ The default source is the public manifest at
74
74
  set `RECONIFY_OPENAPI_SPEC` to an explicit OpenAPI JSON file. The SDK never
75
75
  depends on another checkout or an absolute workspace path.
76
76
 
77
- ## Migration to 1.0.0
77
+ ## Migration to 2.0.0
78
78
 
79
- Version `1.0.0` targets the current monitoring and issue-investigation API. The
80
- former ledger, wallet, setup, search, alert, and reconciliation methods are
81
- removed because they are not part of the public contract. See
79
+ Version `2.0.0` targets the v2 monitoring and issue-investigation API at `/v2`.
80
+ Generated operation IDs use stable `resource_action` identifiers while the
81
+ Python resource methods retain their snake_case names. See
82
82
  [UPGRADING.md](UPGRADING.md).
83
83
 
84
84
  ## Build and release
@@ -1,6 +1,6 @@
1
1
  # Reconify Python SDK
2
2
 
3
- Typed synchronous and asynchronous clients for the public Reconify v1 API.
3
+ Typed synchronous and asynchronous clients for the public Reconify v2 API.
4
4
 
5
5
  ## Installation and quickstart
6
6
 
@@ -18,8 +18,8 @@ with Reconify(api_key="rk_...") as client:
18
18
  ```
19
19
 
20
20
  The API key may also come from `RECONIFY_API_KEY`. The default endpoint is
21
- `https://api.reconifyhq.com/v1`. `RECONIFY_API_URL` or `base_url` can select a
22
- staging or self-hosted endpoint, and URLs with or without `/v1` are accepted.
21
+ `https://api.reconifyhq.com/v2`. `RECONIFY_API_URL` or `base_url` can select a
22
+ staging or self-hosted endpoint, and URLs with or without `/v2` are accepted.
23
23
 
24
24
  ## Public resources
25
25
 
@@ -56,11 +56,11 @@ The default source is the public manifest at
56
56
  set `RECONIFY_OPENAPI_SPEC` to an explicit OpenAPI JSON file. The SDK never
57
57
  depends on another checkout or an absolute workspace path.
58
58
 
59
- ## Migration to 1.0.0
59
+ ## Migration to 2.0.0
60
60
 
61
- Version `1.0.0` targets the current monitoring and issue-investigation API. The
62
- former ledger, wallet, setup, search, alert, and reconciliation methods are
63
- removed because they are not part of the public contract. See
61
+ Version `2.0.0` targets the v2 monitoring and issue-investigation API at `/v2`.
62
+ Generated operation IDs use stable `resource_action` identifiers while the
63
+ Python resource methods retain their snake_case names. See
64
64
  [UPGRADING.md](UPGRADING.md).
65
65
 
66
66
  ## Build and release
@@ -0,0 +1,36 @@
1
+ # Upgrading to 2.0.0
2
+
3
+ The 2.0.0 client targets the public Reconify v2 contract at `/v2`.
4
+ Generated operation IDs now use stable `resource_action` identifiers. The
5
+ Python resource methods keep their existing snake_case names.
6
+
7
+ Use these resources:
8
+
9
+ - metadata: API information and health
10
+ - events: event listing, lookup, and issue-linked evidence
11
+ - ingestion: monitoring event batches
12
+ - issues: issue listing, lookup, assignment, notes, and linked data
13
+ - organization: organization and member reads
14
+
15
+ Python models use snake_case fields and preserve unknown enum values through
16
+ tolerant string enums. Existing v1 clients can continue using `/v1`; v2
17
+ clients must use the v2 artifact and endpoint.
18
+
19
+ ## Upgrading to 2.1.0
20
+
21
+ The 2.1.0 client adds the optional `correlation_id` field to
22
+ `MonitoringEvent`. Use it when the same transaction spans services that report
23
+ different references:
24
+
25
+ ```python
26
+ MonitoringEvent(
27
+ flow="payment_to_wallet",
28
+ type="payment.succeeded",
29
+ reference="order-123",
30
+ entity_id="wallet-123",
31
+ correlation_id="checkout-123",
32
+ )
33
+ ```
34
+
35
+ The value is sent as event metadata and does not change operation grouping or
36
+ evaluation behavior.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "reconify-python"
7
- version = "1.0.0"
7
+ version = "2.1.0"
8
8
  description = "Typed Python client for the Reconify Public API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -26,12 +26,12 @@ from .resources import (
26
26
  )
27
27
  from .transport import AsyncTransport, RetryConfig, SyncTransport
28
28
 
29
- DEFAULT_BASE_URL = "https://api.reconifyhq.com/v1"
29
+ DEFAULT_BASE_URL = "https://api.reconifyhq.com/v2"
30
30
 
31
31
 
32
32
  def _normalize_base_url(base_url: str | None) -> str:
33
33
  value = (base_url or os.getenv("RECONIFY_API_URL") or DEFAULT_BASE_URL).rstrip("/")
34
- return value if value.endswith("/v1") else f"{value}/v1"
34
+ return value if value.endswith("/v2") else f"{value}/v2"
35
35
 
36
36
 
37
37
  def _api_key(api_key: str | None) -> str:
@@ -131,6 +131,7 @@ class MonitoringEvent(RequestModel):
131
131
  entity_id: str
132
132
  occurred_at: datetime | None = None
133
133
  amount: str | None = None
134
+ correlation_id: str | None = None
134
135
  currency: str | None = None
135
136
  data: MonitoringEventData | None = None
136
137
  metadata: dict[str, str | int | float | bool] | None = None
@@ -0,0 +1,71 @@
1
+ """Resource clients grouped by the current public API surface."""
2
+
3
+ from .events import AsyncEvents, Events
4
+ from .ingestion import AsyncIngestion, Ingestion
5
+ from .issues import AsyncIssues, Issues
6
+ from .metadata import AsyncMetadata, Metadata
7
+ from .organization import AsyncOrganization, Organization
8
+
9
+ SYNC_RESOURCE_CLASSES = {
10
+ "metadata": Metadata,
11
+ "events": Events,
12
+ "ingestion": Ingestion,
13
+ "issues": Issues,
14
+ "organization": Organization,
15
+ }
16
+ ASYNC_RESOURCE_CLASSES = {
17
+ "metadata": AsyncMetadata,
18
+ "events": AsyncEvents,
19
+ "ingestion": AsyncIngestion,
20
+ "issues": AsyncIssues,
21
+ "organization": AsyncOrganization,
22
+ }
23
+
24
+ OPERATION_SPECS = {
25
+ "api_info_get": ("metadata", "GET", "/"),
26
+ "events_list": ("events", "GET", "/events"),
27
+ "events_ingest": ("ingestion", "POST", "/events"),
28
+ "events_get": ("events", "GET", "/events/{event_id}"),
29
+ "health_get": ("metadata", "GET", "/health"),
30
+ "issues_list": ("issues", "GET", "/issues"),
31
+ "issues_get": ("issues", "GET", "/issues/{issue_id}"),
32
+ "issues_assign": ("issues", "PATCH", "/issues/{issue_id}"),
33
+ "issues_list_events": ("events", "GET", "/issues/{issue_id}/events"),
34
+ "issues_list_notes": ("issues", "GET", "/issues/{issue_id}/notes"),
35
+ "issues_add_note": ("issues", "POST", "/issues/{issue_id}/notes"),
36
+ "organization_get": ("organization", "GET", "/organization"),
37
+ "organization_list_members": ("organization", "GET", "/organization/members"),
38
+ }
39
+
40
+ OPERATION_METHODS = {
41
+ "api_info_get": "get_api_info",
42
+ "events_list": "list_events",
43
+ "events_ingest": "ingest_monitoring_events",
44
+ "events_get": "get_event",
45
+ "health_get": "get_health",
46
+ "issues_list": "list_issues",
47
+ "issues_get": "get_issue",
48
+ "issues_assign": "update_issue",
49
+ "issues_list_events": "list_issue_events",
50
+ "issues_list_notes": "list_issue_notes",
51
+ "issues_add_note": "add_issue_note",
52
+ "organization_get": "get_organization",
53
+ "organization_list_members": "list_organization_members",
54
+ }
55
+
56
+ __all__ = [
57
+ "AsyncEvents",
58
+ "AsyncIngestion",
59
+ "AsyncIssues",
60
+ "AsyncMetadata",
61
+ "AsyncOrganization",
62
+ "Events",
63
+ "Ingestion",
64
+ "Issues",
65
+ "Metadata",
66
+ "Organization",
67
+ "ASYNC_RESOURCE_CLASSES",
68
+ "OPERATION_SPECS",
69
+ "OPERATION_METHODS",
70
+ "SYNC_RESOURCE_CLASSES",
71
+ ]
@@ -49,20 +49,20 @@ def test_base_url_and_request_contract() -> None:
49
49
 
50
50
  with Reconify(
51
51
  "rk_test",
52
- base_url="http://localhost:3002/v1/",
52
+ base_url="http://localhost:3002/v2/",
53
53
  request_id="caller-id",
54
54
  http_client=httpx.Client(transport=httpx.MockTransport(handler)),
55
55
  ) as client:
56
56
  result = client.events.get_event("event id")
57
57
 
58
58
  assert result.id == "evt_1"
59
- assert str(requests[0].url) == "http://localhost:3002/v1/events/event%20id"
59
+ assert str(requests[0].url) == "http://localhost:3002/v2/events/event%20id"
60
60
  assert requests[0].headers["Authorization"] == "Bearer rk_test"
61
61
  assert requests[0].headers["X-Request-ID"] == "caller-id"
62
62
 
63
63
 
64
64
  def test_base_url_and_key_can_come_from_environment(monkeypatch: pytest.MonkeyPatch) -> None:
65
- monkeypatch.setenv("RECONIFY_API_URL", "http://api.test/v1/")
65
+ monkeypatch.setenv("RECONIFY_API_URL", "http://api.test/v2/")
66
66
  monkeypatch.setenv("RECONIFY_API_KEY", "rk_environment")
67
67
  requests: list[httpx.Request] = []
68
68
 
@@ -73,7 +73,7 @@ def test_base_url_and_key_can_come_from_environment(monkeypatch: pytest.MonkeyPa
73
73
  with Reconify(http_client=httpx.Client(transport=httpx.MockTransport(handler))) as client:
74
74
  client.metadata.get_health()
75
75
 
76
- assert str(requests[0].url) == "http://api.test/v1/health"
76
+ assert str(requests[0].url) == "http://api.test/v2/health"
77
77
  assert requests[0].headers["Authorization"] == "Bearer rk_environment"
78
78
 
79
79
 
@@ -92,6 +92,7 @@ def test_ingestion_serializes_typed_body() -> None:
92
92
  reference="order-1",
93
93
  entity_id="wallet-1",
94
94
  amount="10.00",
95
+ correlation_id="checkout-123",
95
96
  currency="USD",
96
97
  )
97
98
  ]
@@ -104,7 +105,8 @@ def test_ingestion_serializes_typed_body() -> None:
104
105
  client.ingestion.ingest_monitoring_events(body)
105
106
 
106
107
  assert json.loads(requests[0].content)["events"][0]["entity_id"] == "wallet-1"
107
- assert requests[0].url.path == "/v1/events"
108
+ assert json.loads(requests[0].content)["events"][0]["correlation_id"] == "checkout-123"
109
+ assert requests[0].url.path == "/v2/events"
108
110
 
109
111
 
110
112
  def test_note_idempotency_header_and_issue_assignment() -> None:
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
 
7
7
  import pytest
8
8
 
9
- from reconify.resources import OPERATION_SPECS, SYNC_RESOURCE_CLASSES
9
+ from reconify.resources import OPERATION_METHODS, OPERATION_SPECS, SYNC_RESOURCE_CLASSES
10
10
 
11
11
 
12
12
  def _openapi_path() -> Path | None:
@@ -23,7 +23,7 @@ def _operations() -> list[tuple[str, str, str]]:
23
23
  pytest.skip("OpenAPI source is not available; run scripts/fetch_contract.py")
24
24
  document = json.loads(path.read_text())
25
25
  return [
26
- (operation["operationId"], method.upper(), route.removeprefix("/v1") or "/")
26
+ (operation["operationId"], method.upper(), route.removeprefix("/v2") or "/")
27
27
  for route, methods in document["paths"].items()
28
28
  for method, operation in methods.items()
29
29
  if method.lower() in {"get", "post", "put", "patch", "delete"}
@@ -44,9 +44,9 @@ def test_every_openapi_operation_has_a_public_method() -> None:
44
44
  assert len({operation_id for operation_id, _, _ in operations}) == len(operations)
45
45
  assert len(OPERATION_SPECS) == len(operations)
46
46
  for operation_id, verb, route in operations:
47
- method_name = operation_id.replace("-", "_")
48
- assert method_name in OPERATION_SPECS, f"Missing SDK contract for {operation_id}"
49
- group, registered_verb, registered_route = OPERATION_SPECS[method_name]
47
+ method_name = OPERATION_METHODS[operation_id]
48
+ assert operation_id in OPERATION_SPECS, f"Missing SDK contract for {operation_id}"
49
+ group, registered_verb, registered_route = OPERATION_SPECS[operation_id]
50
50
  assert registered_route == route
51
51
  assert registered_verb == verb
52
52
  assert hasattr(SYNC_RESOURCE_CLASSES[group], method_name), (
@@ -567,7 +567,7 @@ wheels = [
567
567
 
568
568
  [[package]]
569
569
  name = "reconify-python"
570
- version = "1.0.0"
570
+ version = "2.1.0"
571
571
  source = { editable = "." }
572
572
  dependencies = [
573
573
  { name = "httpx" },
@@ -1,4 +0,0 @@
1
- {
2
- "version": "1.0.0",
3
- "sha256": "04170b7eda8a7bacef6591a7132b9a5cbdb62963af9ca6260e1948c1ee8233c1"
4
- }
@@ -1,17 +0,0 @@
1
- # Upgrading to 1.0.0
2
-
3
- The 1.0.0 client is rebuilt against the current public Reconify v1 contract.
4
- It removes methods that described private or retired ledger, wallet, setup,
5
- search, alert, and reconciliation routes.
6
-
7
- Use these resources:
8
-
9
- - metadata: API information and health
10
- - events: event listing, lookup, and issue-linked evidence
11
- - ingestion: monitoring event batches
12
- - issues: issue listing, lookup, assignment, notes, and linked data
13
- - organization: organization and member reads
14
-
15
- Python models use snake_case fields and preserve unknown enum values through
16
- tolerant string enums. Regenerate or refresh the models after downloading a
17
- new public contract version.
@@ -1,54 +0,0 @@
1
- """Resource clients grouped by the current public API surface."""
2
-
3
- from .events import AsyncEvents, Events
4
- from .ingestion import AsyncIngestion, Ingestion
5
- from .issues import AsyncIssues, Issues
6
- from .metadata import AsyncMetadata, Metadata
7
- from .organization import AsyncOrganization, Organization
8
-
9
- SYNC_RESOURCE_CLASSES = {
10
- "metadata": Metadata,
11
- "events": Events,
12
- "ingestion": Ingestion,
13
- "issues": Issues,
14
- "organization": Organization,
15
- }
16
- ASYNC_RESOURCE_CLASSES = {
17
- "metadata": AsyncMetadata,
18
- "events": AsyncEvents,
19
- "ingestion": AsyncIngestion,
20
- "issues": AsyncIssues,
21
- "organization": AsyncOrganization,
22
- }
23
-
24
- OPERATION_SPECS = {
25
- "get_api_info": ("metadata", "GET", "/"),
26
- "list_events": ("events", "GET", "/events"),
27
- "ingest_monitoring_events": ("ingestion", "POST", "/events"),
28
- "get_event": ("events", "GET", "/events/{event_id}"),
29
- "get_health": ("metadata", "GET", "/health"),
30
- "list_issues": ("issues", "GET", "/issues"),
31
- "get_issue": ("issues", "GET", "/issues/{issue_id}"),
32
- "update_issue": ("issues", "PATCH", "/issues/{issue_id}"),
33
- "list_issue_events": ("events", "GET", "/issues/{issue_id}/events"),
34
- "list_issue_notes": ("issues", "GET", "/issues/{issue_id}/notes"),
35
- "add_issue_note": ("issues", "POST", "/issues/{issue_id}/notes"),
36
- "get_organization": ("organization", "GET", "/organization"),
37
- "list_organization_members": ("organization", "GET", "/organization/members"),
38
- }
39
-
40
- __all__ = [
41
- "AsyncEvents",
42
- "AsyncIngestion",
43
- "AsyncIssues",
44
- "AsyncMetadata",
45
- "AsyncOrganization",
46
- "Events",
47
- "Ingestion",
48
- "Issues",
49
- "Metadata",
50
- "Organization",
51
- "ASYNC_RESOURCE_CLASSES",
52
- "OPERATION_SPECS",
53
- "SYNC_RESOURCE_CLASSES",
54
- ]
File without changes