tango-python 1.11.0__tar.gz → 1.12.0__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.11.0 → tango_python-1.12.0}/CHANGELOG.md +16 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/PKG-INFO +1 -1
- {tango_python-1.11.0 → tango_python-1.12.0}/docs/API_REFERENCE.md +14 -2
- {tango_python-1.11.0 → tango_python-1.12.0}/pyproject.toml +1 -1
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/__init__.py +7 -1
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/client.py +16 -1
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/models.py +55 -2
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/generated_overlay.py +6 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_client.py +135 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/.gitignore +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/LICENSE +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/README.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/docs/CLIENT.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/docs/DYNAMIC_MODELS.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/docs/ERRORS.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/docs/PAGINATION.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/docs/SHAPES.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/docs/WEBHOOKS.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/README.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/check_filter_shape_conformance.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/check_shape_coverage.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/fetch_api_schema.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/generate_schemas_from_api.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/generate_shape_overlay.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/pr_review.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/probe_shape_types.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/refresh_contract.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/smoke_api_parity.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/scripts/test_production.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/exceptions.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/__init__.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/explicit_schemas.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/factory.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/generator.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/models.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/parser.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/schema.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/shapes/types.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/webhooks/__init__.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/webhooks/cli.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/webhooks/receiver.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/webhooks/signing.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tango/webhooks/simulate.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/__init__.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestAgenciesIntegration.test_get_agency +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestAgenciesIntegration.test_list_agencies +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_field_type_validation +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_parsing_consistency +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestBusinessTypesIntegration.test_list_business_types +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_combined_filters_work_together +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_contract_cursor_pagination +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_contract_data_object_parsing +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_contract_field_types +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[keyword-software] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[psc_code-R425] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_awarding_agency_filter +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_date_range_filter +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_flat +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_naics_code_filter +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[custom-key,piid,recipient(display_name),total_contract_value,award_date] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[default-None] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_new_expiring_filters +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_new_fiscal_year_range_filters +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_new_identifier_filters +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_search_contracts_with_filters +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_search_filters_object_with_new_parameters +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[asc-] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[desc--] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_contracts +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_entities +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_date_field_parsing_edge_cases +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_decimal_field_parsing_edge_cases +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_empty_list_responses +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_entity_parsing_with_various_address_formats +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_flattened_responses_with_flat_lists +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_list_field_parsing_consistency +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_nested_objects_with_missing_data +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_null_missing_fields_in_contracts +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_with_minimal_shape_sparse_data +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_entity_field_types +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_entity_location_parsing +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_entity_parsing_with_business_types +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_entity_with_various_identifiers +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_budget_flows +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_by_uei +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_flat +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_search +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[custom-uei,legal_business_name,cage_code] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestForecastsIntegration.test_forecast_field_types +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[custom-id,title,anticipated_award_date] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[default-None] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[minimal-id,title,anticipated_award_date,fiscal_year,naics_code,status] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestGrantsIntegration.test_grant_field_types +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestGrantsIntegration.test_grant_pagination +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[custom-grant_id,title,opportunity_number] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[default-None] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[minimal-grant_id,opportunity_number,title,status(-),agency_code] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestIDVsIntegration.test_get_idv_uses_default_shape +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_awards_uses_default_shape +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_child_idvs_uses_default_shape +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_transactions +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestIDVsIntegration.test_list_idvs_uses_default_shape_and_keyset_params +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestNaicsIntegration.test_list_naics +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[custom-notice_id,title,solicitation_number] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[default-None] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestNoticesIntegration.test_notice_field_types +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestNoticesIntegration.test_notice_pagination +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestNoticesIntegration.test_notice_with_meta_fields +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOTAsIntegration.test_get_ota +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOTAsIntegration.test_list_otas +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOTIDVsIntegration.test_get_otidv +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOTIDVsIntegration.test_list_otidvs +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOfficesIntegration.test_get_office +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOfficesIntegration.test_list_offices +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[custom-opportunity_id,title,solicitation_number] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[default-None] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOpportunitiesIntegration.test_opportunity_field_types +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOrganizationsIntegration.test_get_organization +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestOrganizationsIntegration.test_list_organizations +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestProtestsIntegration.test_get_protest_by_case_id +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_filter +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[custom-case_id,title,source_system,outcome] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[default-None] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[minimal-case_id,case_number,title,source_system,outcome,filed_date] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestProtestsIntegration.test_protest_pagination +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestSubawardsIntegration.test_list_subawards +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[custom-key,piid,description] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[minimal-key,piid,award_date,recipient(display_name),description,total_contract_value] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[ultra_minimal-key,piid,recipient(display_name),total_contract_value] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[with_address-uei,legal_business_name,cage_code,business_types,physical_address] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestTypeHintsIntegration.test_notices_dict_access[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/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.11.0 → tango_python-1.12.0}/tests/cassettes/TestTypeHintsIntegration.test_opportunities_dict_access[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_with_metrics_expansion +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_orders_uses_default_shape +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_with_ordering +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/conftest.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/README.md +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/__init__.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/conftest.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_agencies_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_contracts_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_edge_cases_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_entities_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_forecasts_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_grants_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_itdashboard_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_naics_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_notices_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_offices_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_opportunities_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_organizations_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_otas_otidvs_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_protests_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_reference_data_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_subawards_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/test_vehicles_idvs_integration.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/integration/validation.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/production/__init__.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/production/conftest.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/production/test_production_smoke.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_api_parity.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_contract_appeals.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_dibbs_exclusions_sbir.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_ebuy.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_federal_register.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_models.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_opportunity_attachments.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_opportunity_awards.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_organization_scope.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_shape_coverage_gate.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_shapes.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_sled.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_webhooks_cli.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_webhooks_receiver.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_webhooks_signing.py +0 -0
- {tango_python-1.11.0 → tango_python-1.12.0}/tests/test_webhooks_simulate.py +0 -0
|
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.12.0] - 2026-10-02
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`account_category` and `source_anomalies` on budget accounts** (Tango API 5.7.0). Both are in the default `BUDGET_ACCOUNTS_MINIMAL` shape and accepted in custom shapes. `account_category` is `budgetary` or `credit_financing` today. `source_anomalies` lists the problems found in the source data behind an account, and is `[]` when there are none. Each element is typed as the new `BudgetAccountSourceAnomaly` `TypedDict` (with `BudgetAccountAnomalySource` and `BudgetAccountAnomalySourceRow` for its nested `source`), and every key is optional. Treat `account_category` and an anomaly's `code` as open strings, since new values may appear.
|
|
15
|
+
- **`list_budget_accounts(account_category=..., account_category_in=...)`** filters by account category, exactly or against a comma-separated list.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **`list_budget_accounts()` documents the API's default ordering**: the latest fiscal year first, then largest `enacted_ba` first, with accounts that have no `enacted_ba` last.
|
|
20
|
+
- Re-vendored `contracts/filter_shape_contract.json` (Tango API 5.7.0) and regenerated `tango/shapes/generated_overlay.py`.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **`list_idvs()`, `list_idv_awards()`, `list_idv_child_idvs()` and `list_idv_transactions()` now return the API's pagination `cursor`.** They dropped it, so `response.cursor` was always `None` and a caller following the cursor stopped after the first page.
|
|
25
|
+
|
|
10
26
|
## [1.11.0] - 2026-09-29
|
|
11
27
|
|
|
12
28
|
### Added
|
|
@@ -1770,6 +1770,8 @@ accounts = client.list_budget_accounts(
|
|
|
1770
1770
|
bea_category=None,
|
|
1771
1771
|
on_off_budget=None,
|
|
1772
1772
|
subfunction_code=None,
|
|
1773
|
+
account_category=None,
|
|
1774
|
+
account_category_in=None,
|
|
1773
1775
|
search=None,
|
|
1774
1776
|
ordering=None,
|
|
1775
1777
|
)
|
|
@@ -1785,8 +1787,18 @@ accounts = client.list_budget_accounts(
|
|
|
1785
1787
|
- `bea_category` - BEA category (exact)
|
|
1786
1788
|
- `on_off_budget` - On/off budget flag (exact)
|
|
1787
1789
|
- `subfunction_code` - Subfunction code (exact)
|
|
1790
|
+
- `account_category` - Account category (exact): `budgetary` or `credit_financing` today; treat it as an open string
|
|
1791
|
+
- `account_category_in` - Comma-separated account categories to match any of (e.g. `"budgetary,credit_financing"`)
|
|
1788
1792
|
- `search` - Full-text search over `account_title`, `agency_name`, `bureau_name`
|
|
1789
|
-
- `ordering` - Sort field; prefix with `-` for descending
|
|
1793
|
+
- `ordering` - Sort field; prefix with `-` for descending. The default is the latest fiscal year first, then largest `enacted_ba` first, with accounts that have no `enacted_ba` last.
|
|
1794
|
+
|
|
1795
|
+
**Source anomalies:** the default shape includes `account_category` and `source_anomalies`. `source_anomalies` is a list of problems found in the source data behind the account, and `[]` when there are none. Each element is a `BudgetAccountSourceAnomaly` (a `TypedDict`; every key is optional and may be `None`, so read keys with `.get()`): `code`, `field`, `bound_field`, `action` (`capped` or `flagged`), `reported_value`, `served_value`, `likely_cause`, `affected_fields`, `message`, and `source` (`dataset`, `fiscal_year`, and `rows` of `fiscal_period`, `piid`, `parent_piid`, `tas`, `reporting_agency_id`, `transaction_obligated_amount`, `file_c_source`). Today `code` is one of `contract_exceeds_obligations`, `assistance_exceeds_obligations` or `contract_without_obligations`; treat it as an open string. There is no filter on anomalies.
|
|
1796
|
+
|
|
1797
|
+
```python
|
|
1798
|
+
for acct in client.list_budget_accounts(fiscal_year=2025).results:
|
|
1799
|
+
for anomaly in acct["source_anomalies"] or []:
|
|
1800
|
+
print(acct["federal_account_symbol"], anomaly.get("code"), anomaly.get("action"))
|
|
1801
|
+
```
|
|
1790
1802
|
|
|
1791
1803
|
**Returns:** [PaginatedResponse](#paginatedresponse) of `BudgetAccount` records (see [ShapeConfig](#shapeconfig-predefined-shapes) for the default shape).
|
|
1792
1804
|
|
|
@@ -2547,7 +2559,7 @@ entity = client.get_entity("UEI_KEY", shape=ShapeConfig.ENTITIES_COMPREHENSIVE)
|
|
|
2547
2559
|
| `FEDERAL_REGISTER_COMPREHENSIVE` | `get_federal_register_document` | The list fields plus dates, signing_date, start_page, end_page, volume, docket_ids, dockets, regulation_id_numbers, topics, correction_of, corrections, executive_order_number, presidential_document_number, proclamation_number, comment_url, regulations_dot_gov_url, raw_text_url, body_html_url (omits `full_text`) |
|
|
2548
2560
|
| `EBUY_REQUESTS_MINIMAL` | `list_ebuy_requests` | rfq_id, request_type, title, schedule, sin, status, buyer_name, buyer_agency, buyer_agency_code, reference_number, issue_date, close_date, attachment_count, link_count, last_seen |
|
|
2549
2561
|
| `EBUY_REQUESTS_COMPREHENSIVE` | `get_ebuy_request` | Every field, plus the `organization` and `attachments` expands |
|
|
2550
|
-
| `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 |
|
|
2562
|
+
| `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, account_category, lifecycle (requested/enacted/apportioned/obligated/outlayed/unobligated), contract & assistance rollups, key ratios, next-year growth, source_anomalies |
|
|
2551
2563
|
| `VEHICLE_ORDERS_MINIMAL` | `list_vehicle_orders` | key, piid, award_date, recipient(display_name,uei), total_contract_value, obligated |
|
|
2552
2564
|
| `ITDASHBOARD_INVESTMENTS_MINIMAL` | `list_itdashboard_investments` | Minimal IT Dashboard investment fields |
|
|
2553
2565
|
| `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 |
|
|
@@ -11,6 +11,9 @@ from .exceptions import (
|
|
|
11
11
|
)
|
|
12
12
|
from .models import (
|
|
13
13
|
BudgetAccount,
|
|
14
|
+
BudgetAccountAnomalySource,
|
|
15
|
+
BudgetAccountAnomalySourceRow,
|
|
16
|
+
BudgetAccountSourceAnomaly,
|
|
14
17
|
ContractAppeal,
|
|
15
18
|
DibbsAward,
|
|
16
19
|
DibbsRfp,
|
|
@@ -59,7 +62,7 @@ from .webhooks import (
|
|
|
59
62
|
)
|
|
60
63
|
from .webhooks.receiver import Delivery, WebhookReceiver
|
|
61
64
|
|
|
62
|
-
__version__ = "1.
|
|
65
|
+
__version__ = "1.12.0"
|
|
63
66
|
__all__ = [
|
|
64
67
|
"TangoClient",
|
|
65
68
|
"TangoAPIError",
|
|
@@ -72,6 +75,9 @@ __all__ = [
|
|
|
72
75
|
"ResolveCandidate",
|
|
73
76
|
"ResolveResult",
|
|
74
77
|
"BudgetAccount",
|
|
78
|
+
"BudgetAccountAnomalySource",
|
|
79
|
+
"BudgetAccountAnomalySourceRow",
|
|
80
|
+
"BudgetAccountSourceAnomaly",
|
|
75
81
|
"ContractAppeal",
|
|
76
82
|
"FederalRegisterDocument",
|
|
77
83
|
"EbuyAccess",
|
|
@@ -986,6 +986,7 @@ class TangoClient:
|
|
|
986
986
|
next=data.get("next"),
|
|
987
987
|
previous=data.get("previous"),
|
|
988
988
|
results=results,
|
|
989
|
+
cursor=data.get("cursor"),
|
|
989
990
|
page_metadata=data.get("page_metadata"),
|
|
990
991
|
meta=data.get("meta"),
|
|
991
992
|
)
|
|
@@ -1088,6 +1089,7 @@ class TangoClient:
|
|
|
1088
1089
|
next=data.get("next"),
|
|
1089
1090
|
previous=data.get("previous"),
|
|
1090
1091
|
results=results,
|
|
1092
|
+
cursor=data.get("cursor"),
|
|
1091
1093
|
page_metadata=data.get("page_metadata"),
|
|
1092
1094
|
meta=data.get("meta"),
|
|
1093
1095
|
)
|
|
@@ -1133,6 +1135,7 @@ class TangoClient:
|
|
|
1133
1135
|
next=data.get("next"),
|
|
1134
1136
|
previous=data.get("previous"),
|
|
1135
1137
|
results=results,
|
|
1138
|
+
cursor=data.get("cursor"),
|
|
1136
1139
|
page_metadata=data.get("page_metadata"),
|
|
1137
1140
|
meta=data.get("meta"),
|
|
1138
1141
|
)
|
|
@@ -1150,6 +1153,7 @@ class TangoClient:
|
|
|
1150
1153
|
next=data.get("next"),
|
|
1151
1154
|
previous=data.get("previous"),
|
|
1152
1155
|
results=data.get("results") or [],
|
|
1156
|
+
cursor=data.get("cursor"),
|
|
1153
1157
|
page_metadata=data.get("page_metadata"),
|
|
1154
1158
|
meta=data.get("meta"),
|
|
1155
1159
|
)
|
|
@@ -4444,6 +4448,8 @@ class TangoClient:
|
|
|
4444
4448
|
bea_category: str | None = None,
|
|
4445
4449
|
on_off_budget: str | None = None,
|
|
4446
4450
|
subfunction_code: str | None = None,
|
|
4451
|
+
account_category: str | None = None,
|
|
4452
|
+
account_category_in: str | None = None,
|
|
4447
4453
|
# Range-numeric filters: each field also accepts ``__gte`` / ``__lte``.
|
|
4448
4454
|
requested_ba: float | None = None,
|
|
4449
4455
|
requested_ba_gte: float | None = None,
|
|
@@ -4550,6 +4556,11 @@ class TangoClient:
|
|
|
4550
4556
|
bea_category: BEA category (exact).
|
|
4551
4557
|
on_off_budget: On/off budget flag (exact).
|
|
4552
4558
|
subfunction_code: Subfunction code (exact).
|
|
4559
|
+
account_category: Account category (exact), e.g. ``budgetary`` or
|
|
4560
|
+
``credit_financing``. Treat the value as an open string; new
|
|
4561
|
+
categories may be added.
|
|
4562
|
+
account_category_in: Comma-separated account categories to match
|
|
4563
|
+
any of, e.g. ``"budgetary,credit_financing"``.
|
|
4553
4564
|
requested_ba: President's-budget requested BA (exact). Also
|
|
4554
4565
|
``requested_ba_gte`` / ``requested_ba_lte`` for range queries.
|
|
4555
4566
|
enacted_ba: Enacted budget authority (exact / gte / lte).
|
|
@@ -4592,7 +4603,9 @@ class TangoClient:
|
|
|
4592
4603
|
ordering: Sort field (prefix with '-' for descending). Any of the
|
|
4593
4604
|
numeric fields above is a valid ordering target — e.g.
|
|
4594
4605
|
``ordering="-unobligated_balance"`` to rank by largest
|
|
4595
|
-
headroom first.
|
|
4606
|
+
headroom first. The default ordering is the latest fiscal year
|
|
4607
|
+
first, then largest ``enacted_ba`` first, with accounts that
|
|
4608
|
+
have no ``enacted_ba`` sorted last.
|
|
4596
4609
|
"""
|
|
4597
4610
|
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
4598
4611
|
if shape is None:
|
|
@@ -4615,6 +4628,8 @@ class TangoClient:
|
|
|
4615
4628
|
("bea_category", bea_category),
|
|
4616
4629
|
("on_off_budget", on_off_budget),
|
|
4617
4630
|
("subfunction_code", subfunction_code),
|
|
4631
|
+
("account_category", account_category),
|
|
4632
|
+
("account_category__in", account_category_in),
|
|
4618
4633
|
("search", search),
|
|
4619
4634
|
("ordering", ordering),
|
|
4620
4635
|
)
|
|
@@ -786,6 +786,55 @@ class ValidateResult:
|
|
|
786
786
|
errors: list[str] | None = None
|
|
787
787
|
|
|
788
788
|
|
|
789
|
+
class BudgetAccountAnomalySourceRow(TypedDict, total=False):
|
|
790
|
+
"""One source record behind a budget-account source anomaly.
|
|
791
|
+
|
|
792
|
+
Every key is optional and any value may be ``None``.
|
|
793
|
+
"""
|
|
794
|
+
|
|
795
|
+
fiscal_period: int | None
|
|
796
|
+
piid: str | None
|
|
797
|
+
parent_piid: str | None
|
|
798
|
+
tas: str | None
|
|
799
|
+
reporting_agency_id: str | None
|
|
800
|
+
transaction_obligated_amount: float | str | None
|
|
801
|
+
file_c_source: str | None
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
class BudgetAccountAnomalySource(TypedDict, total=False):
|
|
805
|
+
"""Where a budget-account source anomaly was found.
|
|
806
|
+
|
|
807
|
+
Every key is optional and any value may be ``None``.
|
|
808
|
+
"""
|
|
809
|
+
|
|
810
|
+
dataset: str | None
|
|
811
|
+
fiscal_year: int | None
|
|
812
|
+
rows: list[BudgetAccountAnomalySourceRow] | None
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
class BudgetAccountSourceAnomaly(TypedDict, total=False):
|
|
816
|
+
"""One problem found in the source data behind a budget account.
|
|
817
|
+
|
|
818
|
+
An element of ``BudgetAccount.source_anomalies``. Every key is optional and
|
|
819
|
+
any value may be ``None``, so read keys with ``.get()``. ``code`` and
|
|
820
|
+
``action`` are open strings: today ``code`` is one of
|
|
821
|
+
``contract_exceeds_obligations``, ``assistance_exceeds_obligations`` or
|
|
822
|
+
``contract_without_obligations``, and ``action`` is ``capped`` or
|
|
823
|
+
``flagged``, but new values may appear.
|
|
824
|
+
"""
|
|
825
|
+
|
|
826
|
+
code: str | None
|
|
827
|
+
field: str | None
|
|
828
|
+
bound_field: str | None
|
|
829
|
+
action: str | None
|
|
830
|
+
reported_value: float | str | None
|
|
831
|
+
served_value: float | str | None
|
|
832
|
+
likely_cause: str | None
|
|
833
|
+
affected_fields: list[str] | None
|
|
834
|
+
message: str | None
|
|
835
|
+
source: BudgetAccountAnomalySource | None
|
|
836
|
+
|
|
837
|
+
|
|
789
838
|
@dataclass
|
|
790
839
|
class BudgetAccount:
|
|
791
840
|
"""Schema definition for BudgetAccount (not used for instances).
|
|
@@ -805,6 +854,8 @@ class BudgetAccount:
|
|
|
805
854
|
bea_category: str | None = None
|
|
806
855
|
on_off_budget: str | None = None
|
|
807
856
|
subfunction_code: str | None = None
|
|
857
|
+
# ``budgetary`` or ``credit_financing`` today; treat as an open string.
|
|
858
|
+
account_category: str | None = None
|
|
808
859
|
# Lifecycle
|
|
809
860
|
requested_ba: Decimal | None = None
|
|
810
861
|
enacted_ba: Decimal | None = None
|
|
@@ -828,6 +879,8 @@ class BudgetAccount:
|
|
|
828
879
|
assistance_share_of_obligated: Decimal | None = None
|
|
829
880
|
assistance_share_of_obligated_capped: Decimal | None = None
|
|
830
881
|
assistance_share_capped_flag: bool | None = None
|
|
882
|
+
# Problems found in the source data; ``[]`` when there are none.
|
|
883
|
+
source_anomalies: list[BudgetAccountSourceAnomaly] | None = None
|
|
831
884
|
# Forward-look
|
|
832
885
|
next_year_requested_ba: Decimal | None = None
|
|
833
886
|
ba_growth_next_year: Decimal | None = None
|
|
@@ -1728,12 +1781,12 @@ class ShapeConfig:
|
|
|
1728
1781
|
# Mirrors the API's BUDGET_ACCOUNT_DEFAULT_SHAPE.
|
|
1729
1782
|
BUDGET_ACCOUNTS_MINIMAL: Final = (
|
|
1730
1783
|
"id,federal_account_symbol,fiscal_year,agency_code,agency_name,bureau_name,"
|
|
1731
|
-
"account_title,bea_category,on_off_budget,subfunction_code,"
|
|
1784
|
+
"account_title,bea_category,on_off_budget,subfunction_code,account_category,"
|
|
1732
1785
|
"requested_ba,enacted_ba,apportioned,obligated_total,outlayed_total,"
|
|
1733
1786
|
"unobligated_balance,contract_obligated,contract_share_of_obligated_capped,"
|
|
1734
1787
|
"assistance_obligated,obligated_to_apportioned_pct_capped,"
|
|
1735
1788
|
"obligated_to_enacted_pct_capped,outlayed_to_obligated_pct_capped,"
|
|
1736
|
-
"ba_growth_next_year_pct"
|
|
1789
|
+
"ba_growth_next_year_pct,source_anomalies"
|
|
1737
1790
|
)
|
|
1738
1791
|
|
|
1739
1792
|
# Default for list_organizations()
|
|
@@ -1225,6 +1225,9 @@ GENERATED_OVERLAY: dict[str, dict[str, FieldSchema]] = {
|
|
|
1225
1225
|
),
|
|
1226
1226
|
},
|
|
1227
1227
|
"BudgetAccount": {
|
|
1228
|
+
"account_category": FieldSchema(
|
|
1229
|
+
name="account_category", type=str, is_optional=True, is_list=False
|
|
1230
|
+
),
|
|
1228
1231
|
"account_narrative_excerpt": FieldSchema(
|
|
1229
1232
|
name="account_narrative_excerpt", type=str, is_optional=True, is_list=False
|
|
1230
1233
|
),
|
|
@@ -1410,6 +1413,9 @@ GENERATED_OVERLAY: dict[str, dict[str, FieldSchema]] = {
|
|
|
1410
1413
|
"requested_personnel_share": FieldSchema(
|
|
1411
1414
|
name="requested_personnel_share", type=str, is_optional=True, is_list=False
|
|
1412
1415
|
),
|
|
1416
|
+
"source_anomalies": FieldSchema(
|
|
1417
|
+
name="source_anomalies", type=dict, is_optional=True, is_list=True
|
|
1418
|
+
),
|
|
1413
1419
|
"subfunction_code": FieldSchema(
|
|
1414
1420
|
name="subfunction_code", type=str, is_optional=True, is_list=False
|
|
1415
1421
|
),
|
|
@@ -271,6 +271,34 @@ class TestTangoClient:
|
|
|
271
271
|
assert otas.results[0]["key"] == "OTA-1"
|
|
272
272
|
assert otas.cursor == "next-page-token"
|
|
273
273
|
|
|
274
|
+
@pytest.mark.parametrize(
|
|
275
|
+
("method", "args"),
|
|
276
|
+
[
|
|
277
|
+
("list_idvs", ()),
|
|
278
|
+
("list_idv_awards", ("IDV-1",)),
|
|
279
|
+
("list_idv_child_idvs", ("IDV-1",)),
|
|
280
|
+
("list_idv_transactions", ("IDV-1",)),
|
|
281
|
+
],
|
|
282
|
+
)
|
|
283
|
+
@patch("tango.client.httpx.Client.request")
|
|
284
|
+
def test_idv_list_methods_return_cursor(self, mock_request, method, args):
|
|
285
|
+
mock_response = Mock()
|
|
286
|
+
mock_response.is_success = True
|
|
287
|
+
mock_response.json.return_value = {
|
|
288
|
+
"count": 250,
|
|
289
|
+
"next": "https://tango.makegov.com/api/idvs/?cursor=next-page-token",
|
|
290
|
+
"previous": None,
|
|
291
|
+
"results": [{"key": "IDV-1"}],
|
|
292
|
+
"cursor": "next-page-token",
|
|
293
|
+
}
|
|
294
|
+
mock_response.content = b'{"count": 250}'
|
|
295
|
+
mock_request.return_value = mock_response
|
|
296
|
+
|
|
297
|
+
client = TangoClient(api_key="test-key")
|
|
298
|
+
page = getattr(client, method)(*args, limit=1)
|
|
299
|
+
|
|
300
|
+
assert page.cursor == "next-page-token"
|
|
301
|
+
|
|
274
302
|
@patch("tango.client.httpx.Client.request")
|
|
275
303
|
def test_list_otidvs_with_default_shape(self, mock_request):
|
|
276
304
|
"""Test list_otidvs uses default minimal shape"""
|
|
@@ -573,6 +601,113 @@ class TestTangoClient:
|
|
|
573
601
|
]
|
|
574
602
|
assert leaked == [], f"unexpected filter keys sent: {leaked}"
|
|
575
603
|
|
|
604
|
+
@patch("tango.client.httpx.Client.request")
|
|
605
|
+
def test_list_budget_accounts_account_category_filters(self, mock_request):
|
|
606
|
+
mock_response = Mock()
|
|
607
|
+
mock_response.is_success = True
|
|
608
|
+
mock_response.json.return_value = {
|
|
609
|
+
"count": 0,
|
|
610
|
+
"next": None,
|
|
611
|
+
"previous": None,
|
|
612
|
+
"results": [],
|
|
613
|
+
}
|
|
614
|
+
mock_response.content = b'{"count": 0, "results": []}'
|
|
615
|
+
mock_request.return_value = mock_response
|
|
616
|
+
|
|
617
|
+
client = TangoClient(api_key="test-key")
|
|
618
|
+
client.list_budget_accounts(
|
|
619
|
+
account_category="credit_financing",
|
|
620
|
+
account_category_in="budgetary,credit_financing",
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
params = mock_request.call_args[1]["params"]
|
|
624
|
+
assert params["account_category"] == "credit_financing"
|
|
625
|
+
assert params["account_category__in"] == "budgetary,credit_financing"
|
|
626
|
+
|
|
627
|
+
@patch("tango.client.httpx.Client.request")
|
|
628
|
+
def test_list_budget_accounts_default_shape_parses_source_anomalies(self, mock_request):
|
|
629
|
+
anomaly = {
|
|
630
|
+
"code": "contract_exceeds_obligations",
|
|
631
|
+
"field": "contract_obligated",
|
|
632
|
+
"bound_field": "obligated_total",
|
|
633
|
+
"action": "capped",
|
|
634
|
+
"reported_value": 1250.0,
|
|
635
|
+
"served_value": 1000.0,
|
|
636
|
+
"likely_cause": None,
|
|
637
|
+
"affected_fields": ["contract_obligated", "contract_share_of_obligated"],
|
|
638
|
+
"message": "Contract obligations exceed total obligations.",
|
|
639
|
+
"source": {
|
|
640
|
+
"dataset": "file_c",
|
|
641
|
+
"fiscal_year": 2025,
|
|
642
|
+
"rows": [
|
|
643
|
+
{
|
|
644
|
+
"fiscal_period": 12,
|
|
645
|
+
"piid": "ABC123",
|
|
646
|
+
"parent_piid": None,
|
|
647
|
+
"tas": "012-1234",
|
|
648
|
+
"reporting_agency_id": "012",
|
|
649
|
+
"transaction_obligated_amount": 1250.0,
|
|
650
|
+
"file_c_source": "award",
|
|
651
|
+
}
|
|
652
|
+
],
|
|
653
|
+
},
|
|
654
|
+
}
|
|
655
|
+
mock_response = Mock()
|
|
656
|
+
mock_response.is_success = True
|
|
657
|
+
mock_response.json.return_value = {
|
|
658
|
+
"count": 2,
|
|
659
|
+
"next": None,
|
|
660
|
+
"previous": None,
|
|
661
|
+
"results": [
|
|
662
|
+
{
|
|
663
|
+
"id": 1,
|
|
664
|
+
"fiscal_year": 2025,
|
|
665
|
+
"account_category": "budgetary",
|
|
666
|
+
"source_anomalies": [anomaly],
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
"id": 2,
|
|
670
|
+
"fiscal_year": 2025,
|
|
671
|
+
"account_category": "credit_financing",
|
|
672
|
+
"enacted_ba": None,
|
|
673
|
+
"source_anomalies": [],
|
|
674
|
+
},
|
|
675
|
+
],
|
|
676
|
+
}
|
|
677
|
+
mock_response.content = b"{}"
|
|
678
|
+
mock_request.return_value = mock_response
|
|
679
|
+
|
|
680
|
+
client = TangoClient(api_key="test-key")
|
|
681
|
+
page = client.list_budget_accounts()
|
|
682
|
+
|
|
683
|
+
shape_fields = mock_request.call_args[1]["params"]["shape"].split(",")
|
|
684
|
+
assert "account_category" in shape_fields
|
|
685
|
+
assert "source_anomalies" in shape_fields
|
|
686
|
+
first, second = page.results
|
|
687
|
+
assert first["account_category"] == "budgetary"
|
|
688
|
+
assert first["source_anomalies"] == [anomaly]
|
|
689
|
+
assert first["source_anomalies"][0]["source"]["rows"][0]["piid"] == "ABC123"
|
|
690
|
+
assert second["account_category"] == "credit_financing"
|
|
691
|
+
assert second["source_anomalies"] == []
|
|
692
|
+
|
|
693
|
+
@patch("tango.client.httpx.Client.request")
|
|
694
|
+
def test_get_budget_account_accepts_explicit_anomaly_shape(self, mock_request):
|
|
695
|
+
mock_response = Mock()
|
|
696
|
+
mock_response.is_success = True
|
|
697
|
+
mock_response.json.return_value = {
|
|
698
|
+
"id": 7,
|
|
699
|
+
"account_category": "budgetary",
|
|
700
|
+
"source_anomalies": [{"code": "some_future_code"}],
|
|
701
|
+
}
|
|
702
|
+
mock_response.content = b"{}"
|
|
703
|
+
mock_request.return_value = mock_response
|
|
704
|
+
|
|
705
|
+
client = TangoClient(api_key="test-key")
|
|
706
|
+
account = client.get_budget_account(7, shape="id,account_category,source_anomalies")
|
|
707
|
+
|
|
708
|
+
assert account["source_anomalies"] == [{"code": "some_future_code"}]
|
|
709
|
+
assert account["account_category"] == "budgetary"
|
|
710
|
+
|
|
576
711
|
|
|
577
712
|
class TestShapeConfig:
|
|
578
713
|
"""Test ShapeConfig class"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tango_python-1.11.0 → tango_python-1.12.0}/tests/cassettes/TestAgenciesIntegration.test_get_agency
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|