Skip to content

Commit 96b43d0

Browse files
vdavezclaude
andcommitted
Add Vehicle filters/ordering and 4.2.x SDK catch-up
list_vehicles now exposes 21 explicit filter parameters (vehicle_type, type_of_idc, contract_type, set_aside, who_can_use, naics_code, psc_code, program_acronym, agency, organization_id, total_obligated_min/max, idv_count_min/max, order_count_min/max, fiscal_year, award_date_after/before, last_date_to_order_after/before) plus an ordering parameter, matching API v4.3.0. list_vehicle_awardees gains a search parameter for entity-aware full-text search across IDV and recipient fields. Schema additions catch the SDK up through API 4.2.x: new top-level Vehicle fields (is_synthetic_solicitation, program_acronym, idv_count, total_obligated, latest_award_date), a bundled metrics expansion (12 lakehouse rollups), an organization(*) expand on Vehicle/Forecast/Grant/ITDashboard/Protest returning the canonical 7-key office payload, and a vehicle(*) expand on Contract. VEHICLES_MINIMAL/COMPREHENSIVE defaults updated to surface the new fields. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 35f8d77 commit 96b43d0

4 files changed

Lines changed: 224 additions & 29 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- Vehicles: `list_vehicles` gained 21 explicit filter parameters and `ordering` per API 4.3.0: `vehicle_type`, `type_of_idc`, `contract_type`, `set_aside` (multi-value via `|`), `who_can_use`, `naics_code`, `psc_code`, `program_acronym`, `agency`, `organization_id`, `total_obligated_min`/`max`, `idv_count_min`/`max`, `order_count_min`/`max`, `fiscal_year`, `award_date_after`/`before`, `last_date_to_order_after`/`before`, `ordering` (whitelist: `vehicle_obligations`, `latest_award_date`, `total_obligated`, `award_date`, `last_date_to_order`, `fiscal_year`, `idv_count`, `order_count`).
12+
- Vehicles: `list_vehicle_awardees` gained a `search` parameter for entity-aware full-text search across IDV fields and recipient entity details (API 4.3.0).
13+
- Vehicles: New top-level fields on `Vehicle` shape — `is_synthetic_solicitation`, `program_acronym`, `idv_count`, `total_obligated`, `latest_award_date` — plus a bundled `metrics` expansion (12 lakehouse rollups) on detail (API 4.2.1).
14+
- Shaping: New `organization(*)` expand on `Vehicle`, `Forecast`, `Grant`, `ITDashboardInvestment`, and `Protest` schemas — returns the canonical 7-key office payload (`organization_id`, `office_code`, `office_name`, `agency_code`, `agency_name`, `department_code`, `department_name`).
15+
- Shaping: New `vehicle(*)` expand on `Contract` — request the parent vehicle inline from `/api/contracts/` (API 4.2.0).
16+
17+
### Changed
18+
- Default vehicle shapes (`ShapeConfig.VEHICLES_MINIMAL` / `VEHICLES_COMPREHENSIVE`) updated to surface the new top-level fields; comprehensive default now includes `organization(*)` and `metrics(*)`.
19+
1020
## [0.5.0] - 2026-04-08
1121

1222
### Added

tango/client.py

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ def last_response_headers(self) -> httpx.Headers | None:
123123
@staticmethod
124124
def _parse_rate_limit_headers(headers: httpx.Headers) -> RateLimitInfo:
125125
"""Extract rate limit info from response headers."""
126+
126127
def _int_or_none(val: str | None) -> int | None:
127128
if val is None:
128129
return None
@@ -1456,8 +1457,40 @@ def list_vehicles(
14561457
flat_lists: bool = False,
14571458
joiner: str = ".",
14581459
search: str | None = None,
1460+
vehicle_type: str | None = None,
1461+
type_of_idc: str | None = None,
1462+
contract_type: str | None = None,
1463+
set_aside: str | None = None,
1464+
who_can_use: str | None = None,
1465+
naics_code: int | None = None,
1466+
psc_code: str | None = None,
1467+
program_acronym: str | None = None,
1468+
agency: str | None = None,
1469+
organization_id: str | None = None,
1470+
total_obligated_min: float | int | Decimal | None = None,
1471+
total_obligated_max: float | int | Decimal | None = None,
1472+
idv_count_min: int | None = None,
1473+
idv_count_max: int | None = None,
1474+
order_count_min: int | None = None,
1475+
order_count_max: int | None = None,
1476+
fiscal_year: int | None = None,
1477+
award_date_after: str | date | datetime | None = None,
1478+
award_date_before: str | date | datetime | None = None,
1479+
last_date_to_order_after: str | date | datetime | None = None,
1480+
last_date_to_order_before: str | date | datetime | None = None,
1481+
ordering: str | None = None,
14591482
) -> PaginatedResponse:
1460-
"""List Vehicles (solicitation-centric groupings of IDVs)."""
1483+
"""List Vehicles (solicitation-centric groupings of IDVs).
1484+
1485+
Multi-value filters (``vehicle_type``, ``type_of_idc``, ``contract_type``,
1486+
``set_aside``) accept pipe-separated values for OR semantics, e.g.
1487+
``vehicle_type="A|B|C"``.
1488+
1489+
``ordering`` accepts: ``vehicle_obligations``, ``latest_award_date``,
1490+
``total_obligated``, ``award_date``, ``last_date_to_order``,
1491+
``fiscal_year``, ``idv_count``, ``order_count``. Prefix with ``-`` for
1492+
descending.
1493+
"""
14611494
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
14621495

