diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fbc51b..85af65c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- 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`). +- 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). +- 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). +- 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`). +- Shaping: New `vehicle(*)` expand on `Contract` — request the parent vehicle inline from `/api/contracts/` (API 4.2.0). + +### Changed +- Default vehicle shapes (`ShapeConfig.VEHICLES_MINIMAL` / `VEHICLES_COMPREHENSIVE`) updated to surface the new top-level fields; comprehensive default now includes `organization(*)` and `metrics(*)`. + ## [0.5.0] - 2026-04-08 ### Added diff --git a/tango/client.py b/tango/client.py index 2d29c36..dc1fc1c 100644 --- a/tango/client.py +++ b/tango/client.py @@ -123,6 +123,7 @@ def last_response_headers(self) -> httpx.Headers | None: @staticmethod def _parse_rate_limit_headers(headers: httpx.Headers) -> RateLimitInfo: """Extract rate limit info from response headers.""" + def _int_or_none(val: str | None) -> int | None: if val is None: return None @@ -1456,8 +1457,40 @@ def list_vehicles( flat_lists: bool = False, joiner: str = ".", search: str | None = None, + vehicle_type: str | None = None, + type_of_idc: str | None = None, + contract_type: str | None = None, + set_aside: str | None = None, + who_can_use: str | None = None, + naics_code: int | None = None, + psc_code: str | None = None, + program_acronym: str | None = None, + agency: str | None = None, + organization_id: str | None = None, + total_obligated_min: float | int | Decimal | None = None, + total_obligated_max: float | int | Decimal | None = None, + idv_count_min: int | None = None, + idv_count_max: int | None = None, + order_count_min: int | None = None, + order_count_max: int | None = None, + fiscal_year: int | None = None, + award_date_after: str | date | datetime | None = None, + award_date_before: str | date | datetime | None = None, + last_date_to_order_after: str | date | datetime | None = None, + last_date_to_order_before: str | date | datetime | None = None, + ordering: str | None = None, ) -> PaginatedResponse: - """List Vehicles (solicitation-centric groupings of IDVs).""" + """List Vehicles (solicitation-centric groupings of IDVs). + + Multi-value filters (``vehicle_type``, ``type_of_idc``, ``contract_type``, + ``set_aside``) accept pipe-separated values for OR semantics, e.g. + ``vehicle_type="A|B|C"``. + + ``ordering`` accepts: ``vehicle_obligations``, ``latest_award_date``, + ``total_obligated``, ``award_date``, ``last_date_to_order``, + ``fiscal_year``, ``idv_count``, ``order_count``. Prefix with ``-`` for + descending. + """ params: dict[str, Any] = {"page": page, "limit": min(limit, 100)} if shape is None: @@ -1471,8 +1504,37 @@ def list_vehicles( if flat_lists: params["flat_lists"] = "true" - if search: - params["search"] = search + for k, val in ( + ("search", search), + ("vehicle_type", vehicle_type), + ("type_of_idc", type_of_idc), + ("contract_type", contract_type), + ("set_aside", set_aside), + ("who_can_use", who_can_use), + ("naics_code", naics_code), + ("psc_code", psc_code), + ("program_acronym", program_acronym), + ("agency", agency), + ("organization_id", organization_id), + ("total_obligated_min", total_obligated_min), + ("total_obligated_max", total_obligated_max), + ("idv_count_min", idv_count_min), + ("idv_count_max", idv_count_max), + ("order_count_min", order_count_min), + ("order_count_max", order_count_max), + ("fiscal_year", fiscal_year), + ("award_date_after", award_date_after), + ("award_date_before", award_date_before), + ("last_date_to_order_after", last_date_to_order_after), + ("last_date_to_order_before", last_date_to_order_before), + ("ordering", ordering), + ): + if val is None: + continue + if isinstance(val, (date, datetime)): + params[k] = val.isoformat() + else: + params[k] = val data = self._get("/api/vehicles/", params) @@ -1531,8 +1593,14 @@ def list_vehicle_awardees( flat: bool = False, flat_lists: bool = False, joiner: str = ".", + search: str | None = None, ) -> PaginatedResponse: - """List the IDV awardees for a Vehicle (`/api/vehicles/{uuid}/awardees/`).""" + """List the IDV awardees for a Vehicle (`/api/vehicles/{uuid}/awardees/`). + + ``search`` runs entity-aware full-text search across IDV fields + (PIID, key, solicitation_identifier, NAICS, PSC, idv_type, + fiscal_year) and recipient entity details (name, address). + """ params: dict[str, Any] = {"page": page, "limit": min(limit, 100)} if shape is None: @@ -1546,6 +1614,9 @@ def list_vehicle_awardees( if flat_lists: params["flat_lists"] = "true" + if search: + params["search"] = search + data = self._get(f"/api/vehicles/{uuid}/awardees/", params) results = [ diff --git a/tango/models.py b/tango/models.py index 3cab2c0..26d508c 100644 --- a/tango/models.py +++ b/tango/models.py @@ -690,16 +690,19 @@ class ShapeConfig: # Default for list_vehicles() VEHICLES_MINIMAL: Final = ( - "uuid,solicitation_identifier,organization_id,awardee_count,order_count," + "uuid,solicitation_identifier,is_synthetic_solicitation,program_acronym," + "organization_id,idv_count,awardee_count,order_count,total_obligated," "vehicle_obligations,vehicle_contracts_value,solicitation_title,solicitation_date" ) # Default for get_vehicle() VEHICLES_COMPREHENSIVE: Final = ( - "uuid,solicitation_identifier,agency_id,organization_id,vehicle_type,who_can_use," + "uuid,solicitation_identifier,is_synthetic_solicitation,program_acronym," + "agency_id,organization_id,vehicle_type,who_can_use," "solicitation_title,solicitation_description,solicitation_date,naics_code,psc_code,set_aside," - "fiscal_year,award_date,last_date_to_order,awardee_count,order_count,vehicle_obligations,vehicle_contracts_value," - "type_of_idc,contract_type,competition_details(*)" + "fiscal_year,award_date,last_date_to_order,idv_count,awardee_count,order_count," + "total_obligated,vehicle_obligations,vehicle_contracts_value," + "type_of_idc,contract_type,competition_details(*),organization(*),metrics(*)" ) # Default for list_vehicle_awardees() diff --git a/tango/shapes/explicit_schemas.py b/tango/shapes/explicit_schemas.py index 3833cb6..5457808 100644 --- a/tango/shapes/explicit_schemas.py +++ b/tango/shapes/explicit_schemas.py @@ -37,6 +37,25 @@ ), } +# Canonical 7-key office payload returned by the `organization(...)` shape +# expand on awards, vehicles, forecasts, grants, IT Dashboard, and protests. +# Resolved deterministically from the resource's organization_id. +ORGANIZATION_OFFICE_SCHEMA: dict[str, FieldSchema] = { + "organization_id": FieldSchema( + name="organization_id", type=str, is_optional=True, is_list=False + ), + "office_code": FieldSchema(name="office_code", type=str, is_optional=True, is_list=False), + "office_name": FieldSchema(name="office_name", type=str, is_optional=True, is_list=False), + "agency_code": FieldSchema(name="agency_code", type=str, is_optional=True, is_list=False), + "agency_name": FieldSchema(name="agency_name", type=str, is_optional=True, is_list=False), + "department_code": FieldSchema( + name="department_code", type=str, is_optional=True, is_list=False + ), + "department_name": FieldSchema( + name="department_name", type=str, is_optional=True, is_list=False + ), +} + PERIOD_OF_PERFORMANCE_IDV_SCHEMA: dict[str, FieldSchema] = { "start_date": FieldSchema(name="start_date", type=date, is_optional=True, is_list=False), "last_date_to_order": FieldSchema( @@ -396,6 +415,13 @@ "undefinitized_action": FieldSchema( name="undefinitized_action", type=str, is_optional=True, is_list=False ), + "vehicle": FieldSchema( + name="vehicle", + type=dict, + is_optional=True, + is_list=False, + nested_model="Vehicle", + ), } @@ -556,6 +582,13 @@ "source_system": FieldSchema(name="source_system", type=str, is_optional=False, is_list=False), "status": FieldSchema(name="status", type=str, is_optional=True, is_list=False), "title": FieldSchema(name="title", type=str, is_optional=False, is_list=False), + "organization": FieldSchema( + name="organization", + type=dict, + is_optional=True, + is_list=False, + nested_model="OrganizationOffice", + ), } @@ -685,6 +718,13 @@ "dockets": FieldSchema( name="dockets", type=dict, is_optional=True, is_list=True, nested_model="ProtestDocket" ), + "organization": FieldSchema( + name="organization", + type=dict, + is_optional=True, + is_list=False, + nested_model="OrganizationOffice", + ), } @@ -785,6 +825,13 @@ is_list=True, nested_model="GrantAttachment", ), + "organization": FieldSchema( + name="organization", + type=dict, + is_optional=True, + is_list=False, + nested_model="OrganizationOffice", + ), } @@ -965,11 +1012,59 @@ } +# Vehicle detail's bundled `metrics` object (12 lakehouse rollups from +# awards_vehicle_stats). All fields nullable because the stats companion +# is sparse during the bootstrap window between migrate and the first +# sync_vehicle_stats run. +VEHICLE_METRICS_SCHEMA: dict[str, FieldSchema] = { + "avg_offers_received": FieldSchema( + name="avg_offers_received", type=float, is_optional=True, is_list=False + ), + "award_concentration_hhi": FieldSchema( + name="award_concentration_hhi", type=float, is_optional=True, is_list=False + ), + "order_concentration_hhi": FieldSchema( + name="order_concentration_hhi", type=float, is_optional=True, is_list=False + ), + "competed_rate": FieldSchema(name="competed_rate", type=float, is_optional=True, is_list=False), + "using_agency_count": FieldSchema( + name="using_agency_count", type=int, is_optional=True, is_list=False + ), + "avg_order_value": FieldSchema( + name="avg_order_value", type=float, is_optional=True, is_list=False + ), + "max_order_value": FieldSchema( + name="max_order_value", type=float, is_optional=True, is_list=False + ), + "top_recipient_share": FieldSchema( + name="top_recipient_share", type=float, is_optional=True, is_list=False + ), + "recent_obligations_24mo": FieldSchema( + name="recent_obligations_24mo", type=float, is_optional=True, is_list=False + ), + "recent_orders_24mo": FieldSchema( + name="recent_orders_24mo", type=int, is_optional=True, is_list=False + ), + "days_since_last_order": FieldSchema( + name="days_since_last_order", type=int, is_optional=True, is_list=False + ), + "obligation_to_ceiling_ratio": FieldSchema( + name="obligation_to_ceiling_ratio", type=float, is_optional=True, is_list=False + ), +} + + VEHICLE_SCHEMA: dict[str, FieldSchema] = { "uuid": FieldSchema(name="uuid", type=str, is_optional=False, is_list=False), "solicitation_identifier": FieldSchema( name="solicitation_identifier", type=str, is_optional=False, is_list=False ), + "is_synthetic_solicitation": FieldSchema( + name="is_synthetic_solicitation", type=bool, is_optional=True, is_list=False + ), + "program_acronym": FieldSchema( + name="program_acronym", type=str, is_optional=True, is_list=False + ), "agency_id": FieldSchema(name="agency_id", type=str, is_optional=False, is_list=False), "organization_id": FieldSchema( name="organization_id", type=str, is_optional=True, is_list=False @@ -985,11 +1080,18 @@ "descriptions": FieldSchema(name="descriptions", type=str, is_optional=True, is_list=True), "fiscal_year": FieldSchema(name="fiscal_year", type=int, is_optional=True, is_list=False), "award_date": FieldSchema(name="award_date", type=date, is_optional=True, is_list=False), + "latest_award_date": FieldSchema( + name="latest_award_date", type=date, is_optional=True, is_list=False + ), "last_date_to_order": FieldSchema( name="last_date_to_order", type=date, is_optional=True, is_list=False ), "awardee_count": FieldSchema(name="awardee_count", type=int, is_optional=True, is_list=False), + "idv_count": FieldSchema(name="idv_count", type=int, is_optional=True, is_list=False), "order_count": FieldSchema(name="order_count", type=int, is_optional=True, is_list=False), + "total_obligated": FieldSchema( + name="total_obligated", type=Decimal, is_optional=True, is_list=False + ), "vehicle_obligations": FieldSchema( name="vehicle_obligations", type=Decimal, is_optional=True, is_list=False ), @@ -1016,6 +1118,20 @@ "opportunity": FieldSchema( name="opportunity", type=dict, is_optional=True, is_list=False, nested_model="Opportunity" ), + "organization": FieldSchema( + name="organization", + type=dict, + is_optional=True, + is_list=False, + nested_model="OrganizationOffice", + ), + "metrics": FieldSchema( + name="metrics", + type=dict, + is_optional=True, + is_list=False, + nested_model="VehicleMetrics", + ), "competition_details": FieldSchema( name="competition_details", type=dict, @@ -1135,18 +1251,10 @@ # IT Dashboard Investment ITDASHBOARD_INVESTMENT_SCHEMA: dict[str, FieldSchema] = { "uii": FieldSchema(name="uii", type=str, is_optional=False, is_list=False), - "agency_code": FieldSchema( - name="agency_code", type=int, is_optional=True, is_list=False - ), - "agency_name": FieldSchema( - name="agency_name", type=str, is_optional=True, is_list=False - ), - "bureau_code": FieldSchema( - name="bureau_code", type=int, is_optional=True, is_list=False - ), - "bureau_name": FieldSchema( - name="bureau_name", type=str, is_optional=True, is_list=False - ), + "agency_code": FieldSchema(name="agency_code", type=int, is_optional=True, is_list=False), + "agency_name": FieldSchema(name="agency_name", type=str, is_optional=True, is_list=False), + "bureau_code": FieldSchema(name="bureau_code", type=int, is_optional=True, is_list=False), + "bureau_name": FieldSchema(name="bureau_name", type=str, is_optional=True, is_list=False), "investment_title": FieldSchema( name="investment_title", type=str, is_optional=True, is_list=False ), @@ -1167,15 +1275,9 @@ # Modeled as opaque dict/list since their inner shapes are dynamic. "funding": FieldSchema(name="funding", type=dict, is_optional=True, is_list=False), "details": FieldSchema(name="details", type=dict, is_optional=True, is_list=False), - "cio_evaluation": FieldSchema( - name="cio_evaluation", type=list, is_optional=True, is_list=True - ), - "contracts": FieldSchema( - name="contracts", type=list, is_optional=True, is_list=True - ), - "projects": FieldSchema( - name="projects", type=list, is_optional=True, is_list=True - ), + "cio_evaluation": FieldSchema(name="cio_evaluation", type=list, is_optional=True, is_list=True), + "contracts": FieldSchema(name="contracts", type=list, is_optional=True, is_list=True), + "projects": FieldSchema(name="projects", type=list, is_optional=True, is_list=True), "cost_pools_towers": FieldSchema( name="cost_pools_towers", type=list, is_optional=True, is_list=True ), @@ -1191,6 +1293,13 @@ "operational_analysis": FieldSchema( name="operational_analysis", type=list, is_optional=True, is_list=True ), + "organization": FieldSchema( + name="organization", + type=dict, + is_optional=True, + is_list=False, + nested_model="OrganizationOffice", + ), } # ============================================================================ @@ -1200,6 +1309,7 @@ EXPLICIT_SCHEMAS: dict[str, dict[str, FieldSchema]] = { "Office": OFFICE_SCHEMA, "AwardOffice": AWARD_OFFICE_SCHEMA, + "OrganizationOffice": ORGANIZATION_OFFICE_SCHEMA, "Location": LOCATION_SCHEMA, "PlaceOfPerformance": PLACE_OF_PERFORMANCE_SCHEMA, "Competition": COMPETITION_SCHEMA, @@ -1225,6 +1335,7 @@ "Vehicle": VEHICLE_SCHEMA, "IDV": IDV_SCHEMA, "VehicleCompetitionDetails": VEHICLE_COMPETITION_DETAILS_SCHEMA, + "VehicleMetrics": VEHICLE_METRICS_SCHEMA, # Nested schemas for Grant fields "CFDANumber": CFDA_NUMBER_SCHEMA, "CodeDescription": CODE_DESCRIPTION_SCHEMA, diff --git a/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists b/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists index 4c516e8..785bceb 100644 --- a/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists +++ b/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists @@ -13,24 +13,40 @@ interactions: user-agent: - python-httpx/0.28.1 method: GET - uri: https://tango.makegov.com/api/vehicles/?page=1&limit=1&shape=uuid%2Csolicitation_identifier%2Corganization_id%2Cawardee_count%2Corder_count%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date + uri: https://tango.makegov.com/api/vehicles/?page=1&limit=20&shape=uuid%2Copportunity%28title%29 response: body: - string: '{"count":5874,"next":"https://tango.makegov.com/api/vehicles/?limit=1&page=2&shape=uuid%2Csolicitation_identifier%2Corganization_id%2Cawardee_count%2Corder_count%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date","previous":null,"results":[{"uuid":"84d76669-61d8-5938-83fb-2d6f8a6c85b7","solicitation_identifier":"0","organization_id":"f6c88e61-3d34-5685-a5ab-670858289883","awardee_count":38,"order_count":65,"vehicle_obligations":8876449.66,"vehicle_contracts_value":9688796.56,"solicitation_title":"X1LZ--618-20-2-6190-0007 - - Service - Minneapolis VA CRRC Parking, 33 Parking Spaces - MPLS","solicitation_date":"2020-03-02"}]}' + string: '{"count":20457,"next":"https://tango.makegov.com/api/vehicles/?limit=20&page=2&shape=uuid%2Copportunity%28title%29","previous":null,"results":[{"opportunity":null,"uuid":"8597845d-2a4c-5acd-99ff-1f5fe348501e"},{"opportunity":{"title":"Region + Local Telephony Contract - for Upstate New York, Rochester New York, New Jersey, + and Puerto Rico"},"uuid":"62090454-1126-5f27-8aef-c39e6df5ee7f"},{"opportunity":{"title":"C + -- Indefinite Quantity Contract for A-E Services - Repair/Maintenance, Alteration, + and New Construction"},"uuid":"88f6c85b-b398-5396-808c-316f3f4394e3"},{"opportunity":{"title":"W + -- Aerial dispersal services which shall include aircraft, pilots, vaccine + delivery machinery, and flight engineers"},"uuid":"6b6148c8-8cf2-57f2-b23d-14497f6132e1"},{"opportunity":null,"uuid":"4ba4daee-34fe-5e71-8993-6ce6e564eb48"},{"opportunity":{"title":"C--Professional + Architect and Engineering Services"},"uuid":"664412e7-6833-5ff0-b0c0-5c4de8e9645c"},{"opportunity":{"title":"C--Requirement + for Architectural and Engineering Services."},"uuid":"76d34d0f-6f3d-52c4-a591-ad1830ca8282"},{"opportunity":{"title":"66--66- + Seismometers"},"uuid":"d7a26fbc-76bb-5839-b75b-7fb13f2b5a00"},{"opportunity":{"title":"T--Indefinite + Delivery, Indefinite Quantity contract for furnishign various Aerial Photogrammetry + Services"},"uuid":"dc95647f-ed2a-540f-bd43-2553438eb56c"},{"opportunity":{"title":"F--F--IDIQ + Stockpiling Riprap and Gravel for the Yuma Area Office, Base Year with 2 Option + Years"},"uuid":"f38faccb-d4ab-5886-9490-f7b403469471"},{"opportunity":{"title":"B + -- Nutrient Analysis for the Agricultural Research Service"},"uuid":"0aada776-5b10-51b8-8246-9b84ef8d20ad"},{"opportunity":null,"uuid":"fad73227-c71a-52a1-86dc-afaa19f24d5e"},{"opportunity":null,"uuid":"a8775381-0a49-54aa-954f-5afcda32b0de"},{"opportunity":{"title":"SOLICITATION + - GAO IDIQ CONSTRUCTION SERVICES"},"uuid":"ef62a4f0-080a-503f-adbe-a1705ae410c0"},{"opportunity":null,"uuid":"15a432e6-e692-599b-9815-585eb62adb0e"},{"opportunity":null,"uuid":"6e548ccd-73cd-5aea-be4b-72ca776ece20"},{"opportunity":{"title":"B--Professional + Services IDIQ Contract"},"uuid":"09850593-da36-57c5-abf5-f78d49cf6a22"},{"opportunity":null,"uuid":"508d5921-182f-52a8-aaeb-2afc0432eb50"},{"opportunity":null,"uuid":"b18958ca-9647-57ed-8134-9259f58edd33"},{"opportunity":{"title":"76--Commercial + Satellite Data"},"uuid":"8a4e1e44-9be0-515e-b02b-6ec1db728f32"}]}' headers: CF-RAY: - - 9d71a79d1e69ace2-MSP + - 9f8300911ae0eb68-ORD Connection: - keep-alive Content-Type: - application/json Date: - - Wed, 04 Mar 2026 14:43:42 GMT + - Thu, 07 May 2026 20:33:53 GMT Nel: - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' Report-To: - - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=foISsWd3o4Crwk58iKLLuBVkQFtC11yIJkhkCK4vC%2F0w4I28Kbk4j%2FWdF2Z4gVU3QAwqVjUkR9L3KC6Sa4dIYTFIEYgsuvxpb5FBysskgBHHwX4lRUqueUSX"}]}' + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=cIEJq5J9Gv812rH4c3dzT4m2XnOQsHhZ00XTFnQY8PrjjwAhnIZkmZZuWDNbbC68kD6M6uCIWASlYj4XzQ%2BujVZkfNI8rIKhB3vhzFiRgy6HxkVPeXGWNRcPqw3q1pQ1Xp7O"}]}' Server: - cloudflare Transfer-Encoding: @@ -40,7 +56,7 @@ interactions: cf-cache-status: - DYNAMIC content-length: - - '668' + - '2407' cross-origin-opener-policy: - same-origin referrer-policy: @@ -50,27 +66,29 @@ interactions: x-content-type-options: - nosniff x-execution-time: - - 0.021s + - 0.107s x-frame-options: - DENY x-ratelimit-burst-limit: - '1000' x-ratelimit-burst-remaining: - - '910' + - '998' x-ratelimit-burst-reset: - - '6' + - '59' x-ratelimit-daily-limit: - '2000000' x-ratelimit-daily-remaining: - - '1999670' + - '1999837' x-ratelimit-daily-reset: - - '84966' + - '12367' x-ratelimit-limit: - '1000' x-ratelimit-remaining: - - '910' + - '998' x-ratelimit-reset: - - '6' + - '59' + x-results-counttype: + - exact status: code: 200 message: OK @@ -88,24 +106,24 @@ interactions: user-agent: - python-httpx/0.28.1 method: GET - uri: https://tango.makegov.com/api/vehicles/84d76669-61d8-5938-83fb-2d6f8a6c85b7/?shape=uuid%2Copportunity%28title%29&flat=true&joiner=__&flat_lists=true + uri: https://tango.makegov.com/api/vehicles/62090454-1126-5f27-8aef-c39e6df5ee7f/?shape=uuid%2Copportunity%28title%29&flat=true&joiner=__&flat_lists=true response: body: - string: '{"uuid":"84d76669-61d8-5938-83fb-2d6f8a6c85b7","opportunity__title":"X1LZ--618-20-2-6190-0007 - - Service - Minneapolis VA CRRC Parking, 33 Parking Spaces - MPLS"}' + string: '{"opportunity__title":"Region Local Telephony Contract - for Upstate + New York, Rochester New York, New Jersey, and Puerto Rico","uuid":"62090454-1126-5f27-8aef-c39e6df5ee7f"}' headers: CF-RAY: - - 9d71a79de845ace2-MSP + - 9f830092af71eb68-ORD Connection: - keep-alive Content-Type: - application/json Date: - - Wed, 04 Mar 2026 14:43:42 GMT + - Thu, 07 May 2026 20:33:53 GMT Nel: - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' Report-To: - - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=fTIzuP10eNwQ3RQvXSnqPSyKJ%2F0GkCtQtRiwPTkcg7j62kkVcPa6owX9t2k8dFjcoroz4y6rj8b251WYX0UtASQXH3CIXIV2MxlJ6CzJ9%2FUD%2FcYSU6Ckn1vO"}]}' + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=xtRSfhVoii188PnTYsknN%2BQ8CcYClzGWfplQLUGSyqBtCcxCzCTpeYFQwUlNeaRX0HQFKv2jZxGF8xhFNiGDPCtr0Uv7vj9mQCMILB%2F7QelTyGTy7MEyuHjR6BcndLydmiDd"}]}' Server: - cloudflare Transfer-Encoding: @@ -115,7 +133,7 @@ interactions: cf-cache-status: - DYNAMIC content-length: - - '161' + - '174' cross-origin-opener-policy: - same-origin referrer-policy: @@ -125,27 +143,27 @@ interactions: x-content-type-options: - nosniff x-execution-time: - - 0.032s + - 0.025s x-frame-options: - DENY x-ratelimit-burst-limit: - '1000' x-ratelimit-burst-remaining: - - '909' + - '997' x-ratelimit-burst-reset: - - '6' + - '59' x-ratelimit-daily-limit: - '2000000' x-ratelimit-daily-remaining: - - '1999669' + - '1999836' x-ratelimit-daily-reset: - - '84966' + - '12366' x-ratelimit-limit: - '1000' x-ratelimit-remaining: - - '909' + - '997' x-ratelimit-reset: - - '6' + - '59' status: code: 200 message: OK diff --git a/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape b/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape index c8e7417..9dd9ddb 100644 --- a/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape +++ b/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape @@ -13,24 +13,24 @@ interactions: user-agent: - python-httpx/0.28.1 method: GET - uri: https://tango.makegov.com/api/vehicles/?page=1&limit=1&shape=uuid%2Csolicitation_identifier%2Corganization_id%2Cawardee_count%2Corder_count%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date + uri: https://tango.makegov.com/api/vehicles/?page=1&limit=1&shape=uuid%2Csolicitation_identifier%2Cis_synthetic_solicitation%2Cprogram_acronym%2Corganization_id%2Cidv_count%2Cawardee_count%2Corder_count%2Ctotal_obligated%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date response: body: - string: '{"count":5874,"next":"https://tango.makegov.com/api/vehicles/?limit=1&page=2&shape=uuid%2Csolicitation_identifier%2Corganization_id%2Cawardee_count%2Corder_count%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date","previous":null,"results":[{"uuid":"84d76669-61d8-5938-83fb-2d6f8a6c85b7","solicitation_identifier":"0","organization_id":"f6c88e61-3d34-5685-a5ab-670858289883","awardee_count":38,"order_count":65,"vehicle_obligations":8876449.66,"vehicle_contracts_value":9688796.56,"solicitation_title":"X1LZ--618-20-2-6190-0007 - - Service - Minneapolis VA CRRC Parking, 33 Parking Spaces - MPLS","solicitation_date":"2020-03-02"}]}' + string: '{"count":20457,"next":"https://tango.makegov.com/api/vehicles/?limit=1&page=2&shape=uuid%2Csolicitation_identifier%2Cis_synthetic_solicitation%2Cprogram_acronym%2Corganization_id%2Cidv_count%2Cawardee_count%2Corder_count%2Ctotal_obligated%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date","previous":null,"results":[{"awardee_count":2,"idv_count":2,"is_synthetic_solicitation":false,"order_count":25,"organization_id":"767bb2b0-239a-5bb4-8f3c-16d0a418fb71","program_acronym":"APHIS + VS","solicitation_date":null,"solicitation_identifier":"002-M-APHIS-06","solicitation_title":null,"total_obligated":5388564.69,"uuid":"8597845d-2a4c-5acd-99ff-1f5fe348501e","vehicle_contracts_value":5116733.97,"vehicle_obligations":5388564.6899999995}]}' headers: CF-RAY: - - 9d71a79f4d4ba1c9-MSP + - 9f8300941801f4ae-ORD Connection: - keep-alive Content-Type: - application/json Date: - - Wed, 04 Mar 2026 14:43:42 GMT + - Thu, 07 May 2026 20:33:53 GMT Nel: - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' Report-To: - - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=g0j44m3AvOYMt1ZDTnMMFZ2MIbXGngySfFBMATk3ynlDhde23D0RJVscwUPb6%2FacawtgKkwd%2Bq2ufXW62HT1tqPmdW1YWEDTq8jkHS7HBqy1vBy1fFH36z7q"}]}' + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=uTPbt8NMccR4JfW1yfvwE9RwkNUgkl5gXUTzGyd4%2FT8Mj%2BtA95KV72jcJo2bUtRonvNdcUJ999fR5k5EBLnLz3oe51beVriLg0JGvCsvqkdMS2YTjXgIXmLir2%2F3K%2FrIOxzo"}]}' Server: - cloudflare Transfer-Encoding: @@ -40,7 +40,7 @@ interactions: cf-cache-status: - DYNAMIC content-length: - - '668' + - '775' cross-origin-opener-policy: - same-origin referrer-policy: @@ -50,27 +50,29 @@ interactions: x-content-type-options: - nosniff x-execution-time: - - 0.022s + - 0.023s x-frame-options: - DENY x-ratelimit-burst-limit: - '1000' x-ratelimit-burst-remaining: - - '908' + - '996' x-ratelimit-burst-reset: - - '6' + - '59' x-ratelimit-daily-limit: - '2000000' x-ratelimit-daily-remaining: - - '1999668' + - '1999835' x-ratelimit-daily-reset: - - '84966' + - '12366' x-ratelimit-limit: - '1000' x-ratelimit-remaining: - - '908' + - '996' x-ratelimit-reset: - - '6' + - '59' + x-results-counttype: + - exact status: code: 200 message: OK @@ -88,41 +90,26 @@ interactions: user-agent: - python-httpx/0.28.1 method: GET - uri: https://tango.makegov.com/api/vehicles/84d76669-61d8-5938-83fb-2d6f8a6c85b7/awardees/?page=1&limit=10&shape=uuid%2Ckey%2Cpiid%2Caward_date%2Ctitle%2Corder_count%2Cidv_obligations%2Cidv_contracts_value%2Crecipient%28display_name%2Cuei%29 + uri: https://tango.makegov.com/api/vehicles/8597845d-2a4c-5acd-99ff-1f5fe348501e/awardees/?page=1&limit=10&shape=uuid%2Ckey%2Cpiid%2Caward_date%2Ctitle%2Corder_count%2Cidv_obligations%2Cidv_contracts_value%2Crecipient%28display_name%2Cuei%29 response: body: - string: '{"count":38,"next":"https://tango.makegov.com/api/vehicles/84d76669-61d8-5938-83fb-2d6f8a6c85b7/awardees/?limit=10&page=2&shape=uuid%2Ckey%2Cpiid%2Caward_date%2Ctitle%2Corder_count%2Cidv_obligations%2Cidv_contracts_value%2Crecipient%28display_name%2Cuei%29","previous":null,"results":[{"uuid":"d3eec2d2-f46d-5f3a-a2b3-da474202982d","key":"CONT_IDV_36C24925A0044_3600","piid":"36C24925A0044","award_date":"2025-02-26","title":null,"order_count":2,"idv_obligations":97177.1,"idv_contracts_value":97177.1,"recipient":{"uei":"HPNGJJKW7NZ3","display_name":"MIM - SOFTWARE INC"}},{"uuid":"6b35e54e-cdd7-547a-9912-4f32889904ee","key":"CONT_IDV_36C24923A0055_3600","piid":"36C24923A0055","award_date":"2023-09-21","title":"LEXINGTON - VAMC AMOS CONSIGNMENT","order_count":0,"idv_obligations":0.0,"idv_contracts_value":0.0,"recipient":{"uei":"G8XGKTUWPM14","display_name":"AMO - SALES AND SERVICE, INC."}},{"uuid":"4734026e-f902-5e4d-ae05-2625e9ee09b3","key":"CONT_IDV_36C10X23A0024_3600","piid":"36C10X23A0024","award_date":"2023-09-19","title":"HR - SUPPORT SERVICES","order_count":2,"idv_obligations":929714.8,"idv_contracts_value":931419.55,"recipient":{"uei":"WRHHNUK5YBN1","display_name":"RIVIDIUM - INC."}},{"uuid":"a2304733-ca28-5157-b800-ace63deb1f79","key":"CONT_IDV_36C24723A0033_3600","piid":"36C24723A0033","award_date":"2023-06-23","title":"CONSIGNMENT - INVENTORY","order_count":0,"idv_obligations":0.0,"idv_contracts_value":0.0,"recipient":{"uei":"KP5EVFMHUAN1","display_name":"ABBOTT - LABORATORIES INC."}},{"uuid":"8a721329-40f9-5ca3-858d-ed9a067371f2","key":"CONT_IDV_36C26022A0045_3600","piid":"36C26022A0045","award_date":"2022-09-12","title":"INTRA - OCULAR LENSE CONSIGNMENT AGREEMENT","order_count":0,"idv_obligations":0.0,"idv_contracts_value":0.0,"recipient":{"uei":"G8XGKTUWPM14","display_name":"AMO - SALES AND SERVICE, INC."}},{"uuid":"113dac46-3903-5889-9fc1-d4a58c01c591","key":"CONT_IDV_36C24122A0070_3600","piid":"36C24122A0070","award_date":"2022-03-17","title":"BLANKET - PURCHASE AGREEMENT FOR SUPPLIES NATIONWIDE VHA","order_count":0,"idv_obligations":0.0,"idv_contracts_value":0.0,"recipient":{"uei":"L3CLKHB2VE24","display_name":"Sage - Products, LLC"}},{"uuid":"040283f5-ed08-5434-9df4-907c7af62e4f","key":"CONT_IDV_36C25022A0009_3600","piid":"36C25022A0009","award_date":"2021-10-01","title":"COOK - MEDICAL LLC CONSIGNMENT - IMPLANTS","order_count":0,"idv_obligations":0.0,"idv_contracts_value":0.0,"recipient":{"uei":"GG39AE315NK5","display_name":"COOK - MEDICAL LLC"}},{"uuid":"7fe6ae99-081f-5be6-bd03-6a9bbf354980","key":"CONT_IDV_36C25021A0056_3600","piid":"36C25021A0056","award_date":"2021-03-23","title":null,"order_count":5,"idv_obligations":128048.14,"idv_contracts_value":164888.14,"recipient":{"uei":"STNDUK44ENE8","display_name":"POLYMEDCO - LLC"}},{"uuid":"3ab4321d-76a5-58c2-aaf6-85321ccd1bc1","key":"CONT_IDV_36C24821A0018_3600","piid":"36C24821A0018","award_date":"2021-03-17","title":"STERNAL - PLATES AND SCREWS","order_count":0,"idv_obligations":0.0,"idv_contracts_value":0.0,"recipient":{"uei":"JB1EA2TU8V88","display_name":"BIOMET - MICROFIXATION, LLC"}},{"uuid":"141b0632-e12b-5ac8-a862-869bc1bd9f87","key":"CONT_IDV_36C24821A0016_3600","piid":"36C24821A0016","award_date":"2021-02-15","title":"CONSIGNMENT - AGREEMENT - PERIPHERAL VASCULAR EMBOLIZATION PRODUCTS","order_count":0,"idv_obligations":0.0,"idv_contracts_value":0.0,"recipient":{"uei":"QLC9LYKADGX5","display_name":"PENUMBRA, - INC."}}]}' + string: '{"count":2,"next":null,"previous":null,"results":[{"award_date":"2006-06-01","idv_contracts_value":1183372.8,"idv_obligations":1455203.52,"key":"CONT_IDV_AG6395C060018_12K3","order_count":10,"piid":"AG6395C060018","recipient":{"uei":"GDVZPLNAKLL9","display_name":"STEVEN + INDUSTRIES INC"},"title":"CATTLE AND SWINE BACKTAG CEMENT","uuid":"af5f3527-b51b-55d8-9c6f-2d6aad936d31"},{"award_date":"2006-06-01","idv_contracts_value":3933361.17,"idv_obligations":3933361.17,"key":"CONT_IDV_AG6395C060019_12K3","order_count":15,"piid":"AG6395C060019","recipient":{"uei":"C1D7UA31LAK8","display_name":"M + J RUSCOE"},"title":"CATTLE AND SWINE BACKTAG CEMENT TO BE DELIVERED ON AN + IDIQ BASIS TO KS, MO.","uuid":"55cdcfa5-9b94-5aa5-8a8b-7a291d675e20"}]}' headers: CF-RAY: - - 9d71a7a00eb0a1c9-MSP + - 9f8300952b6ff4ae-ORD Connection: - keep-alive Content-Type: - application/json Date: - - Wed, 04 Mar 2026 14:43:42 GMT + - Thu, 07 May 2026 20:33:53 GMT Nel: - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' Report-To: - - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=PA0MWV3V4YvOgApvlK%2B30Y0fxb8uTbbVuL9VqVukOJLOvEMUylvJhadJX%2BuzJ2P7b5Nd8l6H5tYqYB%2FRfPaJao1Je5g32SIOLm0i2Ohjsm7hv1lGzYI6qyl2"}]}' + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=PE6q1a8YczuiMmH0spHUNUtnHFOuMZxj6ojehjdW1WVv7Ed8PtJJWn1OsPvuDJW4xOfEadqYE%2B25TyIVe6MUMCz2h7yWDHXHlrFDE1u6spv1%2BuSY9B1o9tuvSAMSU0awObb0"}]}' Server: - cloudflare Transfer-Encoding: @@ -132,7 +119,7 @@ interactions: cf-cache-status: - DYNAMIC content-length: - - '3418' + - '739' cross-origin-opener-policy: - same-origin referrer-policy: @@ -142,27 +129,27 @@ interactions: x-content-type-options: - nosniff x-execution-time: - - 0.087s + - 0.032s x-frame-options: - DENY x-ratelimit-burst-limit: - '1000' x-ratelimit-burst-remaining: - - '907' + - '995' x-ratelimit-burst-reset: - - '6' + - '59' x-ratelimit-daily-limit: - '2000000' x-ratelimit-daily-remaining: - - '1999667' + - '1999834' x-ratelimit-daily-reset: - - '84966' + - '12366' x-ratelimit-limit: - '1000' x-ratelimit-remaining: - - '907' + - '995' x-ratelimit-reset: - - '6' + - '59' status: code: 200 message: OK diff --git a/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search b/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search index 12ed35c..562effb 100644 --- a/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search +++ b/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search @@ -13,33 +13,32 @@ interactions: user-agent: - python-httpx/0.28.1 method: GET - uri: https://tango.makegov.com/api/vehicles/?page=1&limit=10&shape=uuid%2Csolicitation_identifier%2Corganization_id%2Cawardee_count%2Corder_count%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date&search=GSA + uri: https://tango.makegov.com/api/vehicles/?page=1&limit=10&shape=uuid%2Csolicitation_identifier%2Cis_synthetic_solicitation%2Cprogram_acronym%2Corganization_id%2Cidv_count%2Cawardee_count%2Corder_count%2Ctotal_obligated%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date&search=GSA response: body: - string: '{"count":73,"next":"https://tango.makegov.com/api/vehicles/?limit=10&page=2&search=GSA&shape=uuid%2Csolicitation_identifier%2Corganization_id%2Cawardee_count%2Corder_count%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date","previous":null,"results":[{"uuid":"6741a166-ae8e-57ba-b156-76f9137febad","solicitation_identifier":"15F06725Q0000150","organization_id":"08ba1358-7dad-5228-9540-0a3718bc621d","awardee_count":4,"order_count":5,"vehicle_obligations":3104682.7,"vehicle_contracts_value":29044858.96,"solicitation_title":"Curriculum - Development Synopsis/Solicitation - Updated GSA site","solicitation_date":"2025-04-10"},{"uuid":"1e03d563-afa5-565f-be04-ba64b0ec053c","solicitation_identifier":"2FYB-BJ-030001-B","organization_id":null,"awardee_count":46,"order_count":7458,"vehicle_obligations":139267557.14,"vehicle_contracts_value":607178722.14,"solicitation_title":"Cameras, - Photographic Printers and Related Supplies and Services","solicitation_date":"2001-03-01"},{"uuid":"6fea329b-c906-5857-8384-6451a4c93430","solicitation_identifier":"36C10X23Q0022","organization_id":"f6c88e61-3d34-5685-a5ab-670858289883","awardee_count":4,"order_count":14,"vehicle_obligations":2356056.0,"vehicle_contracts_value":2356056.0,"solicitation_title":"U008--Acquisition + string: '{"count":103,"next":"https://tango.makegov.com/api/vehicles/?limit=10&page=2&search=GSA&shape=uuid%2Csolicitation_identifier%2Cis_synthetic_solicitation%2Cprogram_acronym%2Corganization_id%2Cidv_count%2Cawardee_count%2Corder_count%2Ctotal_obligated%2Cvehicle_obligations%2Cvehicle_contracts_value%2Csolicitation_title%2Csolicitation_date","previous":null,"results":[{"awardee_count":0,"idv_count":7,"is_synthetic_solicitation":false,"order_count":0,"organization_id":"0ef2831b-d699-50c7-8326-63541a75fa11","program_acronym":"GSA","solicitation_date":null,"solicitation_identifier":"1232SA26Q0019","solicitation_title":null,"total_obligated":0.0,"uuid":"3fdd49c6-bf14-57b5-9b56-05a5d3adb35a","vehicle_contracts_value":0.0,"vehicle_obligations":0.0},{"awardee_count":2,"idv_count":4,"is_synthetic_solicitation":false,"order_count":5,"organization_id":"ea1c7a92-5838-5641-99ba-1527f4524306","program_acronym":null,"solicitation_date":null,"solicitation_identifier":"15F06725Q0000150","solicitation_title":"Curriculum + Development Synopsis/Solicitation - Updated GSA site","total_obligated":3104682.7,"uuid":"6741a166-ae8e-57ba-b156-76f9137febad","vehicle_contracts_value":29044858.959999997,"vehicle_obligations":3104682.7},{"awardee_count":1,"idv_count":4,"is_synthetic_solicitation":false,"order_count":1,"organization_id":"5b904ace-8e3f-5909-a991-3e7297c5ffeb","program_acronym":"GSA","solicitation_date":null,"solicitation_identifier":"1605C2-24-Q-00026","solicitation_title":null,"total_obligated":50000.0,"uuid":"9f042142-a09b-5244-9b3d-a638a4e2f219","vehicle_contracts_value":739950.6,"vehicle_obligations":50000.0},{"awardee_count":3,"idv_count":4,"is_synthetic_solicitation":false,"order_count":14,"organization_id":"d8247025-812e-5403-954c-09577eab4a91","program_acronym":null,"solicitation_date":null,"solicitation_identifier":"36C10X23Q0022","solicitation_title":"U008--Acquisition Workforce Training Multiple Award BPA - NEW GSA Contract Number Business Management - Research Associates, Inc","solicitation_date":"2024-04-05"},{"uuid":"e99312ce-b377-5fac-81ce-7f3f19b548c4","solicitation_identifier":"36C26120Q0012","organization_id":"f6c88e61-3d34-5685-a5ab-670858289883","awardee_count":3,"order_count":92,"vehicle_obligations":51415076.89,"vehicle_contracts_value":51498956.84,"solicitation_title":"Q301--Quest - FSS-BPA GSA Schedule 621 II","solicitation_date":"2020-09-28"},{"uuid":"26090608-dfc4-5245-8f1d-043f40d3cedd","solicitation_identifier":"3FNG-RG-020001-B","organization_id":"edfcdf18-d5d1-5e9a-8563-d8ed1f2844ce","awardee_count":111,"order_count":3766,"vehicle_obligations":231871038.22,"vehicle_contracts_value":235312118.92,"solicitation_title":"Professional - Audio/Video, Telemetry/Tracking, Recording, Reproducing and Signal Data Solutions","solicitation_date":"2010-11-30"},{"uuid":"1293190d-b755-5f61-a484-211f4425aad2","solicitation_identifier":"3FNJ-C1-000001-B","organization_id":null,"awardee_count":275,"order_count":51247,"vehicle_obligations":3570831390.91,"vehicle_contracts_value":11123777947.32,"solicitation_title":"Office, - Imaging and Document","solicitation_date":"1999-04-01"},{"uuid":"74ef741b-f0bc-506a-94cc-8252264a0237","solicitation_identifier":"3FNJ-C1-000001-B","organization_id":"edfcdf18-d5d1-5e9a-8563-d8ed1f2844ce","awardee_count":294,"order_count":10410,"vehicle_obligations":3351983917.63,"vehicle_contracts_value":7967591185.76,"solicitation_title":"Office, - Imaging and Document","solicitation_date":"2010-10-01"},{"uuid":"1f8a3ce7-a58c-5d36-907d-bf67f96e2cd4","solicitation_identifier":"3QSA-JB-100001-B","organization_id":"edfcdf18-d5d1-5e9a-8563-d8ed1f2844ce","awardee_count":497,"order_count":24312,"vehicle_obligations":2067723956.69,"vehicle_contracts_value":2149663259.46,"solicitation_title":"Furniture","solicitation_date":"2010-10-04"},{"uuid":"4b755976-75c2-573a-bd3a-92147261df2f","solicitation_identifier":"47PB0023R0012","organization_id":"17417361-31f1-5514-9623-5ef7b0ae02db","awardee_count":24,"order_count":47,"vehicle_obligations":22210407.27,"vehicle_contracts_value":22210407.27,"solicitation_title":"GSA - Region 1 Construction IDIQ - North/Boston/South Zones","solicitation_date":"2023-06-30"},{"uuid":"59cee065-88e2-5a98-be93-004df7e23d18","solicitation_identifier":"47PB0023R0059","organization_id":"17417361-31f1-5514-9623-5ef7b0ae02db","awardee_count":7,"order_count":18,"vehicle_obligations":1171435.78,"vehicle_contracts_value":1171435.78,"solicitation_title":"Architectural - and Engineering Multiple Award IDIQ New England","solicitation_date":"2023-09-13"}]}' + Research Associates, Inc","total_obligated":2359268.78,"uuid":"6fea329b-c906-5857-8384-6451a4c93430","vehicle_contracts_value":2359268.78,"vehicle_obligations":2359268.78},{"awardee_count":3,"idv_count":3,"is_synthetic_solicitation":false,"order_count":93,"organization_id":"2c45fd53-3590-5589-a188-1f34917b3de5","program_acronym":null,"solicitation_date":null,"solicitation_identifier":"36C26120Q0012","solicitation_title":"Q301--Quest + FSS-BPA GSA Schedule 621 II","total_obligated":52052266.47,"uuid":"e99312ce-b377-5fac-81ce-7f3f19b548c4","vehicle_contracts_value":53523209.29,"vehicle_obligations":52052266.47},{"awardee_count":6,"idv_count":9,"is_synthetic_solicitation":false,"order_count":911,"organization_id":"6f5ca983-9b09-55b6-9ad0-f0ce1c2d06c1","program_acronym":null,"solicitation_date":null,"solicitation_identifier":"47PA0519R0001","solicitation_title":"GSA + Leasing Support Services Plus","total_obligated":0.0,"uuid":"5dbdd43a-d8aa-56eb-a11f-78e0ded35642","vehicle_contracts_value":907.02,"vehicle_obligations":0.0},{"awardee_count":7,"idv_count":9,"is_synthetic_solicitation":false,"order_count":88,"organization_id":"949facff-0fda-5062-972b-01ad17491bc6","program_acronym":null,"solicitation_date":null,"solicitation_identifier":"47PA0825R0002","solicitation_title":"FY25 + GSA Streamlined Retail Electric Solicitation","total_obligated":44802108.86,"uuid":"6aa9d616-4d60-52b3-bfb7-a4f4ba332a3c","vehicle_contracts_value":105773964.96,"vehicle_obligations":44802108.86},{"awardee_count":0,"idv_count":4,"is_synthetic_solicitation":false,"order_count":0,"organization_id":"949facff-0fda-5062-972b-01ad17491bc6","program_acronym":null,"solicitation_date":null,"solicitation_identifier":"47PA0826R0001","solicitation_title":"FY26 + GSA Streamlined Retail Electric Solicitation","total_obligated":0.0,"uuid":"7c370689-aad8-5ba3-9498-c018bc5df121","vehicle_contracts_value":0.0,"vehicle_obligations":0.0},{"awardee_count":8,"idv_count":24,"is_synthetic_solicitation":false,"order_count":51,"organization_id":"2fd4b124-5131-5ab9-9091-e2ee27274d0e","program_acronym":null,"solicitation_date":null,"solicitation_identifier":"47PB0023R0012","solicitation_title":"GSA + Region 1 Construction IDIQ - North/Boston/South Zones","total_obligated":24000257.07,"uuid":"4b755976-75c2-573a-bd3a-92147261df2f","vehicle_contracts_value":24000257.07,"vehicle_obligations":24000257.07},{"awardee_count":0,"idv_count":7,"is_synthetic_solicitation":false,"order_count":0,"organization_id":"54839cf5-aa68-5304-8f46-9aa63eaf2ba5","program_acronym":null,"solicitation_date":null,"solicitation_identifier":"47PC0222R0019","solicitation_title":"GSA + R2 - Caribbean Construction IDIQ","total_obligated":0.0,"uuid":"1a1704af-7d47-5293-b189-cf6a8c7ca35f","vehicle_contracts_value":0.0,"vehicle_obligations":0.0}]}' headers: CF-RAY: - - 9d71a7968b13fc89-MSP + - 9f83008f3b161070-ORD Connection: - keep-alive Content-Type: - application/json Date: - - Wed, 04 Mar 2026 14:43:42 GMT + - Thu, 07 May 2026 20:33:52 GMT Nel: - '{"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}' Report-To: - - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=5%2BHepsdgjcU87kM%2BNnTgEm5bAgw8L9ZsZHeSXeBCTE%2BWnksTynGg8TJ56KoKVetk3pFnm%2Bz6OTI%2BHQ3lraKGlHtfXJrFZtMZU6d5rEzcXciLRMAIthAZ1V8Z"}]}' + - '{"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=rihwkPFkiAbPCEQx6pjfsn1vgHnLuQTlArCWUmyU9d6wt1zaCgpC4VF5MzXyMx7xiTtZtiUJTdG12U38zbbGGrgSSjK%2FJaIgNgIEKewQcq0POO1iQ4H8yvNkX35XMBKCZYWu"}]}' Server: - cloudflare Transfer-Encoding: @@ -49,7 +48,7 @@ interactions: cf-cache-status: - DYNAMIC content-length: - - '3950' + - '4766' cross-origin-opener-policy: - same-origin referrer-policy: @@ -59,27 +58,29 @@ interactions: x-content-type-options: - nosniff x-execution-time: - - 0.578s + - 0.024s x-frame-options: - DENY x-ratelimit-burst-limit: - '1000' x-ratelimit-burst-remaining: - - '911' + - '999' x-ratelimit-burst-reset: - - '7' + - '59' x-ratelimit-daily-limit: - '2000000' x-ratelimit-daily-remaining: - - '1999671' + - '1999838' x-ratelimit-daily-reset: - - '84967' + - '12367' x-ratelimit-limit: - '1000' x-ratelimit-remaining: - - '911' + - '999' x-ratelimit-reset: - - '7' + - '59' + x-results-counttype: + - exact status: code: 200 message: OK diff --git a/tests/integration/test_vehicles_idvs_integration.py b/tests/integration/test_vehicles_idvs_integration.py index 6f7cada..693ecb6 100644 --- a/tests/integration/test_vehicles_idvs_integration.py +++ b/tests/integration/test_vehicles_idvs_integration.py @@ -92,17 +92,23 @@ def test_get_vehicle_supports_joiner_and_flat_lists(self, tango_client): - flat, flat_lists, and joiner parameters work correctly - Vehicle is parsed correctly """ - # First, get a vehicle UUID from listing - list_response = tango_client.list_vehicles(limit=1) + # Find a vehicle that has an opportunity so the joiner/flat_lists + # behavior is meaningfully exercised below. Vehicle ordering is + # not guaranteed, and some vehicles legitimately have no opportunity. + list_response = tango_client.list_vehicles(limit=20, shape="uuid,opportunity(title)") if not list_response.results: pytest.skip("No vehicles available to test get_vehicle") - vehicle_uuid = ( - list_response.results[0].get("uuid") - if isinstance(list_response.results[0], dict) - else list_response.results[0].uuid - ) - assert vehicle_uuid is not None, "Vehicle UUID should be present" + vehicle_uuid = None + for result in list_response.results: + opp = result.get("opportunity") if isinstance(result, dict) else result.opportunity + if opp is None: + continue + vehicle_uuid = result.get("uuid") if isinstance(result, dict) else result.uuid + break + + if vehicle_uuid is None: + pytest.skip("No vehicle with an opportunity available to test joiner") # Test with flat, flat_lists, and joiner vehicle = tango_client.get_vehicle(