Releases: makegov/tango-python
v1.2.0
Added
list_budget_accounts()now exposes the full range-filter surface that the REST endpoint has always supported. Every numeric metric on/api/budget/accounts/— the 26 fields in the backend'sRANGE_NUMERIC_FIELDSlist (enacted_ba,apportioned,obligated_total,unobligated_balance,contract_obligated,contract_share_of_obligated_capped,ba_growth_next_year_pct,actual_vs_requested_contract, all the ratio fields and their_cappedvariants, etc.) — is now accepted in three forms: exact match (field=), greater-or-equal (field_gte=), and less-or-equal (field_lte=). Previously only the identity / taxonomy filters were exposed, which forced callers to discover accounts by exact symbol lookup; the new surface makes pipeline-style queries (e.g. "all FY24 accounts where contract share ≥ 60%, unobligated balance ≥ $200M, and next-year growth ≥ 15%, sorted by largest headroom first") a single SDK call. The new params map to the API'sfield__gte/field__lteform;ordering=already accepted any of these fields and continues to.
Full changelog: https://github.com/makegov/tango-python/blob/v1.2.0/CHANGELOG.md
v1.1.3
Added
- Reference-data list/get methods now accept
shape(and the associated
flat/flat_lists) parameters, matching the underlying API which has
always supported the shape system viaShapeOnDemandMixin. Affected:
list_naics/get_naics,list_psc/get_psc,
list_assistance_listings/get_assistance_listing,
list_business_types/get_business_type,
list_mas_sins/get_mas_sin. Whenshapeis omitted, behavior is
unchanged — the API applies its own per-resource default.
list_business_typesreturns raw dicts (instead ofBusinessType
instances) when ashapeis supplied so the caller gets exactly the
shape requested.
v1.1.2
Changed
get_entity_budget_flows()now exposes the backend's standard page/limit pagination andfiscal_yearfilter, and returnsPaginatedResponse[dict[str, Any]]instead of a raw dict. The backend has always paginated this endpoint viaStandardResultsSetPagination; the previous signature gave callers no way to reach pages beyond the first or to narrow by fiscal year. Callers that were indexingresult["results"]on the old return value should switch toresult.results(and can now useresult.next/page=to walk further pages).- Completed the strict-
mypyburn-down acrosstango/shapes/(parser, generator, factory, schema). All changes are type-annotation/typing corrections with no runtime behavior change, except:FieldSchema.nested_modelis now typedtype | str | None(it always accepted string model names from the explicit schemas; the annotation was wrong).ModelFactory.validate_dataandShapeParser._validate_field_speclikewise accepttype | strfor the model argument.- Removed two dead
elif field_spec.is_wildcard:branches (inTypeGenerator.generate_typeandModelFactory.create_instance) and the now-orphaned_parse_nested_wildcardhelper. These were unreachable — wildcard field specs are fully handled by the top-of-loop branch thatcontinues before reaching them — so removal is behavior-preserving.
Docs
docs/API_REFERENCE.mdnow documents the Budget surface that shipped in v1.1.0: a new## Budgetsection coveringlist_budget_accounts,get_budget_account,get_budget_account_quarters, andget_budget_account_recipients; aget_entity_budget_flows()entry under Entity Sub-resources; aBUDGET_ACCOUNTS_MINIMALrow in the ShapeConfig table; and a Budget entry in the table of contents.
CI
- Bumped GitHub Actions off the deprecated Node 20 runtime (forced off 2026-06-02):
actions/checkoutv4→v6,astral-sh/setup-uvv4→v8.1.0 (pinned exact — no floatingv8major tag is published yet), andcodecov/codecov-actionv3→v5 (with the renamedfiles:input). mypyis now a hard gate inlint.yml(no longer advisory). Thetango/package type-checks cleanly under strict mypy.
Full Changelog: v1.1.1...v1.1.2
v1.1.1
Removed
- The
notebooksoptional extra (jupyter,ipykernel). It only powered local
editing ofdocs/quick_start.ipynb, which still renders on GitHub/PyPI without
it, and its transitive tree (jupyter-server, jupyterlab, nbconvert, tornado,
etc.) accounted for the bulk of the repo's open Dependabot alerts. Contributors
who want to re-run the notebook canpip install jupyterdirectly. The shipped
SDK is unaffected — its only runtime dependency remainshttpx.
Changed
- Refreshed the dev/test dependency lock to clear the remaining Dependabot
alerts (patchedidna,pygments,pytest,python-dotenv; dropped
urllib3/requeststransitives). Dev-tool majors moved forward
(mypy1.18→2.1,pytest8→9,ruff0.14→0.15,vcrpy7→8); all lint,
type, and test gates stay green. No change to the shipped SDK's runtime deps.
v1.1.0
Fixed
_parse_webhook_alert: aligned the parser output with theWebhookAlert
type contract. Sparse server payloads now hydratequery_typeandfilters
as""/{}(matching their declared non-null types) rather thanNone,
andstatusis typed as theLiteral["active", "paused"]the model promises.
Clears the four type-check errors this introduced; no change for full payloads.Contractmodel: removed dead fields (id,award_id,recipient_name,
award_amount,awarding_agency,funding_agency) and added the real API
fields (key,piid,obligated,total_contract_value,
base_and_exercised_options_value,awarding_office,funding_office,
naics_code,psc_code,set_aside,solicitation_identifier,
parent_award,legislative_mandates,subawards_summary,
place_of_performance). The deprecated fields remain declared withNone
defaults for one minor cycle (they never returned data) and will be removed
in2.0.0. NewOrganizationOfficePayloaddataclass for the office fields.
(Contractis a documentation-only dataclass — not instantiated or exported
— so there is no runtime impact.)list_contracts: no longer sendspage=1to the cursor-only/api/contracts/
endpoint. When no cursor is supplied, neitherpagenorcursoris sent and
the API returns the first page by default.- Shape validation: registered the
ContractOrIDVCompetitionnested schema
(alias ofCompetition) so nested selections like
competition(extent_competed,number_of_offers_received)on contract / IDV
shapes validate instead of raisingShapeValidationError.
Added
- Budget accounts surface (tango v4.6.8):
list_budget_accounts,
get_budget_account,get_budget_account_quarters,
get_budget_account_recipients. NewBudgetAccountdataclass exported from
the top-level package, plusShapeConfig.BUDGET_ACCOUNTS_MINIMAL. - Singleton detail GETs:
get_contract,get_contract_subawards,
get_contract_transactions,get_forecast,get_grant,get_notice,
get_opportunity,get_subaward. get_entity_budget_flows(uei)for/api/entities/{uei}/budget-flows/.list_otidv_awards(key)for/api/otidvs/{key}/awards/(parity with Node).grant_idfilter kwarg onlist_grants(supports multi-value OR via|).
CI
- Re-enabled
lint.ymlas a PR + push-to-main gate.ruff formatand
ruff checkare hard gates;mypyruns advisory (continue-on-error) pending
burn-down of ~28 pre-existing type errors. The filter/shape conformance check
is a separate job that skips cleanly until aTANGO_API_REPO_ACCESS_TOKEN
secret for the private manifest repo is configured, at which point it becomes
a hard gate.
v1.0.0
First stable release.
tango-pythonis now at full API parity with the
Tango HTTP surface, the legacy subject-based webhook subscription
mechanism has been removed in favor of filter alerts, the shape parser
agrees byte-for-byte with the server's expand-alias handling, and the
SDK's docs are auto-published todocs.makegov.com/sdks/python/via the
composer pipeline (makegov/docs#15 / makegov/docs#16). From1.xon,
we'll only do breaking changes on a major bump.Originally tracked as: API parity (PR #25), subject-based webhook
removal (PR #27 / issue #2275), shape-validator alias support (PR #28 /
issue #2266), and the docs-only content port (makegov/docs#16).
Added
orderingparameter onlist_forecasts,list_grants,list_subawards,list_gsa_elibrary_contracts, andlist_opportunities. Prefix with-for descending. Closes a parity gap with the API surface (these endpoints all accept?ordering=server-side).create_webhook_endpointacceptsname=(keyword-only) and now requires it. The Tango API enforces unique(user, name)on endpoints; omittingnamereturns a 400 server-side, so the SDK raisesTangoValidationErrorclient-side instead of round-tripping. (0.7.0 — never publicly released — emitted aDeprecationWarninginstead.)update_webhook_endpointacceptsname=for renaming an endpoint.- Webhook alerts (filter subscriptions):
list_webhook_alerts,get_webhook_alert,create_webhook_alert,update_webhook_alert,delete_webhook_alert— the canonical write surface over/api/webhooks/alerts/. NewWebhookAlertdataclass exported from the top-level package. resolve(name, target_type, ...)— POST/api/resolve/to rank entity / organization candidates from a free-text name. ReturnsResolveResultwithResolveCandidateentries (both exported).validate(identifier_type, value)— POST/api/validate/to validate the format of a PIID, solicitation number, or UEI. ReturnsValidateResult(exported).- 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 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)for/api/opportunities/attachment-search/;get_version()for/api/version/;list_api_keys()for/api/api-keys/.
Changed
create_webhook_alertacceptsendpoint=(keyword-only). Required for accounts with multiple webhook endpoints; auto-resolves for single-endpoint accounts. Closes the multi-endpoint smoke-test gap (tango#2256).test_webhook_deliverynow sends the canonicalendpointbody key instead of the deprecatedendpoint_idalias (tango#2252). The Python kwarg name staysendpoint_id=for backwards compatibility; the wire payload is what changed.generate_signature(body, secret)now returns the full wire form"sha256=<hex>"instead of bare hex. Callers can assign the return value directly to theX-Tango-Signatureheader without wrapping in a format string. This is a breaking change for code that relied on the bare-hex return; pass it throughparse_signature_header()to recover the previous form.verify_signatureaccepts both prefixed and bare-hex inputs (unchanged), so receivers continue to work either way.
Removed
- Subject-based webhook subscription surface (tango#2275). Migrate to
create_webhook_alert(...)and the alerts API.- Methods:
list_webhook_subscriptions,get_webhook_subscription,create_webhook_subscription,update_webhook_subscription,delete_webhook_subscription. - Dataclasses:
WebhookSubscription,WebhookSubjectTypeDefinition. Both are no longer exported from the top-leveltangopackage — importing them raisesImportError. - Fields:
default_subject_typeremoved fromWebhookEventType;subject_typesandsubject_type_definitionsremoved fromWebhookEventTypesResponse. The server's/api/webhooks/event-types/response no longer carries these. - CLI: the entire
tango webhooks subscriptionsClick subgroup (list/get/create/delete). Use the SDK'sclient.create_webhook_alert(...)etc. directly — there is no CLI subgroup for alerts.
- Methods:
orderingkwarg fromlist_noticesandlist_protests. The notices and protests viewsets reject every?ordering=value at runtime (tango#2254); the kwarg silently sent unsupported values. Other five list methods retainordering.
Fixed
TangoClient._post()and_patch()accept bothjson_data=(positional) andjson=(keyword) for backward compatibility. Internal callers and docs examples that usejson=no longer fail withTypeError. Passing both now raisesTangoValidationErrorrather than silently preferring one — that ambiguity would hide caller bugs.get_psc_metrics/get_naics_metrics/get_entity_metricsdocstrings —period_groupingvalues are"month"/"quarter"/"year"(the path-segment values the API accepts), not"monthly"/"quarterly".docs/API_REFERENCE.md#get_agency— example usesclient.get_agency("GSA")consistently and notes the parameter accepts CGAC / FPDS / short code / abbreviation / canonical name.README.mdQuick Start —get_agency()returns anAgencydataclass, so the example uses attribute access (agency.name) instead ofagency['name']which wouldTypeError.scripts/smoke_api_parity.py—list_business_types(limit=1)is now wrapped in therun(...)helper so a failure on that call records FAIL instead of aborting the smoke run.tango webhooks endpoints createCLI now accepts and requires--name(passed through tocreate_webhook_endpoint(name=...)). Previously the option was absent, meaning the CLI could never set a custom endpoint name and every call would 400 server-side (the server enforcesunique(user, name)).WebhookAlert.query_typeandWebhookAlert.filterstightened fromOptionalto non-optional (stranddict[str, Any]respectively). Legacy nullable rows were purged by the tango#2275 migration; the server model and serializer guarantee non-null values for all current data.WebhookAlert.statusnarrowed fromstrtoLiteral["active", "paused"]— the server serializer produces exactly those two values.- Shape validator agrees with server on
naics(...)/psc(...)expansions. The client-sideShapeParser.validate()previously rejected the canonicalshape=naics(code,description)form (which the server has always accepted) and also rejected the aliasshape=naics_code(code,description). The parser now mirrors the server's_EXPAND_ALIASES(introduced in Tango PR makegov/tango#2259) and rewritesnaics_code(...)/psc_code(...)to their canonicalnaics(...)/psc(...)form at parse time. Bare scalar leaves (shape=naics_code/shape=psc_code) are left untouched and still return the raw column value, matching the server. Schemas forContract,Forecast,Opportunity,Notice, andVehiclegained explicitnaics/pscexpand entries backed by the existingCodeDescriptionnested model. Fixes makegov/tango#2266. Subawardschema matches the server'sSubawardSerializer. The previousSUBAWARD_SCHEMAdeclared two fields the server has never exposed (id,amount) and was missing every real field on the resource — includingpiid,key,awarding_office/funding_office/place_of_performance/subaward_details/fsrs_details/highly_compensated_officers/usaspending_permalink, and the denormalizedprime_awardee_*/recipient_*lookup columns. Shape strings that referenced any real field (e.g.shape="piid") would fail client-side validation withunknown_field, and conversely the SDK happily passedshape="id"/shape="amount"through to the server, where they were rejected.SUBAWARD_SCHEMAis now derived directly fromawards.serializers.subawards.SubawardSerializerand the resource's runtimeavailable_fields. TheSubawarddataclass intango/models.pywas updated to match. New nested schemasSubawardDetails,FsrsDetails,SubawardPlaceOfPerformance, andHighlyCompensatedOfficerare registered so the corresponding shape expansions validate end-to-end.
Documentation
- New
docs/ERRORS.md— full exception hierarchy, recovery patterns, and the shape-error classes (ShapeValidationError,ShapeParseError,TypeGenerationError,ModelInstantiationError). Ported fromdocs.makegov.com/sdks/python/errors.mdahead of the docs-site auto-pull cutover (makegov/docs#15 / makegov/docs#16). - New
docs/PAGINATION.md— page-based vs cursor-based strategies, iteration patterns, and thePaginatedResponsefield reference. Ported fromdocs.makegov.com/sdks/python/pagination.md. - New
docs/CLIENT.md—TangoClientconstructor reference,rate_limit_info/last_response_headersproperties, and retry-semantics note (the SDK has no built-in retry). Ported fromdocs.makegov.com/sdks/python/client.md.
CI
- New
.github/workflows/docs-dispatch.yml— fires on push tomainwhendocs/**,README.md, orCHANGELOG.mdchanges and dispatchesexternal_updatedatmakegov/docsso the public docs site rebuilds with the latest SDK content. Required for the makegov/docs#15 auto-pull pipeline.
v0.3.0
Added
- Vehicles endpoints:
list_vehicles,get_vehicle,list_vehicle_awardees - IDV endpoints:
list_idvs,get_idv,list_idv_awards,list_idv_child_idvs,list_idv_transactions,get_idv_summary,list_idv_summary_awards - Webhooks v2 client support: event type discovery, subscription CRUD, endpoint management, test delivery, sample payload helpers
Changed
- Expanded explicit schemas to support common IDV shaping expansions
- HTTP client now supports PATCH/DELETE helpers for webhook management endpoints
v0.2.0 (2025-11-17)
🎉 The gritty reboot of a Tango SDK!