14631496
if shape is None:
@@ -1471,8 +1504,37 @@ def list_vehicles(
14711504
if flat_lists:
14721505
params["flat_lists"] = "true"
14731506

1474-
if search:
1475-
params["search"] = search
1507+
for k, val in (
1508+
("search", search),
1509+
("vehicle_type", vehicle_type),
1510+
("type_of_idc", type_of_idc),
1511+
("contract_type", contract_type),
1512+
("set_aside", set_aside),
1513+
("who_can_use", who_can_use),
1514+
("naics_code", naics_code),
1515+
("psc_code", psc_code),
1516+
("program_acronym", program_acronym),
1517+
("agency", agency),
1518+
("organization_id", organization_id),
1519+
("total_obligated_min", total_obligated_min),
1520+
("total_obligated_max", total_obligated_max),
1521+
("idv_count_min", idv_count_min),
1522+
("idv_count_max", idv_count_max),
1523+
("order_count_min", order_count_min),
1524+
("order_count_max", order_count_max),
1525+
("fiscal_year", fiscal_year),
1526+
("award_date_after", award_date_after),
1527+
("award_date_before", award_date_before),
1528+
("last_date_to_order_after", last_date_to_order_after),
1529+
("last_date_to_order_before", last_date_to_order_before),
1530+
("ordering", ordering),
1531+
):
1532+
if val is None:
1533+
continue
1534+
if isinstance(val, (date, datetime)):
1535+
params[k] = val.isoformat()
1536+
else:
1537+
params[k] = val
14761538

14771539
data = self._get("/api/vehicles/", params)
14781540

@@ -1531,8 +1593,14 @@ def list_vehicle_awardees(
15311593
flat: bool = False,
15321594
flat_lists: bool = False,
15331595
joiner: str = ".",
1596+
search: str | None = None,
15341597
) -> PaginatedResponse:
1535-
"""List the IDV awardees for a Vehicle (`/api/vehicles/{uuid}/awardees/`)."""
1598+
"""List the IDV awardees for a Vehicle (`/api/vehicles/{uuid}/awardees/`).
1599+
1600+
``search`` runs entity-aware full-text search across IDV fields
1601+
(PIID, key, solicitation_identifier, NAICS, PSC, idv_type,
1602+
fiscal_year) and recipient entity details (name, address).
1603+
"""
15361604
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
15371605

15381606
if shape is None:
@@ -1546,6 +1614,9 @@ def list_vehicle_awardees(
15461614
if flat_lists:
15471615
params["flat_lists"] = "true"
15481616

1617+
if search:
1618+
params["search"] = search
1619+
15491620
data = self._get(f"/api/vehicles/{uuid}/awardees/", params)
15501621

15511622
results = [

tango/models.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -690,16 +690,19 @@ class ShapeConfig:
690690

691691
# Default for list_vehicles()
692692
VEHICLES_MINIMAL: Final = (
693-
"uuid,solicitation_identifier,organization_id,awardee_count,order_count,"
693+
"uuid,solicitation_identifier,is_synthetic_solicitation,program_acronym,"
694+
"organization_id,idv_count,awardee_count,order_count,total_obligated,"
694695
"vehicle_obligations,vehicle_contracts_value,solicitation_title,solicitation_date"
695696
)
696697

697698
# Default for get_vehicle()
698699
VEHICLES_COMPREHENSIVE: Final = (
699-
"uuid,solicitation_identifier,agency_id,organization_id,vehicle_type,who_can_use,"
700+
"uuid,solicitation_identifier,is_synthetic_solicitation,program_acronym,"
701+
"agency_id,organization_id,vehicle_type,who_can_use,"
700702
"solicitation_title,solicitation_description,solicitation_date,naics_code,psc_code,set_aside,"
701-
"fiscal_year,award_date,last_date_to_order,awardee_count,order_count,vehicle_obligations,vehicle_contracts_value,"
702-
"type_of_idc,contract_type,competition_details(*)"
703+
"fiscal_year,award_date,last_date_to_order,idv_count,awardee_count,order_count,"
704+
"total_obligated,vehicle_obligations,vehicle_contracts_value,"
705+
"type_of_idc,contract_type,competition_details(*),organization(*),metrics(*)"
703706
)
704707

705708
# Default for list_vehicle_awardees()

0 commit comments

Comments
 (0)