tango-python 1.1.1__tar.gz → 1.1.3__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.
- {tango_python-1.1.1 → tango_python-1.1.3}/.github/workflows/docs-dispatch.yml +1 -1
- {tango_python-1.1.1 → tango_python-1.1.3}/.github/workflows/lint.yml +8 -10
- {tango_python-1.1.1 → tango_python-1.1.3}/.github/workflows/publish.yml +2 -2
- {tango_python-1.1.1 → tango_python-1.1.3}/.github/workflows/test.yml +4 -4
- {tango_python-1.1.1 → tango_python-1.1.3}/CHANGELOG.md +55 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/PKG-INFO +1 -1
- {tango_python-1.1.1 → tango_python-1.1.3}/docs/API_REFERENCE.md +134 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/pyproject.toml +1 -1
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/__init__.py +1 -1
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/client.py +180 -20
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/shapes/factory.py +12 -76
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/shapes/generator.py +12 -27
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/shapes/parser.py +17 -16
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/shapes/schema.py +3 -2
- tango_python-1.1.3/tests/cassettes/TestEntitiesIntegration.test_get_entity_budget_flows +229 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_entities_integration.py +58 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/test_client.py +59 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/.gitignore +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/LICENSE +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/README.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/docs/CLIENT.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/docs/DYNAMIC_MODELS.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/docs/ERRORS.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/docs/PAGINATION.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/docs/SHAPES.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/docs/WEBHOOKS.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/scripts/README.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/scripts/check_filter_shape_conformance.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/scripts/fetch_api_schema.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/scripts/generate_schemas_from_api.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/scripts/pr_review.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/scripts/smoke_api_parity.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/scripts/test_production.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/exceptions.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/models.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/shapes/__init__.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/shapes/explicit_schemas.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/shapes/models.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/shapes/types.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/webhooks/__init__.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/webhooks/cli.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/webhooks/receiver.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/webhooks/signing.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tango/webhooks/simulate.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/__init__.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestAgenciesIntegration.test_get_agency +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestAgenciesIntegration.test_list_agencies +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_field_type_validation +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_parsing_consistency +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestBusinessTypesIntegration.test_list_business_types +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_combined_filters_work_together +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_contract_cursor_pagination +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_contract_data_object_parsing +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_contract_field_types +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[keyword-software] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[psc_code-R425] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_awarding_agency_filter +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_date_range_filter +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_flat +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_naics_code_filter +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[custom-key,piid,recipient(display_name),total_contract_value,award_date] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[default-None] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[detailed-key,piid,award_date,description,total_contract_value,obligated,fiscal_year,set_aside,recipient(display_name,uei),awarding_office(-),place_of_performa...ce114a3c47e2037aaa3c15d00b7031bd +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[minimal-key,piid,award_date,recipient(display_name),description,total_contract_value] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_new_expiring_filters +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_new_fiscal_year_range_filters +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_new_identifier_filters +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_search_contracts_with_filters +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_search_filters_object_with_new_parameters +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[asc-] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[desc--] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_contracts +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_entities +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_date_field_parsing_edge_cases +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_decimal_field_parsing_edge_cases +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_empty_list_responses +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_entity_parsing_with_various_address_formats +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_flattened_responses_with_flat_lists +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_list_field_parsing_consistency +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_nested_objects_with_missing_data +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_null_missing_fields_in_contracts +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_with_minimal_shape_sparse_data +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_entity_field_types +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_entity_location_parsing +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_entity_parsing_with_business_types +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_entity_with_various_identifiers +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_get_entity_by_uei +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_flat +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_search +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[comprehensive-uei,legal_business_name,dba_name,cage_code,business_types,primary_naics,naics_codes,psc_codes,email_address,entity_url,description,capabilities,ke...1603a7d52e211cf2b3bc7d32080238aa +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[custom-uei,legal_business_name,cage_code] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[with_address-uei,legal_business_name,cage_code,business_types,physical_address] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestForecastsIntegration.test_forecast_field_types +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[custom-id,title,anticipated_award_date] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[default-None] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[detailed-id,source_system,external_id,title,description,anticipated_award_date,fiscal_year,naics_code,status,is_active] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[minimal-id,title,anticipated_award_date,fiscal_year,naics_code,status] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestGrantsIntegration.test_grant_field_types +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestGrantsIntegration.test_grant_pagination +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[custom-grant_id,title,opportunity_number] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[default-None] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[detailed-grant_id,opportunity_number,title,status(-),agency_code,description,last_updated,cfda_numbers(number,title),applicant_types(-),funding_categories(-)] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[minimal-grant_id,opportunity_number,title,status(-),agency_code] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestIDVsIntegration.test_get_idv_uses_default_shape +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestIDVsIntegration.test_list_idv_awards_uses_default_shape +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestIDVsIntegration.test_list_idv_child_idvs_uses_default_shape +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestIDVsIntegration.test_list_idv_transactions +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestIDVsIntegration.test_list_idvs_uses_default_shape_and_keyset_params +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[minimal-uii,agency_name,bureau_name,investment_title,type_of_investment,part_of_it_portfolio,updated_time,url] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestNaicsIntegration.test_list_naics +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[custom-notice_id,title,solicitation_number] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[default-None] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[detailed-notice_id,title,description,solicitation_number,posted_date,naics_code,set_aside,office(-),place_of_performance(-)] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestNoticesIntegration.test_notice_field_types +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestNoticesIntegration.test_notice_pagination +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestNoticesIntegration.test_notice_with_meta_fields +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOTAsIntegration.test_get_ota +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOTAsIntegration.test_list_otas +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOTIDVsIntegration.test_get_otidv +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOTIDVsIntegration.test_list_otidvs +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOfficesIntegration.test_get_office +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOfficesIntegration.test_list_offices +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[custom-opportunity_id,title,solicitation_number] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[default-None] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[detailed-opportunity_id,title,description,solicitation_number,response_deadline,first_notice_date,last_notice_date,active,naics_code,psc_code,set_asid...23b6b4502ddd665b7184afcff6c6d8d9 +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOpportunitiesIntegration.test_opportunity_field_types +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOrganizationsIntegration.test_get_organization +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestOrganizationsIntegration.test_list_organizations +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestProtestsIntegration.test_get_protest_by_case_id +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_filter +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[custom-case_id,title,source_system,outcome] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[default-None] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[minimal-case_id,case_number,title,source_system,outcome,filed_date] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[with_dockets-case_id,case_number,title,outcome,filed_date,dockets(docket_number,filed_date,outcome)] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestProtestsIntegration.test_protest_pagination +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestSubawardsIntegration.test_list_subawards +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[custom-key,piid,description] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[minimal-key,piid,award_date,recipient(display_name),description,total_contract_value] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[ultra_minimal-key,piid,recipient(display_name),total_contract_value] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[with_address-uei,legal_business_name,cage_code,business_types,physical_address] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_notices_dict_access[detailed-notice_id,title,description,solicitation_number,posted_date,naics_code,set_aside,office(-),place_of_performance(-)] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_notices_dict_access[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_opportunities_dict_access[detailed-opportunity_id,title,description,solicitation_number,response_deadline,first_notice_date,last_notice_date,active,naics_code,psc_code,set_aside,sam_url,office(-),place_of_performance(-)] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestTypeHintsIntegration.test_opportunities_dict_access[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_with_metrics_expansion +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_orders_uses_default_shape +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_with_ordering +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/conftest.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/README.md +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/__init__.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/conftest.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_agencies_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_contracts_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_edge_cases_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_forecasts_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_grants_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_itdashboard_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_naics_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_notices_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_offices_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_opportunities_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_organizations_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_otas_otidvs_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_protests_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_reference_data_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_subawards_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/test_vehicles_idvs_integration.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/integration/validation.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/production/__init__.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/production/conftest.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/production/test_production_smoke.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/test_api_parity.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/test_models.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/test_shapes.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/test_webhooks_cli.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/test_webhooks_receiver.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/test_webhooks_signing.py +0 -0
- {tango_python-1.1.1 → tango_python-1.1.3}/tests/test_webhooks_simulate.py +0 -0
|
@@ -3,9 +3,8 @@ name: Linting
|
|
|
3
3
|
# Lint gate runs on every PR and push to main.
|
|
4
4
|
#
|
|
5
5
|
# - ruff format + ruff check are HARD gates (block the PR).
|
|
6
|
-
# - mypy is
|
|
7
|
-
#
|
|
8
|
-
# in makegov/tango-python; flip `continue-on-error` off once that's clear.
|
|
6
|
+
# - mypy is a HARD gate: the package type-checks cleanly under strict mypy.
|
|
7
|
+
# (The earlier ~28-error burn-down is complete.)
|
|
9
8
|
# - The SDK filter/shape conformance check needs the canonical manifest from the
|
|
10
9
|
# private makegov/tango repo, which requires a TANGO_API_REPO_ACCESS_TOKEN
|
|
11
10
|
# secret the public CI does not have. The conformance job SKIPS cleanly when
|
|
@@ -23,10 +22,10 @@ jobs:
|
|
|
23
22
|
runs-on: ubuntu-latest
|
|
24
23
|
|
|
25
24
|
steps:
|
|
26
|
-
- uses: actions/checkout@
|
|
25
|
+
- uses: actions/checkout@v6
|
|
27
26
|
|
|
28
27
|
- name: Install uv
|
|
29
|
-
uses: astral-sh/setup-uv@
|
|
28
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
30
29
|
with:
|
|
31
30
|
version: "latest"
|
|
32
31
|
|
|
@@ -42,8 +41,7 @@ jobs:
|
|
|
42
41
|
- name: Lint with ruff
|
|
43
42
|
run: uv run ruff check tango/
|
|
44
43
|
|
|
45
|
-
- name: Type check with mypy
|
|
46
|
-
continue-on-error: true
|
|
44
|
+
- name: Type check with mypy
|
|
47
45
|
run: uv run mypy tango/
|
|
48
46
|
|
|
49
47
|
conformance:
|
|
@@ -66,12 +64,12 @@ jobs:
|
|
|
66
64
|
echo "::notice::Skipping SDK conformance check — TANGO_API_REPO_ACCESS_TOKEN not configured."
|
|
67
65
|
fi
|
|
68
66
|
|
|
69
|
-
- uses: actions/checkout@
|
|
67
|
+
- uses: actions/checkout@v6
|
|
70
68
|
if: steps.gate.outputs.ready == 'true'
|
|
71
69
|
|
|
72
70
|
- name: Checkout tango API repo (manifest source)
|
|
73
71
|
if: steps.gate.outputs.ready == 'true'
|
|
74
|
-
uses: actions/checkout@
|
|
72
|
+
uses: actions/checkout@v6
|
|
75
73
|
with:
|
|
76
74
|
repository: makegov/tango
|
|
77
75
|
path: tango-api
|
|
@@ -79,7 +77,7 @@ jobs:
|
|
|
79
77
|
|
|
80
78
|
- name: Install uv
|
|
81
79
|
if: steps.gate.outputs.ready == 'true'
|
|
82
|
-
uses: astral-sh/setup-uv@
|
|
80
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
83
81
|
with:
|
|
84
82
|
version: "latest"
|
|
85
83
|
|
|
@@ -20,10 +20,10 @@ jobs:
|
|
|
20
20
|
if: matrix.os == 'windows-latest'
|
|
21
21
|
run: git config --global core.longpaths true
|
|
22
22
|
|
|
23
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v6
|
|
24
24
|
|
|
25
25
|
- name: Install uv
|
|
26
|
-
uses: astral-sh/setup-uv@
|
|
26
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
27
27
|
with:
|
|
28
28
|
version: "latest"
|
|
29
29
|
|
|
@@ -37,8 +37,8 @@ jobs:
|
|
|
37
37
|
run: uv run pytest
|
|
38
38
|
|
|
39
39
|
- name: Upload coverage to Codecov
|
|
40
|
-
uses: codecov/codecov-action@
|
|
40
|
+
uses: codecov/codecov-action@v5
|
|
41
41
|
with:
|
|
42
|
-
|
|
42
|
+
files: ./coverage.xml
|
|
43
43
|
flags: unittests
|
|
44
44
|
name: codecov-${{ matrix.os }}-py${{ matrix.python-version }}
|
|
@@ -7,6 +7,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.1.3] - 2026-06-04
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Reference-data list/get methods now accept `shape` (and the associated
|
|
14
|
+
`flat` / `flat_lists`) parameters, matching the underlying API which has
|
|
15
|
+
always supported the shape system via `ShapeOnDemandMixin`. Affected:
|
|
16
|
+
`list_naics` / `get_naics`, `list_psc` / `get_psc`,
|
|
17
|
+
`list_assistance_listings` / `get_assistance_listing`,
|
|
18
|
+
`list_business_types` / `get_business_type`,
|
|
19
|
+
`list_mas_sins` / `get_mas_sin`. When `shape` is omitted, behavior is
|
|
20
|
+
unchanged — the API applies its own per-resource default.
|
|
21
|
+
`list_business_types` returns raw dicts (instead of `BusinessType`
|
|
22
|
+
instances) when a `shape` is supplied so the caller gets exactly the
|
|
23
|
+
shape requested.
|
|
24
|
+
|
|
25
|
+
## [1.1.2] - 2026-06-04
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- `get_entity_budget_flows()` now exposes the backend's standard page/limit
|
|
29
|
+
pagination and `fiscal_year` filter, and returns
|
|
30
|
+
`PaginatedResponse[dict[str, Any]]` instead of a raw dict. The backend has
|
|
31
|
+
always paginated this endpoint via `StandardResultsSetPagination`; the
|
|
32
|
+
previous signature gave callers no way to reach pages beyond the first or
|
|
33
|
+
to narrow by fiscal year. Callers that were indexing `result["results"]`
|
|
34
|
+
on the old return value should switch to `result.results` (and can now use
|
|
35
|
+
`result.next` / `page=` to walk further pages).
|
|
36
|
+
- Completed the strict-`mypy` burn-down across `tango/shapes/` (parser,
|
|
37
|
+
generator, factory, schema). All changes are type-annotation/typing
|
|
38
|
+
corrections with no runtime behavior change, except:
|
|
39
|
+
- `FieldSchema.nested_model` is now typed `type | str | None` (it always
|
|
40
|
+
accepted string model names from the explicit schemas; the annotation was
|
|
41
|
+
wrong). `ModelFactory.validate_data` and `ShapeParser._validate_field_spec`
|
|
42
|
+
likewise accept `type | str` for the model argument.
|
|
43
|
+
- Removed two dead `elif field_spec.is_wildcard:` branches (in
|
|
44
|
+
`TypeGenerator.generate_type` and `ModelFactory.create_instance`) and the
|
|
45
|
+
now-orphaned `_parse_nested_wildcard` helper. These were unreachable —
|
|
46
|
+
wildcard field specs are fully handled by the top-of-loop branch that
|
|
47
|
+
`continue`s before reaching them — so removal is behavior-preserving.
|
|
48
|
+
|
|
49
|
+
### Docs
|
|
50
|
+
- `docs/API_REFERENCE.md` now documents the Budget surface that shipped in
|
|
51
|
+
v1.1.0: a new `## Budget` section covering `list_budget_accounts`,
|
|
52
|
+
`get_budget_account`, `get_budget_account_quarters`, and
|
|
53
|
+
`get_budget_account_recipients`; a `get_entity_budget_flows()` entry under
|
|
54
|
+
Entity Sub-resources; a `BUDGET_ACCOUNTS_MINIMAL` row in the ShapeConfig
|
|
55
|
+
table; and a Budget entry in the table of contents.
|
|
56
|
+
|
|
57
|
+
### CI
|
|
58
|
+
- Bumped GitHub Actions off the deprecated Node 20 runtime (forced off
|
|
59
|
+
2026-06-02): `actions/checkout` v4→v6, `astral-sh/setup-uv` v4→v8.1.0
|
|
60
|
+
(pinned exact — no floating `v8` major tag is published yet), and
|
|
61
|
+
`codecov/codecov-action` v3→v5 (with the renamed `files:` input).
|
|
62
|
+
- `mypy` is now a **hard gate** in `lint.yml` (no longer advisory). The
|
|
63
|
+
`tango/` package type-checks cleanly under strict mypy.
|
|
64
|
+
|
|
10
65
|
## [1.1.1] - 2026-05-29
|
|
11
66
|
|
|
12
67
|
### Removed
|
|
@@ -21,6 +21,7 @@ Complete reference for all Tango Python SDK methods and functionality.
|
|
|
21
21
|
- [Grants](#grants)
|
|
22
22
|
- [GSA eLibrary Contracts](#gsa-elibrary-contracts)
|
|
23
23
|
- [Protests](#protests)
|
|
24
|
+
- [Budget](#budget)
|
|
24
25
|
- [Business Types](#business-types)
|
|
25
26
|
- [NAICS](#naics)
|
|
26
27
|
- [Webhooks](#webhooks)
|
|
@@ -1212,6 +1213,118 @@ protest = client.get_protest(
|
|
|
1212
1213
|
|
|
1213
1214
|
---
|
|
1214
1215
|
|
|
1216
|
+
## Budget
|
|
1217
|
+
|
|
1218
|
+
Federal account × fiscal year budget rollups, covering the full budget lifecycle (requested → enacted → apportioned → obligated → outlayed), pre-computed ratios and trends, the contract / assistance / unlinked breakdown, and request-vs-actual spend.
|
|
1219
|
+
|
|
1220
|
+
### list_budget_accounts()
|
|
1221
|
+
|
|
1222
|
+
List budget accounts. One row per `(federal_account_symbol, fiscal_year)`.
|
|
1223
|
+
|
|
1224
|
+
```python
|
|
1225
|
+
accounts = client.list_budget_accounts(
|
|
1226
|
+
page=1,
|
|
1227
|
+
limit=25,
|
|
1228
|
+
shape=ShapeConfig.BUDGET_ACCOUNTS_MINIMAL,
|
|
1229
|
+
# Filter parameters (all optional)
|
|
1230
|
+
federal_account_symbol=None,
|
|
1231
|
+
fiscal_year=None,
|
|
1232
|
+
fiscal_year_gte=None,
|
|
1233
|
+
fiscal_year_lte=None,
|
|
1234
|
+
agency_code=None,
|
|
1235
|
+
bureau_name=None,
|
|
1236
|
+
account_title=None,
|
|
1237
|
+
bea_category=None,
|
|
1238
|
+
on_off_budget=None,
|
|
1239
|
+
subfunction_code=None,
|
|
1240
|
+
search=None,
|
|
1241
|
+
ordering=None,
|
|
1242
|
+
)
|
|
1243
|
+
```
|
|
1244
|
+
|
|
1245
|
+
**Filter Parameters:**
|
|
1246
|
+
- `federal_account_symbol` - Exact federal account symbol (e.g., `"097-0100"`)
|
|
1247
|
+
- `fiscal_year` - Fiscal year (exact)
|
|
1248
|
+
- `fiscal_year_gte` / `fiscal_year_lte` - Fiscal year range
|
|
1249
|
+
- `agency_code` - Agency code (exact)
|
|
1250
|
+
- `bureau_name` - Bureau name (exact)
|
|
1251
|
+
- `account_title` - Account title (case-insensitive substring match)
|
|
1252
|
+
- `bea_category` - BEA category (exact)
|
|
1253
|
+
- `on_off_budget` - On/off budget flag (exact)
|
|
1254
|
+
- `subfunction_code` - Subfunction code (exact)
|
|
1255
|
+
- `search` - Full-text search over `account_title`, `agency_name`, `bureau_name`
|
|
1256
|
+
- `ordering` - Sort field; prefix with `-` for descending
|
|
1257
|
+
|
|
1258
|
+
**Returns:** [PaginatedResponse](#paginatedresponse) of `BudgetAccount` records (see [ShapeConfig](#shapeconfig-predefined-shapes) for the default shape).
|
|
1259
|
+
|
|
1260
|
+
**Example:**
|
|
1261
|
+
```python
|
|
1262
|
+
accounts = client.list_budget_accounts(
|
|
1263
|
+
agency_code="097",
|
|
1264
|
+
fiscal_year_gte=2023,
|
|
1265
|
+
ordering="-enacted_ba",
|
|
1266
|
+
limit=10,
|
|
1267
|
+
)
|
|
1268
|
+
|
|
1269
|
+
for acct in accounts.results:
|
|
1270
|
+
print(f"{acct.federal_account_symbol} FY{acct.fiscal_year}: "
|
|
1271
|
+
f"enacted ${acct.enacted_ba:,}")
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
### get_budget_account()
|
|
1275
|
+
|
|
1276
|
+
Get a single budget account by id.
|
|
1277
|
+
|
|
1278
|
+
```python
|
|
1279
|
+
account = client.get_budget_account(
|
|
1280
|
+
12345,
|
|
1281
|
+
shape=ShapeConfig.BUDGET_ACCOUNTS_MINIMAL,
|
|
1282
|
+
)
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1285
|
+
**Parameters:**
|
|
1286
|
+
- `id` (str | int): Budget account id.
|
|
1287
|
+
- `shape` (str, optional): Response shape. Defaults to `BUDGET_ACCOUNTS_MINIMAL`.
|
|
1288
|
+
- `flat` / `flat_lists` / `joiner`: See [Shaping Guide](SHAPES.md).
|
|
1289
|
+
|
|
1290
|
+
**Returns:** A `BudgetAccount` record.
|
|
1291
|
+
|
|
1292
|
+
### get_budget_account_quarters()
|
|
1293
|
+
|
|
1294
|
+
Get quarterly TAS-grain flow for a budget account. FY21+ only.
|
|
1295
|
+
|
|
1296
|
+
```python
|
|
1297
|
+
quarters = client.get_budget_account_quarters(12345, limit=25)
|
|
1298
|
+
```
|
|
1299
|
+
|
|
1300
|
+
**Parameters:**
|
|
1301
|
+
- `id` (str | int): Budget account id.
|
|
1302
|
+
- `tas` (str, optional): Narrow to a single Treasury Account Symbol.
|
|
1303
|
+
- `limit` (int): Results per page (max 100).
|
|
1304
|
+
|
|
1305
|
+
**Returns:** [PaginatedResponse](#paginatedresponse) of quarterly flow records.
|
|
1306
|
+
|
|
1307
|
+
### get_budget_account_recipients()
|
|
1308
|
+
|
|
1309
|
+
Get funding-office × recipient contract-flow detail for a budget account.
|
|
1310
|
+
|
|
1311
|
+
```python
|
|
1312
|
+
recipients = client.get_budget_account_recipients(
|
|
1313
|
+
12345,
|
|
1314
|
+
funding_organization_id=None,
|
|
1315
|
+
limit=25,
|
|
1316
|
+
)
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
**Parameters:**
|
|
1320
|
+
- `id` (str | int): Budget account id.
|
|
1321
|
+
- `funding_organization_id` (str, optional): Narrow to a single funding office (Organization UUID).
|
|
1322
|
+
- `limit` (int): Results per page (max 100).
|
|
1323
|
+
|
|
1324
|
+
**Returns:** [PaginatedResponse](#paginatedresponse) of `(funding_office, recipient)` flow records.
|
|
1325
|
+
|
|
1326
|
+
---
|
|
1327
|
+
|
|
1215
1328
|
## Business Types
|
|
1216
1329
|
|
|
1217
1330
|
Business type classifications.
|
|
@@ -1461,6 +1574,26 @@ lcats = client.list_entity_lcats("ABCDEF123456", limit=25)
|
|
|
1461
1574
|
metrics = client.get_entity_metrics("ABCDEF123456", months=12, period_grouping="month")
|
|
1462
1575
|
```
|
|
1463
1576
|
|
|
1577
|
+
### get_entity_budget_flows()
|
|
1578
|
+
|
|
1579
|
+
Get budget flows for an entity (`/api/entities/{uei}/budget-flows/`) — the federal accounts that funded contracts and assistance awarded to this entity.
|
|
1580
|
+
|
|
1581
|
+
```python
|
|
1582
|
+
flows = client.get_entity_budget_flows("ABCDEF123456", fiscal_year=2024)
|
|
1583
|
+
for row in flows.results:
|
|
1584
|
+
print(row["federal_account_symbol"], row["contract_obligated"])
|
|
1585
|
+
# next page
|
|
1586
|
+
more = client.get_entity_budget_flows("ABCDEF123456", page=2, fiscal_year=2024)
|
|
1587
|
+
```
|
|
1588
|
+
|
|
1589
|
+
**Parameters:**
|
|
1590
|
+
- `uei` (str): Entity UEI. Required.
|
|
1591
|
+
- `page` (int): Page number. Default 1.
|
|
1592
|
+
- `limit` (int): Results per page. Default 25, max 100.
|
|
1593
|
+
- `fiscal_year` (int | None): Optional fiscal year filter.
|
|
1594
|
+
|
|
1595
|
+
**Returns:** `PaginatedResponse[dict[str, Any]]` — standard `count / next / previous / results`. Result rows are raw dicts from the API (not shape-controlled).
|
|
1596
|
+
|
|
1464
1597
|
---
|
|
1465
1598
|
|
|
1466
1599
|
## IDV LCATs
|
|
@@ -1875,6 +2008,7 @@ entity = client.get_entity("UEI_KEY", shape=ShapeConfig.ENTITIES_COMPREHENSIVE)
|
|
|
1875
2008
|
| `SUBAWARDS_MINIMAL` | `list_subawards` | award_key, prime_recipient(uei,display_name), subaward_recipient(uei,display_name) |
|
|
1876
2009
|
| `GSA_ELIBRARY_CONTRACTS_MINIMAL` | `list_gsa_elibrary_contracts` | uuid, contract_number, schedule, recipient(display_name,uei), idv(key,award_date) |
|
|
1877
2010
|
| `PROTESTS_MINIMAL` | `list_protests` | case_id, case_number, title, source_system, outcome, filed_date |
|
|
2011
|
+
| `BUDGET_ACCOUNTS_MINIMAL` | `list_budget_accounts`, `get_budget_account` | id, federal_account_symbol, fiscal_year, agency_code/name, bureau_name, account_title, bea_category, on_off_budget, subfunction_code, lifecycle (requested/enacted/apportioned/obligated/outlayed/unobligated), contract & assistance rollups, key ratios, next-year growth |
|
|
1878
2012
|
| `VEHICLE_ORDERS_MINIMAL` | `list_vehicle_orders` | key, piid, award_date, recipient(display_name,uei), total_contract_value, obligated |
|
|
1879
2013
|
| `ITDASHBOARD_INVESTMENTS_MINIMAL` | `list_itdashboard_investments` | Minimal IT Dashboard investment fields |
|
|
1880
2014
|
| `ITDASHBOARD_INVESTMENTS_COMPREHENSIVE` | `get_itdashboard_investment` | Full investment fields: uii, agency_code, agency_name, bureau_code, bureau_name, investment_title, type_of_investment, part_of_it_portfolio, updated_time, url |
|
|
@@ -1923,15 +1923,37 @@ class TangoClient:
|
|
|
1923
1923
|
)
|
|
1924
1924
|
|
|
1925
1925
|
# Business Types endpoints
|
|
1926
|
-
def list_business_types(
|
|
1927
|
-
|
|
1928
|
-
|
|
1926
|
+
def list_business_types(
|
|
1927
|
+
self,
|
|
1928
|
+
page: int = 1,
|
|
1929
|
+
limit: int = 25,
|
|
1930
|
+
shape: str | None = None,
|
|
1931
|
+
flat: bool = False,
|
|
1932
|
+
flat_lists: bool = False,
|
|
1933
|
+
) -> PaginatedResponse:
|
|
1934
|
+
"""List business types.
|
|
1935
|
+
|
|
1936
|
+
When ``shape`` is omitted the API applies its own default
|
|
1937
|
+
(``name,code``) and results are returned as :class:`BusinessType`
|
|
1938
|
+
instances. When ``shape`` is provided, raw dicts are returned so the
|
|
1939
|
+
caller can rely on the exact shape requested.
|
|
1940
|
+
"""
|
|
1941
|
+
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
1942
|
+
if shape:
|
|
1943
|
+
params["shape"] = shape
|
|
1944
|
+
if flat:
|
|
1945
|
+
params["flat"] = "true"
|
|
1946
|
+
if flat_lists:
|
|
1947
|
+
params["flat_lists"] = "true"
|
|
1929
1948
|
data = self._get("/api/business_types/", params)
|
|
1949
|
+
results: list[Any] = (
|
|
1950
|
+
list(data["results"]) if shape else [BusinessType(**btype) for btype in data["results"]]
|
|
1951
|
+
)
|
|
1930
1952
|
return PaginatedResponse(
|
|
1931
1953
|
count=data["count"],
|
|
1932
1954
|
next=data.get("next"),
|
|
1933
1955
|
previous=data.get("previous"),
|
|
1934
|
-
results=
|
|
1956
|
+
results=results,
|
|
1935
1957
|
)
|
|
1936
1958
|
|
|
1937
1959
|
def list_naics(
|
|
@@ -1945,8 +1967,17 @@ class TangoClient:
|
|
|
1945
1967
|
revenue_limit_gte: int | None = None,
|
|
1946
1968
|
revenue_limit_lte: int | None = None,
|
|
1947
1969
|
search: str | None = None,
|
|
1970
|
+
shape: str | None = None,
|
|
1971
|
+
flat: bool = False,
|
|
1972
|
+
flat_lists: bool = False,
|
|
1948
1973
|
) -> PaginatedResponse:
|
|
1949
|
-
"""List NAICS codes (`/api/naics/`).
|
|
1974
|
+
"""List NAICS codes (`/api/naics/`).
|
|
1975
|
+
|
|
1976
|
+
When ``shape`` is omitted the API applies its own default. Passing any
|
|
1977
|
+
of the ``revenue_limit*`` / ``employee_limit*`` filters causes the API
|
|
1978
|
+
to widen the default shape to include ``size_standards`` and
|
|
1979
|
+
``federal_obligations``.
|
|
1980
|
+
"""
|
|
1950
1981
|
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
1951
1982
|
if employee_limit is not None:
|
|
1952
1983
|
params["employee_limit"] = employee_limit
|
|
@@ -1962,6 +1993,12 @@ class TangoClient:
|
|
|
1962
1993
|
params["revenue_limit_lte"] = revenue_limit_lte
|
|
1963
1994
|
if search is not None:
|
|
1964
1995
|
params["search"] = search
|
|
1996
|
+
if shape:
|
|
1997
|
+
params["shape"] = shape
|
|
1998
|
+
if flat:
|
|
1999
|
+
params["flat"] = "true"
|
|
2000
|
+
if flat_lists:
|
|
2001
|
+
params["flat_lists"] = "true"
|
|
1965
2002
|
data = self._get("/api/naics/", params)
|
|
1966
2003
|
return PaginatedResponse(
|
|
1967
2004
|
count=data.get("count", 0),
|
|
@@ -2081,11 +2118,36 @@ class TangoClient:
|
|
|
2081
2118
|
data = self._get(f"/api/entities/{key}/", params)
|
|
2082
2119
|
return self._parse_response_with_shape(data, shape, Entity, flat, flat_lists)
|
|
2083
2120
|
|
|
2084
|
-
def get_entity_budget_flows(
|
|
2085
|
-
|
|
2121
|
+
def get_entity_budget_flows(
|
|
2122
|
+
self,
|
|
2123
|
+
uei: str,
|
|
2124
|
+
page: int = 1,
|
|
2125
|
+
limit: int = 25,
|
|
2126
|
+
fiscal_year: int | None = None,
|
|
2127
|
+
) -> PaginatedResponse[dict[str, Any]]:
|
|
2128
|
+
"""Get budget flows for an entity (`/api/entities/{uei}/budget-flows/`).
|
|
2129
|
+
|
|
2130
|
+
Standard page/limit pagination (default 25, max 100). Each result row
|
|
2131
|
+
is a hand-built dict from the backend (no shape system).
|
|
2132
|
+
|
|
2133
|
+
Args:
|
|
2134
|
+
uei: Entity UEI. Required.
|
|
2135
|
+
page: Page number.
|
|
2136
|
+
limit: Results per page (max 100).
|
|
2137
|
+
fiscal_year: Optional fiscal year filter.
|
|
2138
|
+
"""
|
|
2086
2139
|
if not uei:
|
|
2087
2140
|
raise TangoValidationError("UEI is required")
|
|
2088
|
-
|
|
2141
|
+
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
2142
|
+
if fiscal_year is not None:
|
|
2143
|
+
params["fiscal_year"] = fiscal_year
|
|
2144
|
+
data = self._get(f"/api/entities/{uei}/budget-flows/", params)
|
|
2145
|
+
return PaginatedResponse(
|
|
2146
|
+
count=int(data.get("count", 0)),
|
|
2147
|
+
next=data.get("next"),
|
|
2148
|
+
previous=data.get("previous"),
|
|
2149
|
+
results=list(data.get("results") or []),
|
|
2150
|
+
)
|
|
2089
2151
|
|
|
2090
2152
|
# Forecast endpoints
|
|
2091
2153
|
def list_forecasts(
|
|
@@ -3319,9 +3381,22 @@ class TangoClient:
|
|
|
3319
3381
|
raise TangoValidationError("Department code is required")
|
|
3320
3382
|
return self._get(f"/api/departments/{code}/")
|
|
3321
3383
|
|
|
3322
|
-
def list_psc(
|
|
3384
|
+
def list_psc(
|
|
3385
|
+
self,
|
|
3386
|
+
page: int = 1,
|
|
3387
|
+
limit: int = 25,
|
|
3388
|
+
shape: str | None = None,
|
|
3389
|
+
flat: bool = False,
|
|
3390
|
+
flat_lists: bool = False,
|
|
3391
|
+
) -> PaginatedResponse[dict[str, Any]]:
|
|
3323
3392
|
"""List Product Service Codes (`/api/psc/`)."""
|
|
3324
3393
|
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
3394
|
+
if shape:
|
|
3395
|
+
params["shape"] = shape
|
|
3396
|
+
if flat:
|
|
3397
|
+
params["flat"] = "true"
|
|
3398
|
+
if flat_lists:
|
|
3399
|
+
params["flat_lists"] = "true"
|
|
3325
3400
|
data = self._get("/api/psc/", params)
|
|
3326
3401
|
return PaginatedResponse(
|
|
3327
3402
|
count=int(data.get("count", 0)),
|
|
@@ -3330,11 +3405,24 @@ class TangoClient:
|
|
|
3330
3405
|
results=list(data.get("results") or []),
|
|
3331
3406
|
)
|
|
3332
3407
|
|
|
3333
|
-
def get_psc(
|
|
3408
|
+
def get_psc(
|
|
3409
|
+
self,
|
|
3410
|
+
code: str,
|
|
3411
|
+
shape: str | None = None,
|
|
3412
|
+
flat: bool = False,
|
|
3413
|
+
flat_lists: bool = False,
|
|
3414
|
+
) -> dict[str, Any]:
|
|
3334
3415
|
"""Get a Product Service Code by code (`/api/psc/{code}/`)."""
|
|
3335
3416
|
if not code:
|
|
3336
3417
|
raise TangoValidationError("PSC code is required")
|
|
3337
|
-
|
|
3418
|
+
params: dict[str, Any] = {}
|
|
3419
|
+
if shape:
|
|
3420
|
+
params["shape"] = shape
|
|
3421
|
+
if flat:
|
|
3422
|
+
params["flat"] = "true"
|
|
3423
|
+
if flat_lists:
|
|
3424
|
+
params["flat_lists"] = "true"
|
|
3425
|
+
return self._get(f"/api/psc/{code}/", params)
|
|
3338
3426
|
|
|
3339
3427
|
def get_psc_metrics(self, code: str, months: int, period_grouping: str) -> dict[str, Any]:
|
|
3340
3428
|
"""Get rolling PSC metrics (`/api/psc/{code}/metrics/{months}/{period_grouping}/`).
|
|
@@ -3349,11 +3437,24 @@ class TangoClient:
|
|
|
3349
3437
|
raise TangoValidationError("PSC code is required")
|
|
3350
3438
|
return self._get(f"/api/psc/{code}/metrics/{months}/{period_grouping}/")
|
|
3351
3439
|
|
|
3352
|
-
def get_naics(
|
|
3440
|
+
def get_naics(
|
|
3441
|
+
self,
|
|
3442
|
+
code: str,
|
|
3443
|
+
shape: str | None = None,
|
|
3444
|
+
flat: bool = False,
|
|
3445
|
+
flat_lists: bool = False,
|
|
3446
|
+
) -> dict[str, Any]:
|
|
3353
3447
|
"""Get a NAICS code by code (`/api/naics/{code}/`)."""
|
|
3354
3448
|
if not code:
|
|
3355
3449
|
raise TangoValidationError("NAICS code is required")
|
|
3356
|
-
|
|
3450
|
+
params: dict[str, Any] = {}
|
|
3451
|
+
if shape:
|
|
3452
|
+
params["shape"] = shape
|
|
3453
|
+
if flat:
|
|
3454
|
+
params["flat"] = "true"
|
|
3455
|
+
if flat_lists:
|
|
3456
|
+
params["flat_lists"] = "true"
|
|
3457
|
+
return self._get(f"/api/naics/{code}/", params)
|
|
3357
3458
|
|
|
3358
3459
|
def get_naics_metrics(self, code: str, months: int, period_grouping: str) -> dict[str, Any]:
|
|
3359
3460
|
"""Get rolling NAICS metrics (`/api/naics/{code}/metrics/{months}/{period_grouping}/`)."""
|
|
@@ -3361,17 +3462,41 @@ class TangoClient:
|
|
|
3361
3462
|
raise TangoValidationError("NAICS code is required")
|
|
3362
3463
|
return self._get(f"/api/naics/{code}/metrics/{months}/{period_grouping}/")
|
|
3363
3464
|
|
|
3364
|
-
def get_business_type(
|
|
3465
|
+
def get_business_type(
|
|
3466
|
+
self,
|
|
3467
|
+
code: str,
|
|
3468
|
+
shape: str | None = None,
|
|
3469
|
+
flat: bool = False,
|
|
3470
|
+
flat_lists: bool = False,
|
|
3471
|
+
) -> dict[str, Any]:
|
|
3365
3472
|
"""Get a business type by code (`/api/business_types/{code}/`)."""
|
|
3366
3473
|
if not code:
|
|
3367
3474
|
raise TangoValidationError("Business type code is required")
|
|
3368
|
-
|
|
3475
|
+
params: dict[str, Any] = {}
|
|
3476
|
+
if shape:
|
|
3477
|
+
params["shape"] = shape
|
|
3478
|
+
if flat:
|
|
3479
|
+
params["flat"] = "true"
|
|
3480
|
+
if flat_lists:
|
|
3481
|
+
params["flat_lists"] = "true"
|
|
3482
|
+
return self._get(f"/api/business_types/{code}/", params)
|
|
3369
3483
|
|
|
3370
3484
|
def list_assistance_listings(
|
|
3371
|
-
self,
|
|
3485
|
+
self,
|
|
3486
|
+
page: int = 1,
|
|
3487
|
+
limit: int = 25,
|
|
3488
|
+
shape: str | None = None,
|
|
3489
|
+
flat: bool = False,
|
|
3490
|
+
flat_lists: bool = False,
|
|
3372
3491
|
) -> PaginatedResponse[dict[str, Any]]:
|
|
3373
3492
|
"""List Assistance Listings (CFDA programs) (`/api/assistance_listings/`)."""
|
|
3374
3493
|
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
3494
|
+
if shape:
|
|
3495
|
+
params["shape"] = shape
|
|
3496
|
+
if flat:
|
|
3497
|
+
params["flat"] = "true"
|
|
3498
|
+
if flat_lists:
|
|
3499
|
+
params["flat_lists"] = "true"
|
|
3375
3500
|
data = self._get("/api/assistance_listings/", params)
|
|
3376
3501
|
return PaginatedResponse(
|
|
3377
3502
|
count=int(data.get("count", 0)),
|
|
@@ -3380,22 +3505,44 @@ class TangoClient:
|
|
|
3380
3505
|
results=list(data.get("results") or []),
|
|
3381
3506
|
)
|
|
3382
3507
|
|
|
3383
|
-
def get_assistance_listing(
|
|
3508
|
+
def get_assistance_listing(
|
|
3509
|
+
self,
|
|
3510
|
+
number: str,
|
|
3511
|
+
shape: str | None = None,
|
|
3512
|
+
flat: bool = False,
|
|
3513
|
+
flat_lists: bool = False,
|
|
3514
|
+
) -> dict[str, Any]:
|
|
3384
3515
|
"""Get an Assistance Listing by CFDA number (`/api/assistance_listings/{number}/`)."""
|
|
3385
3516
|
if not number:
|
|
3386
3517
|
raise TangoValidationError("Assistance listing number is required")
|
|
3387
|
-
|
|
3518
|
+
params: dict[str, Any] = {}
|
|
3519
|
+
if shape:
|
|
3520
|
+
params["shape"] = shape
|
|
3521
|
+
if flat:
|
|
3522
|
+
params["flat"] = "true"
|
|
3523
|
+
if flat_lists:
|
|
3524
|
+
params["flat_lists"] = "true"
|
|
3525
|
+
return self._get(f"/api/assistance_listings/{number}/", params)
|
|
3388
3526
|
|
|
3389
3527
|
def list_mas_sins(
|
|
3390
3528
|
self,
|
|
3391
3529
|
page: int = 1,
|
|
3392
3530
|
limit: int = 25,
|
|
3393
3531
|
search: str | None = None,
|
|
3532
|
+
shape: str | None = None,
|
|
3533
|
+
flat: bool = False,
|
|
3534
|
+
flat_lists: bool = False,
|
|
3394
3535
|
) -> PaginatedResponse[dict[str, Any]]:
|
|
3395
3536
|
"""List GSA MAS SINs (`/api/mas_sins/`)."""
|
|
3396
3537
|
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
3397
3538
|
if search is not None:
|
|
3398
3539
|
params["search"] = search
|
|
3540
|
+
if shape:
|
|
3541
|
+
params["shape"] = shape
|
|
3542
|
+
if flat:
|
|
3543
|
+
params["flat"] = "true"
|
|
3544
|
+
if flat_lists:
|
|
3545
|
+
params["flat_lists"] = "true"
|
|
3399
3546
|
data = self._get("/api/mas_sins/", params)
|
|
3400
3547
|
return PaginatedResponse(
|
|
3401
3548
|
count=int(data.get("count", 0)),
|
|
@@ -3404,11 +3551,24 @@ class TangoClient:
|
|
|
3404
3551
|
results=list(data.get("results") or []),
|
|
3405
3552
|
)
|
|
3406
3553
|
|
|
3407
|
-
def get_mas_sin(
|
|
3554
|
+
def get_mas_sin(
|
|
3555
|
+
self,
|
|
3556
|
+
sin: str,
|
|
3557
|
+
shape: str | None = None,
|
|
3558
|
+
flat: bool = False,
|
|
3559
|
+
flat_lists: bool = False,
|
|
3560
|
+
) -> dict[str, Any]:
|
|
3408
3561
|
"""Get a MAS SIN by code (`/api/mas_sins/{sin}/`)."""
|
|
3409
3562
|
if not sin:
|
|
3410
3563
|
raise TangoValidationError("MAS SIN is required")
|
|
3411
|
-
|
|
3564
|
+
params: dict[str, Any] = {}
|
|
3565
|
+
if shape:
|
|
3566
|
+
params["shape"] = shape
|
|
3567
|
+
if flat:
|
|
3568
|
+
params["flat"] = "true"
|
|
3569
|
+
if flat_lists:
|
|
3570
|
+
params["flat_lists"] = "true"
|
|
3571
|
+
return self._get(f"/api/mas_sins/{sin}/", params)
|
|
3412
3572
|
|
|
3413
3573
|
# ============================================================================
|
|
3414
3574
|
# Entity sub-resources
|