tango-python 1.1.3__tar.gz → 1.2.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.1.3 → tango_python-1.2.0}/CHANGELOG.md +20 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/PKG-INFO +1 -1
- {tango_python-1.1.3 → tango_python-1.2.0}/pyproject.toml +1 -1
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/__init__.py +1 -1
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/client.py +260 -3
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/test_client.py +68 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/.github/workflows/docs-dispatch.yml +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/.github/workflows/lint.yml +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/.github/workflows/publish.yml +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/.github/workflows/test.yml +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/.gitignore +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/LICENSE +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/README.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/docs/API_REFERENCE.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/docs/CLIENT.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/docs/DYNAMIC_MODELS.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/docs/ERRORS.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/docs/PAGINATION.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/docs/SHAPES.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/docs/WEBHOOKS.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/scripts/README.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/scripts/check_filter_shape_conformance.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/scripts/fetch_api_schema.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/scripts/generate_schemas_from_api.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/scripts/pr_review.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/scripts/smoke_api_parity.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/scripts/test_production.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/exceptions.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/models.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/shapes/__init__.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/shapes/explicit_schemas.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/shapes/factory.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/shapes/generator.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/shapes/models.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/shapes/parser.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/shapes/schema.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/shapes/types.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/webhooks/__init__.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/webhooks/cli.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/webhooks/receiver.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/webhooks/signing.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tango/webhooks/simulate.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/__init__.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestAgenciesIntegration.test_get_agency +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestAgenciesIntegration.test_list_agencies +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_field_type_validation +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_parsing_consistency +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestBusinessTypesIntegration.test_list_business_types +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_combined_filters_work_together +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_contract_cursor_pagination +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_contract_data_object_parsing +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_contract_field_types +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[keyword-software] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[psc_code-R425] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_awarding_agency_filter +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_date_range_filter +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_flat +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_naics_code_filter +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[default-None] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_new_expiring_filters +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_new_fiscal_year_range_filters +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_new_identifier_filters +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_search_contracts_with_filters +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_search_filters_object_with_new_parameters +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[asc-] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[desc--] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_contracts +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_entities +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_date_field_parsing_edge_cases +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_decimal_field_parsing_edge_cases +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_empty_list_responses +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_entity_parsing_with_various_address_formats +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_flattened_responses_with_flat_lists +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_list_field_parsing_consistency +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_nested_objects_with_missing_data +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_null_missing_fields_in_contracts +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_with_minimal_shape_sparse_data +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_entity_field_types +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_entity_location_parsing +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_entity_parsing_with_business_types +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_entity_with_various_identifiers +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_budget_flows +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_by_uei +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_flat +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_search +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[custom-uei,legal_business_name,cage_code] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestForecastsIntegration.test_forecast_field_types +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[custom-id,title,anticipated_award_date] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[default-None] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestGrantsIntegration.test_grant_field_types +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestGrantsIntegration.test_grant_pagination +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[custom-grant_id,title,opportunity_number] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[default-None] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[minimal-grant_id,opportunity_number,title,status(-),agency_code] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestIDVsIntegration.test_get_idv_uses_default_shape +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_awards_uses_default_shape +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_child_idvs_uses_default_shape +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_transactions +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestIDVsIntegration.test_list_idvs_uses_default_shape_and_keyset_params +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestNaicsIntegration.test_list_naics +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[custom-notice_id,title,solicitation_number] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[default-None] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestNoticesIntegration.test_notice_field_types +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestNoticesIntegration.test_notice_pagination +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestNoticesIntegration.test_notice_with_meta_fields +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOTAsIntegration.test_get_ota +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOTAsIntegration.test_list_otas +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOTIDVsIntegration.test_get_otidv +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOTIDVsIntegration.test_list_otidvs +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOfficesIntegration.test_get_office +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOfficesIntegration.test_list_offices +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[custom-opportunity_id,title,solicitation_number] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[default-None] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOpportunitiesIntegration.test_opportunity_field_types +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOrganizationsIntegration.test_get_organization +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestOrganizationsIntegration.test_list_organizations +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestProtestsIntegration.test_get_protest_by_case_id +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_filter +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[custom-case_id,title,source_system,outcome] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[default-None] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestProtestsIntegration.test_protest_pagination +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestSubawardsIntegration.test_list_subawards +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[custom-key,piid,description] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[ultra_minimal-key,piid,recipient(display_name),total_contract_value] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestTypeHintsIntegration.test_notices_dict_access[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.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.1.3 → tango_python-1.2.0}/tests/cassettes/TestTypeHintsIntegration.test_opportunities_dict_access[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_with_metrics_expansion +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_orders_uses_default_shape +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_with_ordering +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/conftest.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/README.md +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/__init__.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/conftest.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_agencies_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_contracts_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_edge_cases_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_entities_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_forecasts_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_grants_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_itdashboard_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_naics_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_notices_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_offices_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_opportunities_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_organizations_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_otas_otidvs_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_protests_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_reference_data_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_subawards_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/test_vehicles_idvs_integration.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/integration/validation.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/production/__init__.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/production/conftest.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/production/test_production_smoke.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/test_api_parity.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/test_models.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/test_shapes.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/test_webhooks_cli.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/test_webhooks_receiver.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/test_webhooks_signing.py +0 -0
- {tango_python-1.1.3 → tango_python-1.2.0}/tests/test_webhooks_simulate.py +0 -0
|
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.0] - 2026-06-05
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `list_budget_accounts()` now exposes the full range-filter surface that the
|
|
14
|
+
REST endpoint has always supported. Every numeric metric on
|
|
15
|
+
`/api/budget/accounts/` — the 26 fields in the backend's
|
|
16
|
+
`RANGE_NUMERIC_FIELDS` list (`enacted_ba`, `apportioned`, `obligated_total`,
|
|
17
|
+
`unobligated_balance`, `contract_obligated`,
|
|
18
|
+
`contract_share_of_obligated_capped`, `ba_growth_next_year_pct`,
|
|
19
|
+
`actual_vs_requested_contract`, all the ratio fields and their `_capped`
|
|
20
|
+
variants, etc.) — is now accepted in three forms: exact match (`field=`),
|
|
21
|
+
greater-or-equal (`field_gte=`), and less-or-equal (`field_lte=`).
|
|
22
|
+
Previously only the identity / taxonomy filters were exposed, which forced
|
|
23
|
+
callers to discover accounts by exact symbol lookup; the new surface makes
|
|
24
|
+
pipeline-style queries (e.g. "all FY24 accounts where contract share ≥ 60%,
|
|
25
|
+
unobligated balance ≥ $200M, and next-year growth ≥ 15%, sorted by largest
|
|
26
|
+
headroom first") a single SDK call. The new params map to the API's
|
|
27
|
+
`field__gte` / `field__lte` form; `ordering=` already accepted any of these
|
|
28
|
+
fields and continues to.
|
|
29
|
+
|
|
10
30
|
## [1.1.3] - 2026-06-04
|
|
11
31
|
|
|
12
32
|
### Added
|
|
@@ -2649,6 +2649,85 @@ class TangoClient:
|
|
|
2649
2649
|
bea_category: str | None = None,
|
|
2650
2650
|
on_off_budget: str | None = None,
|
|
2651
2651
|
subfunction_code: str | None = None,
|
|
2652
|
+
# Range-numeric filters: each field also accepts ``__gte`` / ``__lte``.
|
|
2653
|
+
requested_ba: float | None = None,
|
|
2654
|
+
requested_ba_gte: float | None = None,
|
|
2655
|
+
requested_ba_lte: float | None = None,
|
|
2656
|
+
enacted_ba: float | None = None,
|
|
2657
|
+
enacted_ba_gte: float | None = None,
|
|
2658
|
+
enacted_ba_lte: float | None = None,
|
|
2659
|
+
apportioned: float | None = None,
|
|
2660
|
+
apportioned_gte: float | None = None,
|
|
2661
|
+
apportioned_lte: float | None = None,
|
|
2662
|
+
obligated_total: float | None = None,
|
|
2663
|
+
obligated_total_gte: float | None = None,
|
|
2664
|
+
obligated_total_lte: float | None = None,
|
|
2665
|
+
outlayed_total: float | None = None,
|
|
2666
|
+
outlayed_total_gte: float | None = None,
|
|
2667
|
+
outlayed_total_lte: float | None = None,
|
|
2668
|
+
unobligated_balance: float | None = None,
|
|
2669
|
+
unobligated_balance_gte: float | None = None,
|
|
2670
|
+
unobligated_balance_lte: float | None = None,
|
|
2671
|
+
contract_obligated: float | None = None,
|
|
2672
|
+
contract_obligated_gte: float | None = None,
|
|
2673
|
+
contract_obligated_lte: float | None = None,
|
|
2674
|
+
contract_outlayed: float | None = None,
|
|
2675
|
+
contract_outlayed_gte: float | None = None,
|
|
2676
|
+
contract_outlayed_lte: float | None = None,
|
|
2677
|
+
assistance_obligated: float | None = None,
|
|
2678
|
+
assistance_obligated_gte: float | None = None,
|
|
2679
|
+
assistance_obligated_lte: float | None = None,
|
|
2680
|
+
assistance_outlayed: float | None = None,
|
|
2681
|
+
assistance_outlayed_gte: float | None = None,
|
|
2682
|
+
assistance_outlayed_lte: float | None = None,
|
|
2683
|
+
contract_share_of_obligated_capped: float | None = None,
|
|
2684
|
+
contract_share_of_obligated_capped_gte: float | None = None,
|
|
2685
|
+
contract_share_of_obligated_capped_lte: float | None = None,
|
|
2686
|
+
obligated_to_apportioned_pct: float | None = None,
|
|
2687
|
+
obligated_to_apportioned_pct_gte: float | None = None,
|
|
2688
|
+
obligated_to_apportioned_pct_lte: float | None = None,
|
|
2689
|
+
obligated_to_apportioned_pct_capped: float | None = None,
|
|
2690
|
+
obligated_to_apportioned_pct_capped_gte: float | None = None,
|
|
2691
|
+
obligated_to_apportioned_pct_capped_lte: float | None = None,
|
|
2692
|
+
apportioned_to_enacted_pct: float | None = None,
|
|
2693
|
+
apportioned_to_enacted_pct_gte: float | None = None,
|
|
2694
|
+
apportioned_to_enacted_pct_lte: float | None = None,
|
|
2695
|
+
apportioned_to_enacted_pct_capped: float | None = None,
|
|
2696
|
+
apportioned_to_enacted_pct_capped_gte: float | None = None,
|
|
2697
|
+
apportioned_to_enacted_pct_capped_lte: float | None = None,
|
|
2698
|
+
obligated_to_enacted_pct: float | None = None,
|
|
2699
|
+
obligated_to_enacted_pct_gte: float | None = None,
|
|
2700
|
+
obligated_to_enacted_pct_lte: float | None = None,
|
|
2701
|
+
obligated_to_enacted_pct_capped: float | None = None,
|
|
2702
|
+
obligated_to_enacted_pct_capped_gte: float | None = None,
|
|
2703
|
+
obligated_to_enacted_pct_capped_lte: float | None = None,
|
|
2704
|
+
outlayed_to_obligated_pct: float | None = None,
|
|
2705
|
+
outlayed_to_obligated_pct_gte: float | None = None,
|
|
2706
|
+
outlayed_to_obligated_pct_lte: float | None = None,
|
|
2707
|
+
outlayed_to_obligated_pct_capped: float | None = None,
|
|
2708
|
+
outlayed_to_obligated_pct_capped_gte: float | None = None,
|
|
2709
|
+
outlayed_to_obligated_pct_capped_lte: float | None = None,
|
|
2710
|
+
unobligated_pct: float | None = None,
|
|
2711
|
+
unobligated_pct_gte: float | None = None,
|
|
2712
|
+
unobligated_pct_lte: float | None = None,
|
|
2713
|
+
enacted_ba_yoy_pct: float | None = None,
|
|
2714
|
+
enacted_ba_yoy_pct_gte: float | None = None,
|
|
2715
|
+
enacted_ba_yoy_pct_lte: float | None = None,
|
|
2716
|
+
obligated_yoy_pct: float | None = None,
|
|
2717
|
+
obligated_yoy_pct_gte: float | None = None,
|
|
2718
|
+
obligated_yoy_pct_lte: float | None = None,
|
|
2719
|
+
enacted_ba_5yr_cagr: float | None = None,
|
|
2720
|
+
enacted_ba_5yr_cagr_gte: float | None = None,
|
|
2721
|
+
enacted_ba_5yr_cagr_lte: float | None = None,
|
|
2722
|
+
ba_growth_next_year_pct: float | None = None,
|
|
2723
|
+
ba_growth_next_year_pct_gte: float | None = None,
|
|
2724
|
+
ba_growth_next_year_pct_lte: float | None = None,
|
|
2725
|
+
actual_vs_requested_contract: float | None = None,
|
|
2726
|
+
actual_vs_requested_contract_gte: float | None = None,
|
|
2727
|
+
actual_vs_requested_contract_lte: float | None = None,
|
|
2728
|
+
actual_vs_requested_contract_capped: float | None = None,
|
|
2729
|
+
actual_vs_requested_contract_capped_gte: float | None = None,
|
|
2730
|
+
actual_vs_requested_contract_capped_lte: float | None = None,
|
|
2652
2731
|
search: str | None = None,
|
|
2653
2732
|
ordering: str | None = None,
|
|
2654
2733
|
) -> PaginatedResponse:
|
|
@@ -2674,8 +2753,49 @@ class TangoClient:
|
|
|
2674
2753
|
bea_category: BEA category (exact).
|
|
2675
2754
|
on_off_budget: On/off budget flag (exact).
|
|
2676
2755
|
subfunction_code: Subfunction code (exact).
|
|
2756
|
+
requested_ba: President's-budget requested BA (exact). Also
|
|
2757
|
+
``requested_ba_gte`` / ``requested_ba_lte`` for range queries.
|
|
2758
|
+
enacted_ba: Enacted budget authority (exact / gte / lte).
|
|
2759
|
+
apportioned: Apportioned amount (exact / gte / lte).
|
|
2760
|
+
obligated_total: Total obligated (exact / gte / lte).
|
|
2761
|
+
outlayed_total: Total outlayed (exact / gte / lte).
|
|
2762
|
+
unobligated_balance: Apportioned minus obligated, in dollars
|
|
2763
|
+
(exact / gte / lte). Use ``__gte`` to surface accounts with
|
|
2764
|
+
appropriated headroom that hasn't yet hit contract.
|
|
2765
|
+
contract_obligated: Contract-only obligated (exact / gte / lte).
|
|
2766
|
+
contract_outlayed: Contract-only outlayed (exact / gte / lte).
|
|
2767
|
+
assistance_obligated: Assistance-only obligated (exact / gte / lte).
|
|
2768
|
+
assistance_outlayed: Assistance-only outlayed (exact / gte / lte).
|
|
2769
|
+
contract_share_of_obligated_capped: Contracts as share of
|
|
2770
|
+
obligated, capped at 1.0 (exact / gte / lte). Use ``__gte`` to
|
|
2771
|
+
filter to contract-heavy accounts.
|
|
2772
|
+
obligated_to_apportioned_pct: Burn ratio
|
|
2773
|
+
(obligated / apportioned). Also ``_capped`` variant capped at
|
|
2774
|
+
1.0. Both expose exact / gte / lte.
|
|
2775
|
+
apportioned_to_enacted_pct: Apportionment ratio
|
|
2776
|
+
(apportioned / enacted). Also ``_capped`` variant. Exact / gte / lte.
|
|
2777
|
+
obligated_to_enacted_pct: Obligated-to-enacted ratio. Also
|
|
2778
|
+
``_capped`` variant. Exact / gte / lte.
|
|
2779
|
+
outlayed_to_obligated_pct: Spendout ratio (outlayed / obligated).
|
|
2780
|
+
Also ``_capped`` variant. Exact / gte / lte.
|
|
2781
|
+
unobligated_pct: Unobligated share of apportioned (exact / gte / lte).
|
|
2782
|
+
enacted_ba_yoy_pct: Year-over-year enacted BA growth
|
|
2783
|
+
(exact / gte / lte).
|
|
2784
|
+
obligated_yoy_pct: Year-over-year obligated growth
|
|
2785
|
+
(exact / gte / lte).
|
|
2786
|
+
enacted_ba_5yr_cagr: 5-year compound annual growth of enacted BA
|
|
2787
|
+
(exact / gte / lte).
|
|
2788
|
+
ba_growth_next_year_pct: Next-year requested BA growth
|
|
2789
|
+
(exact / gte / lte). Use ``__gte`` for forward-looking
|
|
2790
|
+
pipeline discovery.
|
|
2791
|
+
actual_vs_requested_contract: Realization ratio of contract
|
|
2792
|
+
obligated against the prior-year request (exact / gte / lte).
|
|
2793
|
+
Also ``_capped`` variant.
|
|
2677
2794
|
search: Full-text search over account_title/agency_name/bureau_name.
|
|
2678
|
-
ordering: Sort field (prefix with '-' for descending).
|
|
2795
|
+
ordering: Sort field (prefix with '-' for descending). Any of the
|
|
2796
|
+
numeric fields above is a valid ordering target — e.g.
|
|
2797
|
+
``ordering="-unobligated_balance"`` to rank by largest
|
|
2798
|
+
headroom first.
|
|
2679
2799
|
"""
|
|
2680
2800
|
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
2681
2801
|
if shape is None:
|
|
@@ -2686,7 +2806,7 @@ class TangoClient:
|
|
|
2686
2806
|
params["flat"] = "true"
|
|
2687
2807
|
if flat_lists:
|
|
2688
2808
|
params["flat_lists"] = "true"
|
|
2689
|
-
|
|
2809
|
+
scalar_filters: tuple[tuple[str, Any], ...] = (
|
|
2690
2810
|
("federal_account_symbol", federal_account_symbol),
|
|
2691
2811
|
("fiscal_year", fiscal_year),
|
|
2692
2812
|
("fiscal_year__gte", fiscal_year_gte),
|
|
@@ -2699,9 +2819,146 @@ class TangoClient:
|
|
|
2699
2819
|
("subfunction_code", subfunction_code),
|
|
2700
2820
|
("search", search),
|
|
2701
2821
|
("ordering", ordering),
|
|
2702
|
-
)
|
|
2822
|
+
)
|
|
2823
|
+
for key, val in scalar_filters:
|
|
2703
2824
|
if val is not None:
|
|
2704
2825
|
params[key] = val
|
|
2826
|
+
# Range-numeric filters: each field has exact / __gte / __lte forms.
|
|
2827
|
+
range_filters: tuple[tuple[str, float | None, float | None, float | None], ...] = (
|
|
2828
|
+
("requested_ba", requested_ba, requested_ba_gte, requested_ba_lte),
|
|
2829
|
+
("enacted_ba", enacted_ba, enacted_ba_gte, enacted_ba_lte),
|
|
2830
|
+
("apportioned", apportioned, apportioned_gte, apportioned_lte),
|
|
2831
|
+
("obligated_total", obligated_total, obligated_total_gte, obligated_total_lte),
|
|
2832
|
+
("outlayed_total", outlayed_total, outlayed_total_gte, outlayed_total_lte),
|
|
2833
|
+
(
|
|
2834
|
+
"unobligated_balance",
|
|
2835
|
+
unobligated_balance,
|
|
2836
|
+
unobligated_balance_gte,
|
|
2837
|
+
unobligated_balance_lte,
|
|
2838
|
+
),
|
|
2839
|
+
(
|
|
2840
|
+
"contract_obligated",
|
|
2841
|
+
contract_obligated,
|
|
2842
|
+
contract_obligated_gte,
|
|
2843
|
+
contract_obligated_lte,
|
|
2844
|
+
),
|
|
2845
|
+
(
|
|
2846
|
+
"contract_outlayed",
|
|
2847
|
+
contract_outlayed,
|
|
2848
|
+
contract_outlayed_gte,
|
|
2849
|
+
contract_outlayed_lte,
|
|
2850
|
+
),
|
|
2851
|
+
(
|
|
2852
|
+
"assistance_obligated",
|
|
2853
|
+
assistance_obligated,
|
|
2854
|
+
assistance_obligated_gte,
|
|
2855
|
+
assistance_obligated_lte,
|
|
2856
|
+
),
|
|
2857
|
+
(
|
|
2858
|
+
"assistance_outlayed",
|
|
2859
|
+
assistance_outlayed,
|
|
2860
|
+
assistance_outlayed_gte,
|
|
2861
|
+
assistance_outlayed_lte,
|
|
2862
|
+
),
|
|
2863
|
+
(
|
|
2864
|
+
"contract_share_of_obligated_capped",
|
|
2865
|
+
contract_share_of_obligated_capped,
|
|
2866
|
+
contract_share_of_obligated_capped_gte,
|
|
2867
|
+
contract_share_of_obligated_capped_lte,
|
|
2868
|
+
),
|
|
2869
|
+
(
|
|
2870
|
+
"obligated_to_apportioned_pct",
|
|
2871
|
+
obligated_to_apportioned_pct,
|
|
2872
|
+
obligated_to_apportioned_pct_gte,
|
|
2873
|
+
obligated_to_apportioned_pct_lte,
|
|
2874
|
+
),
|
|
2875
|
+
(
|
|
2876
|
+
"obligated_to_apportioned_pct_capped",
|
|
2877
|
+
obligated_to_apportioned_pct_capped,
|
|
2878
|
+
obligated_to_apportioned_pct_capped_gte,
|
|
2879
|
+
obligated_to_apportioned_pct_capped_lte,
|
|
2880
|
+
),
|
|
2881
|
+
(
|
|
2882
|
+
"apportioned_to_enacted_pct",
|
|
2883
|
+
apportioned_to_enacted_pct,
|
|
2884
|
+
apportioned_to_enacted_pct_gte,
|
|
2885
|
+
apportioned_to_enacted_pct_lte,
|
|
2886
|
+
),
|
|
2887
|
+
(
|
|
2888
|
+
"apportioned_to_enacted_pct_capped",
|
|
2889
|
+
apportioned_to_enacted_pct_capped,
|
|
2890
|
+
apportioned_to_enacted_pct_capped_gte,
|
|
2891
|
+
apportioned_to_enacted_pct_capped_lte,
|
|
2892
|
+
),
|
|
2893
|
+
(
|
|
2894
|
+
"obligated_to_enacted_pct",
|
|
2895
|
+
obligated_to_enacted_pct,
|
|
2896
|
+
obligated_to_enacted_pct_gte,
|
|
2897
|
+
obligated_to_enacted_pct_lte,
|
|
2898
|
+
),
|
|
2899
|
+
(
|
|
2900
|
+
"obligated_to_enacted_pct_capped",
|
|
2901
|
+
obligated_to_enacted_pct_capped,
|
|
2902
|
+
obligated_to_enacted_pct_capped_gte,
|
|
2903
|
+
obligated_to_enacted_pct_capped_lte,
|
|
2904
|
+
),
|
|
2905
|
+
(
|
|
2906
|
+
"outlayed_to_obligated_pct",
|
|
2907
|
+
outlayed_to_obligated_pct,
|
|
2908
|
+
outlayed_to_obligated_pct_gte,
|
|
2909
|
+
outlayed_to_obligated_pct_lte,
|
|
2910
|
+
),
|
|
2911
|
+
(
|
|
2912
|
+
"outlayed_to_obligated_pct_capped",
|
|
2913
|
+
outlayed_to_obligated_pct_capped,
|
|
2914
|
+
outlayed_to_obligated_pct_capped_gte,
|
|
2915
|
+
outlayed_to_obligated_pct_capped_lte,
|
|
2916
|
+
),
|
|
2917
|
+
("unobligated_pct", unobligated_pct, unobligated_pct_gte, unobligated_pct_lte),
|
|
2918
|
+
(
|
|
2919
|
+
"enacted_ba_yoy_pct",
|
|
2920
|
+
enacted_ba_yoy_pct,
|
|
2921
|
+
enacted_ba_yoy_pct_gte,
|
|
2922
|
+
enacted_ba_yoy_pct_lte,
|
|
2923
|
+
),
|
|
2924
|
+
(
|
|
2925
|
+
"obligated_yoy_pct",
|
|
2926
|
+
obligated_yoy_pct,
|
|
2927
|
+
obligated_yoy_pct_gte,
|
|
2928
|
+
obligated_yoy_pct_lte,
|
|
2929
|
+
),
|
|
2930
|
+
(
|
|
2931
|
+
"enacted_ba_5yr_cagr",
|
|
2932
|
+
enacted_ba_5yr_cagr,
|
|
2933
|
+
enacted_ba_5yr_cagr_gte,
|
|
2934
|
+
enacted_ba_5yr_cagr_lte,
|
|
2935
|
+
),
|
|
2936
|
+
(
|
|
2937
|
+
"ba_growth_next_year_pct",
|
|
2938
|
+
ba_growth_next_year_pct,
|
|
2939
|
+
ba_growth_next_year_pct_gte,
|
|
2940
|
+
ba_growth_next_year_pct_lte,
|
|
2941
|
+
),
|
|
2942
|
+
(
|
|
2943
|
+
"actual_vs_requested_contract",
|
|
2944
|
+
actual_vs_requested_contract,
|
|
2945
|
+
actual_vs_requested_contract_gte,
|
|
2946
|
+
actual_vs_requested_contract_lte,
|
|
2947
|
+
),
|
|
2948
|
+
(
|
|
2949
|
+
"actual_vs_requested_contract_capped",
|
|
2950
|
+
actual_vs_requested_contract_capped,
|
|
2951
|
+
actual_vs_requested_contract_capped_gte,
|
|
2952
|
+
actual_vs_requested_contract_capped_lte,
|
|
2953
|
+
),
|
|
2954
|
+
)
|
|
2955
|
+
for field, exact, gte, lte in range_filters:
|
|
2956
|
+
if exact is not None:
|
|
2957
|
+
params[field] = exact
|
|
2958
|
+
if gte is not None:
|
|
2959
|
+
params[f"{field}__gte"] = gte
|
|
2960
|
+
if lte is not None:
|
|
2961
|
+
params[f"{field}__lte"] = lte
|
|
2705
2962
|
data = self._get("/api/budget/accounts/", params)
|
|
2706
2963
|
results = [
|
|
2707
2964
|
self._parse_response_with_shape(obj, shape, BudgetAccount, flat, flat_lists)
|
|
@@ -505,6 +505,74 @@ class TestTangoClient:
|
|
|
505
505
|
|
|
506
506
|
assert exc_info.value.status_code == 404
|
|
507
507
|
|
|
508
|
+
@patch("tango.client.httpx.Client.request")
|
|
509
|
+
def test_list_budget_accounts_range_filters(self, mock_request):
|
|
510
|
+
"""Range filters serialize to the API's ``field__gte`` / ``field__lte`` form."""
|
|
511
|
+
mock_response = Mock()
|
|
512
|
+
mock_response.is_success = True
|
|
513
|
+
mock_response.json.return_value = {
|
|
514
|
+
"count": 0,
|
|
515
|
+
"next": None,
|
|
516
|
+
"previous": None,
|
|
517
|
+
"results": [],
|
|
518
|
+
}
|
|
519
|
+
mock_response.content = b'{"count": 0, "results": []}'
|
|
520
|
+
mock_request.return_value = mock_response
|
|
521
|
+
|
|
522
|
+
client = TangoClient(api_key="test-key")
|
|
523
|
+
client.list_budget_accounts(
|
|
524
|
+
fiscal_year=2024,
|
|
525
|
+
contract_share_of_obligated_capped_gte=0.6,
|
|
526
|
+
ba_growth_next_year_pct_gte=0.15,
|
|
527
|
+
unobligated_balance_gte=200_000_000,
|
|
528
|
+
unobligated_balance_lte=10_000_000_000,
|
|
529
|
+
enacted_ba=3_135_000_000,
|
|
530
|
+
ordering="-unobligated_balance",
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
params = mock_request.call_args[1]["params"]
|
|
534
|
+
# Exact-match scalar filter still works.
|
|
535
|
+
assert params["fiscal_year"] == 2024
|
|
536
|
+
# Range filters use the API's double-underscore form.
|
|
537
|
+
assert params["contract_share_of_obligated_capped__gte"] == 0.6
|
|
538
|
+
assert params["ba_growth_next_year_pct__gte"] == 0.15
|
|
539
|
+
assert params["unobligated_balance__gte"] == 200_000_000
|
|
540
|
+
assert params["unobligated_balance__lte"] == 10_000_000_000
|
|
541
|
+
# Range fields also accept exact-match.
|
|
542
|
+
assert params["enacted_ba"] == 3_135_000_000
|
|
543
|
+
# Ordering passes through untouched (callers prefix with '-' for desc).
|
|
544
|
+
assert params["ordering"] == "-unobligated_balance"
|
|
545
|
+
# Unspecified filters are not sent.
|
|
546
|
+
assert "apportioned__gte" not in params
|
|
547
|
+
assert "obligated_yoy_pct__lte" not in params
|
|
548
|
+
|
|
549
|
+
@patch("tango.client.httpx.Client.request")
|
|
550
|
+
def test_list_budget_accounts_no_filters_sends_only_pagination_and_shape(self, mock_request):
|
|
551
|
+
"""With no filter args, the request carries only paging + default shape."""
|
|
552
|
+
mock_response = Mock()
|
|
553
|
+
mock_response.is_success = True
|
|
554
|
+
mock_response.json.return_value = {
|
|
555
|
+
"count": 0,
|
|
556
|
+
"next": None,
|
|
557
|
+
"previous": None,
|
|
558
|
+
"results": [],
|
|
559
|
+
}
|
|
560
|
+
mock_response.content = b'{"count": 0, "results": []}'
|
|
561
|
+
mock_request.return_value = mock_response
|
|
562
|
+
|
|
563
|
+
client = TangoClient(api_key="test-key")
|
|
564
|
+
client.list_budget_accounts()
|
|
565
|
+
|
|
566
|
+
params = mock_request.call_args[1]["params"]
|
|
567
|
+
assert params["page"] == 1
|
|
568
|
+
assert params["limit"] == 25
|
|
569
|
+
assert "shape" in params
|
|
570
|
+
# None of the new range filters leak through as null.
|
|
571
|
+
leaked = [
|
|
572
|
+
k for k in params if k.endswith("__gte") or k.endswith("__lte") or k == "fiscal_year"
|
|
573
|
+
]
|
|
574
|
+
assert leaked == [], f"unexpected filter keys sent: {leaked}"
|
|
575
|
+
|
|
508
576
|
|
|
509
577
|
class TestShapeConfig:
|
|
510
578
|
"""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
|
|
File without changes
|
|
File without changes
|
{tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestAgenciesIntegration.test_get_agency
RENAMED
|
File without changes
|
{tango_python-1.1.3 → tango_python-1.2.0}/tests/cassettes/TestAgenciesIntegration.test_list_agencies
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|