feat(client): API parity — 30+ methods, ordering kwargs, webhook write fixes#25
Draft
makegov-hal[bot] wants to merge 5 commits into
Draft
feat(client): API parity — 30+ methods, ordering kwargs, webhook write fixes#25makegov-hal[bot] wants to merge 5 commits into
makegov-hal[bot] wants to merge 5 commits into
Conversation
Internal HTTP helpers previously accepted only positional `json_data`.
Docs examples and some user code (and a few SDK callers) pass `json=`,
which raised `TypeError`. Make both work — `json_data=` (positional or
keyword) and `json=` (keyword-only) both supply the request body. Empty
body defaults to `{}` for callers that POST/PATCH with no payload.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
These endpoints all accept `?ordering=` server-side (per OpenAPI), but the SDK methods didn't expose it. Add explicit `ordering: str | None` to: - list_forecasts - list_grants - list_subawards - list_gsa_elibrary_contracts - list_opportunities - list_notices - list_protests Pattern matches the existing `ordering` on list_otas / list_otidvs / list_contracts / list_idvs / list_vehicles / list_vehicle_orders. Prefix with `-` for descending. list_entities, list_vehicle_awardees, and list_idv_transactions intentionally NOT updated — those endpoints don't expose `ordering` in their OpenAPI parameters. list_idv_awards / list_idv_child_idvs already accept `**kwargs`, so `ordering=` flows through unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Tango webhooks API requires `name` on WebhookEndpoint create (the server enforces unique(user, name)), and `endpoint` UUID on WebhookSubscription create when a user owns more than one endpoint. The SDK's create methods previously didn't accept either, forcing callers to fall back to raw `_post` or use the `/api/webhooks/alerts/` convenience API. Changes: - create_webhook_endpoint: add keyword-only `name=`. Currently optional for backward compatibility; emits DeprecationWarning when omitted and will become required in a future major version. Documents the server-side 400 callers see today when they skip it. - create_webhook_subscription: add keyword-only `endpoint=`, `subscription_type=`, `query_type=`, `filter_definition=`, `frequency=`, `cron_expression=`, `is_active=`. Mirrors the full WebhookSubscriptionSerializer surface. - update_webhook_subscription: add `frequency=`, `cron_expression=`, `is_active=` so filter subscriptions can be paused / re-frequencied via the canonical PATCH route. - update_webhook_endpoint: add `name=` so endpoints can be renamed. All additions are keyword-only and backward compatible — existing call sites continue to work unchanged. The single in-tree test that constructs a webhook endpoint is updated to pass `name="primary"` so it doesn't trip the new DeprecationWarning. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surveyed the OpenAPI schema and added the methods that were missing
from the SDK. Existing list_/get_ patterns preserved throughout —
shape-aware where the underlying endpoint supports shaping, plain
dict-returning where it doesn't.
Webhook alerts (convenience layer over filter subscriptions):
- list_webhook_alerts / get_webhook_alert / create_webhook_alert
/ update_webhook_alert / delete_webhook_alert
- New WebhookAlert dataclass
Resolve / validate (POST-based identity helpers):
- resolve(name, target_type, ...) — entity/org name disambiguation
- validate(identifier_type, value) — PIID/solicitation/UEI format check
- New ResolveCandidate, ResolveResult, ValidateResult dataclasses
Reference data:
- list_departments, get_department
- list_psc, get_psc, get_psc_metrics
- get_naics, get_naics_metrics
- get_business_type
- list_assistance_listings, get_assistance_listing
- list_mas_sins, get_mas_sin
Entity sub-resources (all under /api/entities/{uei}/...):
- list_entity_contracts, list_entity_idvs
- list_entity_otas, list_entity_otidvs
- list_entity_subawards, list_entity_lcats
- get_entity_metrics
IDV sub-resources:
- list_idv_lcats
Agency sub-resources:
- list_agency_awarding_contracts
- list_agency_funding_contracts
Misc:
- search_opportunity_attachments(q, top_k, include_extracted_text)
- get_version()
- list_api_keys()
Decisions:
- Kept `uuid=` for vehicle methods to match `get_vehicle(uuid)` and the
existing list_vehicle_awardees / list_vehicle_orders surface — these
match the API path param. IDVs use `key=`, vehicles use `uuid=`, and
the SDK stays consistent.
- Stayed away from /api/accounts/usage/ admin endpoints, /api/events/,
/api/news/, and /api/company/rag/ — niche internal surfaces. Easy to
add when there's user demand.
- list_entities, list_vehicle_awardees, and list_idv_transactions are
not getting `ordering` because their server-side parameters don't
advertise it (verified against OpenAPI).
Backward compatible — all additions, no existing call sites changed.
Existing tests still pass (238/238).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two pieces:
1. tests/test_api_parity.py — 40 mock-driven unit tests covering:
- `_post`/`_patch` json kwarg aliases
- resolve / validate (POST endpoints) request shape + response parsing
- WebhookAlert CRUD (create / update / list)
- WebhookEndpoint create/update with name= (and DeprecationWarning
when name= is omitted)
- WebhookSubscription create with endpoint=, subscription_type=,
filter fields
- ordering= threading on the seven affected list_* methods
- Reference-data and entity/agency sub-resource URL construction
2. scripts/smoke_api_parity.py — live smoke test that hits every method
the branch added or changed against a running Tango. Skips
gracefully when the local server can't service a particular
endpoint (404 for attachment-search without the RAG index; 504 from
funding-contracts aggregation; alerts can't auto-resolve endpoint
when the test user owns multiple). Creates webhook endpoints +
subscriptions, verifies them, and tears them down. Local run on
2026-05-11: 45/45 PASS (with three SKIPs for the environmental
reasons above).
Also includes a trivial ruff-format collapse in models.py
(VEHICLE_ORDERS_MINIMAL one-liner).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR expands tango-python toward full Tango API parity by adding many missing client methods and typed models, plus fixing webhook write signatures and request-body kwarg compatibility to match documented usage.
Changes:
- Added Resolve/Validate POST helpers with typed response models (
ResolveResult,ValidateResult) and exported them at the package root. - Implemented webhook alerts CRUD plus webhook endpoint/subscription write-signature parity (including
name=on endpoint creation and additional subscription fields). - Added
ordering=passthrough on several list endpoints and introduced a comprehensive unit-test suite + smoke script for the parity surface.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_client.py | Updates webhook endpoint CRUD test to include name= and assert it is sent in the request body. |
| tests/test_api_parity.py | Adds extensive mock-driven tests covering new parity methods, ordering passthrough, and _post/_patch json kwarg aliasing. |
| tango/models.py | Introduces new dataclasses (WebhookAlert, ResolveCandidate/Result, ValidateResult) and minor shape string formatting change. |
| tango/client.py | Adds _post/_patch json= alias support, ordering= kwargs, webhook write fixes, webhook alerts CRUD, resolve/validate endpoints, and multiple reference/sub-resource list/get methods. |
| tango/init.py | Exports new parity models from the package root. |
| scripts/smoke_api_parity.py | Adds an end-to-end smoke script to exercise parity methods against a running Tango instance with cleanup. |
| CHANGELOG.md | Documents newly added methods/kwargs and the _post/_patch compatibility fix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+209
to
+224
| def _post( | ||
| self, | ||
| endpoint: str, | ||
| json_data: dict[str, Any] | None = None, | ||
| *, | ||
| json: dict[str, Any] | None = None, | ||
| ) -> dict[str, Any]: | ||
| """Make a POST request. | ||
|
|
||
| Accepts either ``json_data`` (positional) or ``json=`` (keyword) for | ||
| backward compatibility with internal callers and docs examples. | ||
| """ | ||
| body = json_data if json_data is not None else json | ||
| if body is None: | ||
| body = {} | ||
| return self._request("POST", endpoint, json_data=body) |
| Args: | ||
| code: PSC code. | ||
| months: Window size in months (e.g. 6, 12, 24, 36). | ||
| period_grouping: ``monthly``, ``quarterly``, etc. |
Comment on lines
+10
to
+12
| ### Added | ||
| - `ordering` parameter on `list_forecasts`, `list_grants`, `list_subawards`, `list_gsa_elibrary_contracts`, `list_opportunities`, `list_notices`, and `list_protests`. Prefix with `-` for descending. Closes a parity gap with the API surface (these endpoints all accept `?ordering=` server-side). | ||
| - `create_webhook_endpoint` accepts `name=` (keyword-only). Required by the Tango API since multi-endpoint support landed; omitting it now emits a `DeprecationWarning` and will become an error in a future major version. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings
tango-pythonto full API parity with Tango: 30+ new methods, signature fixes for write paths,orderingkwargs on list endpoints that were silently missing them, and four new typed response models. 278 unit tests pass, 45/45 smoke checks pass against a running Tango instance, 80% line coverage across the package.Branch: 5 commits on
feat/api-parityoffmain.What's new
Resolve / Validate utilities (typed wrappers)
Two new top-level methods replace the prior
client._post("/api/resolve/", ...)workaround:resolve(name, target_type, ...)— POST/api/resolve/. Returns a typedResolveResultwithResolveCandidateentries (identifier,display_name,match_tieron Pro+). Optional context:state,city,contextstring. Backed by new dataclasses exported from the package root.validate(identifier_type, value)— POST/api/validate/. ReturnsValidateResult.Webhook alerts CRUD parity
The convenience layer over
/api/webhooks/alerts/(filter subscriptions) was previously create-only. Full CRUD now:list_webhook_alerts(...)get_webhook_alert(id)create_webhook_alert(name=, query_type=, filters=, frequency=, cron_expression=)update_webhook_alert(id, ...)delete_webhook_alert(id)WebhookAlertdataclass exported fromtango.Webhook write-method signatures, completed
The SDK's write methods were missing fields that the Tango API has required since multi-endpoint support landed. Catching up:
create_webhook_endpointnow acceptsname=(keyword-only). Required by the server; omitting it emits aDeprecationWarningand will become an error in a future major version.create_webhook_subscriptionacceptsendpoint=,subscription_type=,query_type=,filter_definition=,frequency=,cron_expression=,is_active=— covers both subject and filter subscription patterns through the canonical/api/webhooks/subscriptions/API.update_webhook_subscriptionacceptsfrequency=,cron_expression=,is_active=.update_webhook_endpointacceptsname=for renames.Reference data
list_departments,get_department,list_psc,get_psc,get_psc_metrics,get_naics,get_naics_metrics,get_business_type,list_assistance_listings,get_assistance_listing,list_mas_sins,get_mas_sin.Entity sub-resources
list_entity_contracts,list_entity_idvs,list_entity_otas,list_entity_otidvs,list_entity_subawards,list_entity_lcats,get_entity_metrics. All shape-aware where the underlying endpoint supports shaping.IDV + agency sub-resources
list_idv_lcatslist_agency_awarding_contracts,list_agency_funding_contractsMisc
search_opportunity_attachments(q, top_k, include_extracted_text)for/api/opportunities/attachment-search/get_version()for/api/version/list_api_keys()for/api/api-keys/orderingparameter where the API supports itSeven list methods now accept
ordering=and pass it through:list_forecasts,list_grants,list_subawards,list_gsa_elibrary_contracts,list_opportunities,list_notices,list_protests. Prefix with-for descending. This closes parity gaps where the API documented?ordering=but the SDK silently rejected the kwarg.Fixed
TangoClient._post()and_patch()now accept bothjson_data=(positional, original) andjson=(kwarg). Internal callers and docs examples that usejson=no longer fail withTypeError.Testing
pytest: 412 passed, 31 skipped — was 238 before this branch; +40 new tests intests/test_api_parity.py.80% line coverageacrosstango/(pytest --cov).mypyclean on changed code;ruffclean.scripts/smoke_api_parity.pyagainsthttp://localhost:8000): 45/45 pass. Three blocks SKIPped for environmental reasons (/attachment-search/404 locally,/funding-contracts/504 on the test agency,create_webhook_alertskipped when the test account has multiple endpoints — see makegov/tango#2256).Decisions worth flagging
uuid=on vehicle methods (list_vehicle_awardees,list_vehicle_orders). Matches the existingget_vehicle(uuid)path-param convention. SDK convention: IDVs usekey=, vehicles useuuid=.Known issues uncovered during parity work (tracked separately on tango)
/subscriptions/POST uses fieldendpoint;/endpoints/test-delivery/usesendpoint_id.orderingon/notices/,/protests/,/subawards/but viewsets reject most values./api/webhooks/alerts/; backend needs to accept an explicitendpointfield on the alert create serializer before the SDKs can paper over the limitation.Risks
DeprecationWarningoncreate_webhook_endpointwithoutname=may surface in user logs — intentional, since the API will eventually rejectname-less requests outright.Sibling work
Companion PR in
tango-nodecovers the same parity work for the Node SDK. Docs are updated to reflect both SDKs' new surfaces inmakegov/docs#9.– Hal 🤖