tango-python 1.16.0__tar.gz → 1.18.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.16.0 → tango_python-1.18.0}/CHANGELOG.md +22 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/PKG-INFO +1 -1
- {tango_python-1.16.0 → tango_python-1.18.0}/docs/API_REFERENCE.md +22 -2
- {tango_python-1.16.0 → tango_python-1.18.0}/pyproject.toml +1 -1
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/__init__.py +1 -1
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/client.py +8 -1
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/models.py +11 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/explicit_schemas.py +35 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/generated_overlay.py +18 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_client.py +27 -0
- tango_python-1.18.0/tests/test_obligations_by_fiscal_year.py +88 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/.gitignore +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/LICENSE +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/README.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/docs/CLIENT.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/docs/DYNAMIC_MODELS.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/docs/ERRORS.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/docs/PAGINATION.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/docs/SHAPES.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/docs/WEBHOOKS.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/README.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/check_filter_shape_conformance.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/check_shape_coverage.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/fetch_api_schema.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/generate_schemas_from_api.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/generate_shape_overlay.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/pr_review.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/probe_shape_types.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/refresh_contract.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/smoke_api_parity.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/scripts/test_production.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/exceptions.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/__init__.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/factory.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/generator.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/models.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/parser.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/schema.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/shapes/types.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/webhooks/__init__.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/webhooks/cli.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/webhooks/receiver.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/webhooks/signing.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tango/webhooks/simulate.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/__init__.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestAgenciesIntegration.test_get_agency +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestAgenciesIntegration.test_list_agencies +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_field_type_validation +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_parsing_consistency +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestBusinessTypesIntegration.test_list_business_types +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_combined_filters_work_together +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_contract_cursor_pagination +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_contract_data_object_parsing +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_contract_field_types +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[keyword-software] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[psc_code-R425] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_awarding_agency_filter +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_date_range_filter +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_flat +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_naics_code_filter +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[default-None] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_new_expiring_filters +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_new_fiscal_year_range_filters +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_new_identifier_filters +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_search_contracts_with_filters +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_search_filters_object_with_new_parameters +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[asc-] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[desc--] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_contracts +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_entities +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_date_field_parsing_edge_cases +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_decimal_field_parsing_edge_cases +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_empty_list_responses +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_entity_parsing_with_various_address_formats +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_flattened_responses_with_flat_lists +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_list_field_parsing_consistency +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_nested_objects_with_missing_data +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_null_missing_fields_in_contracts +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_with_minimal_shape_sparse_data +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_entity_field_types +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_entity_location_parsing +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_entity_parsing_with_business_types +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_entity_with_various_identifiers +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_budget_flows +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_by_uei +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_flat +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_search +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[custom-uei,legal_business_name,cage_code] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestForecastsIntegration.test_forecast_field_types +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[custom-id,title,anticipated_award_date] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[default-None] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestGrantsIntegration.test_grant_field_types +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestGrantsIntegration.test_grant_pagination +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[custom-grant_id,title,opportunity_number] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[default-None] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[minimal-grant_id,opportunity_number,title,status(-),agency_code] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestIDVsIntegration.test_get_idv_uses_default_shape +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_awards_uses_default_shape +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_child_idvs_uses_default_shape +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_transactions +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestIDVsIntegration.test_list_idvs_uses_default_shape_and_keyset_params +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestNaicsIntegration.test_list_naics +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[custom-notice_id,title,solicitation_number] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[default-None] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestNoticesIntegration.test_notice_field_types +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestNoticesIntegration.test_notice_pagination +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestNoticesIntegration.test_notice_with_meta_fields +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOTAsIntegration.test_get_ota +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOTAsIntegration.test_list_otas +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOTIDVsIntegration.test_get_otidv +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOTIDVsIntegration.test_list_otidvs +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOfficesIntegration.test_get_office +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOfficesIntegration.test_list_offices +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[custom-opportunity_id,title,solicitation_number] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[default-None] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOpportunitiesIntegration.test_opportunity_field_types +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOrganizationsIntegration.test_get_organization +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestOrganizationsIntegration.test_list_organizations +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestProtestsIntegration.test_get_protest_by_case_id +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_filter +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[custom-case_id,title,source_system,outcome] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[default-None] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestProtestsIntegration.test_protest_pagination +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestSubawardsIntegration.test_list_subawards +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[custom-key,piid,description] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[ultra_minimal-key,piid,recipient(display_name),total_contract_value] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestTypeHintsIntegration.test_notices_dict_access[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.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.16.0 → tango_python-1.18.0}/tests/cassettes/TestTypeHintsIntegration.test_opportunities_dict_access[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_with_metrics_expansion +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_orders_uses_default_shape +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_with_ordering +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/conftest.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/README.md +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/__init__.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/conftest.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_agencies_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_contracts_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_edge_cases_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_entities_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_forecasts_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_grants_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_itdashboard_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_naics_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_notices_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_offices_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_opportunities_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_organizations_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_otas_otidvs_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_protests_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_reference_data_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_subawards_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/test_vehicles_idvs_integration.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/integration/validation.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/production/__init__.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/production/conftest.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/production/test_production_smoke.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_api_parity.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_contract_appeals.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_dibbs_exclusions_sbir.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_ebuy.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_federal_register.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_models.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_opportunity_attachments.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_opportunity_awards.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_organization_scope.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_shape_coverage_gate.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_shapes.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_sled.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_webhooks_cli.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_webhooks_receiver.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_webhooks_signing.py +0 -0
- {tango_python-1.16.0 → tango_python-1.18.0}/tests/test_webhooks_simulate.py +0 -0
|
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.18.0] - 2026-10-19
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`obligations_by_fiscal_year(fiscal_year, obligated)` shape expand on contracts, IDVs, OTAs and OTIDVs** (Tango API 5.11.0). Returns the award's obligations per federal fiscal year, each rounded to cents, with `fiscal_year` parsed as `int` and `obligated` as `Decimal`. It is always `None` on IDVs and OTIDVs, whose transactions report a running lifetime total.
|
|
15
|
+
- **`attachments(extraction_status)` shape field on opportunities and notices** (Tango API 5.11.0). Reports `pending`, `extracting`, `completed`, `failed` or `unsupported` for each attachment, so you can tell why `extracted_text` is missing.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Re-vendored `contracts/filter_shape_contract.json` (Tango API 5.11.0) and regenerated the shape overlay.
|
|
20
|
+
- Documented that `recipient_uei` on `list_contracts()` (and `uei` on the IDV, OTA and OTIDV lists) accepts several UEIs joined by `|` (Tango API 5.11.0); the SDK already passed the value through unchanged.
|
|
21
|
+
|
|
22
|
+
## [1.17.0] - 2026-10-16
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **`commercial_item_acquisition_procedures` filter on `list_contracts()` and `list_idvs()`** (Tango API 5.10.0). Filters by the FPDS commercial item acquisition procedures code: `A` (commercial products/services), `B` (products or services pursuant to FAR 12.102(f)), `C` (services pursuant to FAR 12.102(g)), `D` (commercial procedures not used) or `E` (DoD Section 803 Commercial Solutions Opening). Codes are case-insensitive and pipe-separated for OR, e.g. `"A|E"`; an unknown or multi-character code matches nothing. The API does not offer it on OTAs or OTIDVs, so `list_otas()` and `list_otidvs()` do not take it. The field itself was already returned in responses.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Re-vendored `contracts/filter_shape_contract.json` (Tango API 5.10.0).
|
|
31
|
+
|
|
10
32
|
## [1.16.0] - 2026-10-10
|
|
11
33
|
|
|
12
34
|
### Added
|
|
@@ -244,6 +244,7 @@ contracts = client.list_contracts(
|
|
|
244
244
|
naics_code=None, # Mapped to 'naics' API param
|
|
245
245
|
psc_code=None, # Mapped to 'psc' API param
|
|
246
246
|
set_aside_type=None, # Mapped to 'set_aside' API param
|
|
247
|
+
commercial_item_acquisition_procedures=None, # FPDS code A-E, e.g. "A|E"
|
|
247
248
|
# Type filters
|
|
248
249
|
fiscal_year=None,
|
|
249
250
|
fiscal_year_gte=None,
|
|
@@ -284,12 +285,13 @@ contracts = client.list_contracts(
|
|
|
284
285
|
- `awarding_agency` - Agency code (e.g., "4700" for GSA)
|
|
285
286
|
- `funding_agency` - Funding agency code
|
|
286
287
|
- `recipient_name` - Vendor/recipient name (mapped to 'recipient' API param)
|
|
287
|
-
- `recipient_uei` - Vendor UEI (mapped to 'uei' API param)
|
|
288
|
+
- `recipient_uei` - Vendor UEI (mapped to 'uei' API param). Several UEIs joined by `|` match awards to any of them, up to 500 (Tango API 5.11.0).
|
|
288
289
|
|
|
289
290
|
**Classification:**
|
|
290
291
|
- `naics_code` - NAICS industry code (mapped to 'naics' API param)
|
|
291
292
|
- `psc_code` - Product/Service code (mapped to 'psc' API param)
|
|
292
293
|
- `set_aside_type` - Set-aside type (mapped to 'set_aside' API param)
|
|
294
|
+
- `commercial_item_acquisition_procedures` - FPDS commercial item acquisition procedures code, case-insensitive: `A` (commercial products/services), `B` (products or services pursuant to FAR 12.102(f)), `C` (services pursuant to FAR 12.102(g)), `D` (commercial procedures not used) or `E` (DoD Section 803 Commercial Solutions Opening). Multi-value OR via `|`, e.g. `"A|E"`. An unknown or multi-character code matches nothing.
|
|
293
295
|
|
|
294
296
|
**Type Filters:**
|
|
295
297
|
- `fiscal_year` - Federal fiscal year (exact match)
|
|
@@ -379,6 +381,22 @@ contracts = client.list_contracts(
|
|
|
379
381
|
- `psc` - Product/service code (nested)
|
|
380
382
|
- `place_of_performance` - Location (nested)
|
|
381
383
|
|
|
384
|
+
**Obligations by fiscal year — `obligations_by_fiscal_year(fiscal_year, obligated)`** (Tango API 5.11.0):
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
contracts = client.list_contracts(
|
|
388
|
+
shape="key,piid,obligated,obligations_by_fiscal_year(fiscal_year,obligated)",
|
|
389
|
+
piid="SOME_PIID",
|
|
390
|
+
)
|
|
391
|
+
for year in contracts.results[0]["obligations_by_fiscal_year"] or []:
|
|
392
|
+
print(year["fiscal_year"], year["obligated"]) # int, Decimal
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
- Sums the award's transactions per federal fiscal year (October 1 starts the next fiscal year), oldest year first, each rounded to cents. A de-obligation nets against its own year, so a year can be zero or negative.
|
|
396
|
+
- Returned only when named: no default shape includes it.
|
|
397
|
+
- The same expand works on `list_otas()`, `list_idvs()`, `list_otidvs()` and the `get_*` methods. On IDVs and OTIDVs it is always `None`, because their transactions report a running lifetime total rather than each action's obligation.
|
|
398
|
+
- `None` on a contract or OTA with no dated transactions.
|
|
399
|
+
|
|
382
400
|
---
|
|
383
401
|
|
|
384
402
|
## OTAs
|
|
@@ -420,7 +438,7 @@ otas = client.list_otas(
|
|
|
420
438
|
|
|
421
439
|
**Notes:**
|
|
422
440
|
- Uses **keyset pagination** (`cursor` + `limit`) rather than page numbers.
|
|
423
|
-
- Filter parameters mirror those on `list_contracts
|
|
441
|
+
- Filter parameters mirror those on `list_contracts`, except `commercial_item_acquisition_procedures`, which the API does not offer on OTAs or OTIDVs.
|
|
424
442
|
|
|
425
443
|
**Returns:** [PaginatedResponse](#paginatedresponse) with OTA dictionaries
|
|
426
444
|
|
|
@@ -638,12 +656,14 @@ idvs = client.list_idvs(
|
|
|
638
656
|
cursor=None,
|
|
639
657
|
shape=ShapeConfig.IDVS_MINIMAL,
|
|
640
658
|
awarding_agency="4700",
|
|
659
|
+
commercial_item_acquisition_procedures="E", # DoD Section 803 CSO
|
|
641
660
|
)
|
|
642
661
|
```
|
|
643
662
|
|
|
644
663
|
Notes:
|
|
645
664
|
|
|
646
665
|
- This endpoint uses **keyset pagination** (`cursor` + `limit`) rather than page numbers.
|
|
666
|
+
- `commercial_item_acquisition_procedures` takes the same FPDS codes `A`–`E` as on `list_contracts()`, with `|` for OR.
|
|
647
667
|
|
|
648
668
|
### get_idv()
|
|
649
669
|
|
|
@@ -632,6 +632,7 @@ class TangoClient:
|
|
|
632
632
|
award_date_lte: str | None = None,
|
|
633
633
|
award_type: str | None = None,
|
|
634
634
|
awarding_agency: str | None = None,
|
|
635
|
+
commercial_item_acquisition_procedures: str | None = None,
|
|
635
636
|
expiring_gte: str | None = None,
|
|
636
637
|
expiring_lte: str | None = None,
|
|
637
638
|
fiscal_year: int | None = None,
|
|
@@ -674,6 +675,7 @@ class TangoClient:
|
|
|
674
675
|
award_date_lte: Award date <= (YYYY-MM-DD)
|
|
675
676
|
award_type: Award type code
|
|
676
677
|
awarding_agency: Awarding agency code (e.g., "4700" for GSA)
|
|
678
|
+
commercial_item_acquisition_procedures: FPDS commercial item acquisition procedures code, case-insensitive: "A" (commercial products/services), "B" (products or services pursuant to FAR 12.102(f)), "C" (services pursuant to FAR 12.102(g)), "D" (commercial procedures not used) or "E" (DoD Section 803 Commercial Solutions Opening). Pipe-separate codes for OR, e.g. "A|E"; an unknown code matches nothing.
|
|
677
679
|
expiring_gte: Expiring on or after date
|
|
678
680
|
expiring_lte: Expiring on or before date
|
|
679
681
|
fiscal_year: Fiscal year (exact match)
|
|
@@ -693,7 +695,7 @@ class TangoClient:
|
|
|
693
695
|
naics_code: NAICS code (mapped to 'naics' API param)
|
|
694
696
|
psc_code: PSC code (mapped to 'psc' API param)
|
|
695
697
|
recipient_name: Vendor/recipient name (mapped to 'recipient' API param)
|
|
696
|
-
recipient_uei: Vendor UEI (mapped to 'uei' API param)
|
|
698
|
+
recipient_uei: Vendor UEI (mapped to 'uei' API param); join several with `|` for OR, up to 500
|
|
697
699
|
set_aside_type: Set-aside type (mapped to 'set_aside' API param)
|
|
698
700
|
sort: Field to sort by (combined with 'order' to produce 'ordering')
|
|
699
701
|
order: Sort order ('asc' or 'desc', default 'asc')
|
|
@@ -751,6 +753,7 @@ class TangoClient:
|
|
|
751
753
|
("award_date_lte", award_date_lte),
|
|
752
754
|
("award_type", award_type),
|
|
753
755
|
("awarding_agency", awarding_agency),
|
|
756
|
+
("commercial_item_acquisition_procedures", commercial_item_acquisition_procedures),
|
|
754
757
|
("expiring_gte", expiring_gte),
|
|
755
758
|
("expiring_lte", expiring_lte),
|
|
756
759
|
("fiscal_year", fiscal_year),
|
|
@@ -915,6 +918,7 @@ class TangoClient:
|
|
|
915
918
|
award_date_gte: str | None = None,
|
|
916
919
|
award_date_lte: str | None = None,
|
|
917
920
|
awarding_agency: str | None = None,
|
|
921
|
+
commercial_item_acquisition_procedures: str | None = None,
|
|
918
922
|
expiring_gte: str | None = None,
|
|
919
923
|
expiring_lte: str | None = None,
|
|
920
924
|
fiscal_year: int | None = None,
|
|
@@ -941,6 +945,8 @@ class TangoClient:
|
|
|
941
945
|
|
|
942
946
|
This mirrors `/api/idvs/` and supports the same filter parameters as the API,
|
|
943
947
|
plus shaping via `shape`.
|
|
948
|
+
|
|
949
|
+
`commercial_item_acquisition_procedures` takes an FPDS commercial item acquisition procedures code `A`–`E` (case-insensitive; `E` is DoD Section 803 Commercial Solutions Opening), pipe-separated for OR, e.g. `"A|E"`; an unknown code matches nothing.
|
|
944
950
|
"""
|
|
945
951
|
params: dict[str, Any] = {"limit": min(limit, 100)}
|
|
946
952
|
if cursor:
|
|
@@ -962,6 +968,7 @@ class TangoClient:
|
|
|
962
968
|
("award_date_gte", award_date_gte),
|
|
963
969
|
("award_date_lte", award_date_lte),
|
|
964
970
|
("awarding_agency", awarding_agency),
|
|
971
|
+
("commercial_item_acquisition_procedures", commercial_item_acquisition_procedures),
|
|
965
972
|
("expiring_gte", expiring_gte),
|
|
966
973
|
("expiring_lte", expiring_lte),
|
|
967
974
|
("fiscal_year", fiscal_year),
|
|
@@ -281,6 +281,17 @@ class AwardTransaction:
|
|
|
281
281
|
obligated: Decimal | None = None
|
|
282
282
|
|
|
283
283
|
|
|
284
|
+
@dataclass
|
|
285
|
+
class FiscalYearObligation:
|
|
286
|
+
"""Schema definition for FiscalYearObligation (not used for instances).
|
|
287
|
+
|
|
288
|
+
One entry of an award's ``obligations_by_fiscal_year``: the obligations dated in one federal fiscal year, rounded to cents.
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
fiscal_year: int
|
|
292
|
+
obligated: Decimal
|
|
293
|
+
|
|
294
|
+
|
|
284
295
|
@dataclass
|
|
285
296
|
class OrganizationOfficePayload:
|
|
286
297
|
"""Schema definition for OrganizationOfficePayload (not used for instances).
|
|
@@ -197,6 +197,12 @@ TRANSACTION_SCHEMA: dict[str, FieldSchema] = {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
|
|
200
|
+
FISCAL_YEAR_OBLIGATION_SCHEMA: dict[str, FieldSchema] = {
|
|
201
|
+
"fiscal_year": FieldSchema(name="fiscal_year", type=int, is_optional=False, is_list=False),
|
|
202
|
+
"obligated": FieldSchema(name="obligated", type=Decimal, is_optional=False, is_list=False),
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
|
|
200
206
|
DEPARTMENT_SCHEMA: dict[str, FieldSchema] = {
|
|
201
207
|
"abbreviation": FieldSchema(name="abbreviation", type=str, is_optional=True, is_list=False),
|
|
202
208
|
"code": FieldSchema(name="code", type=int, is_optional=True, is_list=False),
|
|
@@ -432,6 +438,13 @@ CONTRACT_SCHEMA: dict[str, FieldSchema] = {
|
|
|
432
438
|
is_list=False,
|
|
433
439
|
nested_model="Vehicle",
|
|
434
440
|
),
|
|
441
|
+
"obligations_by_fiscal_year": FieldSchema(
|
|
442
|
+
name="obligations_by_fiscal_year",
|
|
443
|
+
type=dict,
|
|
444
|
+
is_optional=True,
|
|
445
|
+
is_list=True,
|
|
446
|
+
nested_model="FiscalYearObligation",
|
|
447
|
+
),
|
|
435
448
|
}
|
|
436
449
|
|
|
437
450
|
|
|
@@ -1290,6 +1303,13 @@ IDV_SCHEMA: dict[str, FieldSchema] = {
|
|
|
1290
1303
|
"idv_contracts_value": FieldSchema(
|
|
1291
1304
|
name="idv_contracts_value", type=Decimal, is_optional=True, is_list=False
|
|
1292
1305
|
),
|
|
1306
|
+
"obligations_by_fiscal_year": FieldSchema(
|
|
1307
|
+
name="obligations_by_fiscal_year",
|
|
1308
|
+
type=dict,
|
|
1309
|
+
is_optional=True,
|
|
1310
|
+
is_list=True,
|
|
1311
|
+
nested_model="FiscalYearObligation",
|
|
1312
|
+
),
|
|
1293
1313
|
}
|
|
1294
1314
|
|
|
1295
1315
|
|
|
@@ -1439,6 +1459,13 @@ OTA_SCHEMA: dict[str, FieldSchema] = {
|
|
|
1439
1459
|
is_list=False,
|
|
1440
1460
|
nested_model="RecipientProfile",
|
|
1441
1461
|
),
|
|
1462
|
+
"obligations_by_fiscal_year": FieldSchema(
|
|
1463
|
+
name="obligations_by_fiscal_year",
|
|
1464
|
+
type=dict,
|
|
1465
|
+
is_optional=True,
|
|
1466
|
+
is_list=True,
|
|
1467
|
+
nested_model="FiscalYearObligation",
|
|
1468
|
+
),
|
|
1442
1469
|
}
|
|
1443
1470
|
|
|
1444
1471
|
# OTIDV (Other Transaction IDV) - IDV-like
|
|
@@ -1459,6 +1486,13 @@ OTIDV_SCHEMA: dict[str, FieldSchema] = {
|
|
|
1459
1486
|
is_list=False,
|
|
1460
1487
|
nested_model="RecipientProfile",
|
|
1461
1488
|
),
|
|
1489
|
+
"obligations_by_fiscal_year": FieldSchema(
|
|
1490
|
+
name="obligations_by_fiscal_year",
|
|
1491
|
+
type=dict,
|
|
1492
|
+
is_optional=True,
|
|
1493
|
+
is_list=True,
|
|
1494
|
+
nested_model="FiscalYearObligation",
|
|
1495
|
+
),
|
|
1462
1496
|
}
|
|
1463
1497
|
|
|
1464
1498
|
# Subaward (prime/sub awards)
|
|
@@ -1707,6 +1741,7 @@ EXPLICIT_SCHEMAS: dict[str, dict[str, FieldSchema]] = {
|
|
|
1707
1741
|
"LegislativeMandates": LEGISLATIVE_MANDATES_SCHEMA,
|
|
1708
1742
|
"SubawardsSummary": SUBAWARDS_SUMMARY_SCHEMA,
|
|
1709
1743
|
"Transaction": TRANSACTION_SCHEMA,
|
|
1744
|
+
"FiscalYearObligation": FISCAL_YEAR_OBLIGATION_SCHEMA,
|
|
1710
1745
|
"Department": DEPARTMENT_SCHEMA,
|
|
1711
1746
|
"Contact": CONTACT_SCHEMA,
|
|
1712
1747
|
"RecipientProfile": RECIPIENT_PROFILE_SCHEMA,
|
|
@@ -85,6 +85,9 @@ ATTACHMENTS_SCHEMA: dict[str, FieldSchema] = {
|
|
|
85
85
|
"doc_role": FieldSchema(name="doc_role", type=str, is_optional=True, is_list=False),
|
|
86
86
|
"doc_role_alt": FieldSchema(name="doc_role_alt", type=str, is_optional=True, is_list=False),
|
|
87
87
|
"extracted_text": FieldSchema(name="extracted_text", type=str, is_optional=True, is_list=False),
|
|
88
|
+
"extraction_status": FieldSchema(
|
|
89
|
+
name="extraction_status", type=str, is_optional=True, is_list=False
|
|
90
|
+
),
|
|
88
91
|
"file_size": FieldSchema(name="file_size", type=int, is_optional=True, is_list=False),
|
|
89
92
|
"mime_type": FieldSchema(name="mime_type", type=str, is_optional=True, is_list=False),
|
|
90
93
|
"name": FieldSchema(name="name", type=str, is_optional=True, is_list=False),
|
|
@@ -99,6 +102,9 @@ ATTACHMENTS2_SCHEMA: dict[str, FieldSchema] = {
|
|
|
99
102
|
"doc_role": FieldSchema(name="doc_role", type=str, is_optional=True, is_list=False),
|
|
100
103
|
"doc_role_alt": FieldSchema(name="doc_role_alt", type=str, is_optional=True, is_list=False),
|
|
101
104
|
"extracted_text": FieldSchema(name="extracted_text", type=str, is_optional=True, is_list=False),
|
|
105
|
+
"extraction_status": FieldSchema(
|
|
106
|
+
name="extraction_status", type=str, is_optional=True, is_list=False
|
|
107
|
+
),
|
|
102
108
|
"file_size": FieldSchema(name="file_size", type=int, is_optional=True, is_list=False),
|
|
103
109
|
"mime_type": FieldSchema(name="mime_type", type=str, is_optional=True, is_list=False),
|
|
104
110
|
"name": FieldSchema(name="name", type=str, is_optional=True, is_list=False),
|
|
@@ -135,6 +141,9 @@ ATTACHMENTS3_SCHEMA: dict[str, FieldSchema] = {
|
|
|
135
141
|
|
|
136
142
|
ATTACHMENTS4_SCHEMA: dict[str, FieldSchema] = {
|
|
137
143
|
"attachment_id": FieldSchema(name="attachment_id", type=str, is_optional=True, is_list=False),
|
|
144
|
+
"extraction_status": FieldSchema(
|
|
145
|
+
name="extraction_status", type=str, is_optional=True, is_list=False
|
|
146
|
+
),
|
|
138
147
|
"file_size": FieldSchema(name="file_size", type=str, is_optional=True, is_list=False),
|
|
139
148
|
"mime_type": FieldSchema(name="mime_type", type=str, is_optional=True, is_list=False),
|
|
140
149
|
"name": FieldSchema(name="name", type=str, is_optional=True, is_list=False),
|
|
@@ -149,6 +158,9 @@ ATTACHMENTS5_SCHEMA: dict[str, FieldSchema] = {
|
|
|
149
158
|
"doc_role": FieldSchema(name="doc_role", type=str, is_optional=True, is_list=False),
|
|
150
159
|
"doc_role_alt": FieldSchema(name="doc_role_alt", type=str, is_optional=True, is_list=False),
|
|
151
160
|
"extracted_text": FieldSchema(name="extracted_text", type=str, is_optional=True, is_list=False),
|
|
161
|
+
"extraction_status": FieldSchema(
|
|
162
|
+
name="extraction_status", type=str, is_optional=True, is_list=False
|
|
163
|
+
),
|
|
152
164
|
"file_size": FieldSchema(name="file_size", type=str, is_optional=True, is_list=False),
|
|
153
165
|
"mime_type": FieldSchema(name="mime_type", type=str, is_optional=True, is_list=False),
|
|
154
166
|
"name": FieldSchema(name="name", type=str, is_optional=True, is_list=False),
|
|
@@ -758,6 +770,11 @@ NOTICE_TYPE_SCHEMA: dict[str, FieldSchema] = {
|
|
|
758
770
|
"type": FieldSchema(name="type", type=str, is_optional=True, is_list=False),
|
|
759
771
|
}
|
|
760
772
|
|
|
773
|
+
OBLIGATIONS_BY_FISCAL_YEAR_SCHEMA: dict[str, FieldSchema] = {
|
|
774
|
+
"fiscal_year": FieldSchema(name="fiscal_year", type=str, is_optional=True, is_list=False),
|
|
775
|
+
"obligated": FieldSchema(name="obligated", type=str, is_optional=True, is_list=False),
|
|
776
|
+
}
|
|
777
|
+
|
|
761
778
|
OFFICERS_SCHEMA: dict[str, FieldSchema] = {
|
|
762
779
|
"highly_compensated_officer_1_amount": FieldSchema(
|
|
763
780
|
name="highly_compensated_officer_1_amount", type=Decimal, is_optional=True, is_list=False
|
|
@@ -1161,6 +1178,7 @@ GENERATED_NESTED: dict[str, dict[str, FieldSchema]] = {
|
|
|
1161
1178
|
"NoticeHistory": NOTICE_HISTORY_SCHEMA,
|
|
1162
1179
|
"NoticeHistory2": NOTICE_HISTORY2_SCHEMA,
|
|
1163
1180
|
"NoticeType": NOTICE_TYPE_SCHEMA,
|
|
1181
|
+
"ObligationsByFiscalYear": OBLIGATIONS_BY_FISCAL_YEAR_SCHEMA,
|
|
1164
1182
|
"Officers": OFFICERS_SCHEMA,
|
|
1165
1183
|
"Opportunity": OPPORTUNITY_SCHEMA,
|
|
1166
1184
|
"Opportunity2": OPPORTUNITY2_SCHEMA,
|
|
@@ -2247,6 +2247,33 @@ class TestEntityFilters:
|
|
|
2247
2247
|
assert "socioeconomic" not in mock_request.call_args[1]["params"]
|
|
2248
2248
|
|
|
2249
2249
|
|
|
2250
|
+
class TestCommercialItemAcquisitionProceduresFilter:
|
|
2251
|
+
@pytest.mark.parametrize("method", ["list_contracts", "list_idvs"])
|
|
2252
|
+
@patch("tango.client.httpx.Client.request")
|
|
2253
|
+
def test_forwards_pipe_separated_codes_verbatim(self, mock_request, method):
|
|
2254
|
+
_stub_empty_page(mock_request)
|
|
2255
|
+
getattr(TangoClient(api_key="test-key"), method)(
|
|
2256
|
+
commercial_item_acquisition_procedures="a|E"
|
|
2257
|
+
)
|
|
2258
|
+
assert (
|
|
2259
|
+
mock_request.call_args[1]["params"]["commercial_item_acquisition_procedures"] == "a|E"
|
|
2260
|
+
)
|
|
2261
|
+
|
|
2262
|
+
@pytest.mark.parametrize("method", ["list_contracts", "list_idvs"])
|
|
2263
|
+
@patch("tango.client.httpx.Client.request")
|
|
2264
|
+
def test_omits_unset_filter(self, mock_request, method):
|
|
2265
|
+
_stub_empty_page(mock_request)
|
|
2266
|
+
getattr(TangoClient(api_key="test-key"), method)()
|
|
2267
|
+
assert "commercial_item_acquisition_procedures" not in mock_request.call_args[1]["params"]
|
|
2268
|
+
|
|
2269
|
+
@pytest.mark.parametrize("method", ["list_otas", "list_otidvs"])
|
|
2270
|
+
def test_not_accepted_on_other_transaction_lists(self, method):
|
|
2271
|
+
with pytest.raises(TypeError, match="commercial_item_acquisition_procedures"):
|
|
2272
|
+
getattr(TangoClient(api_key="test-key"), method)(
|
|
2273
|
+
commercial_item_acquisition_procedures="E"
|
|
2274
|
+
)
|
|
2275
|
+
|
|
2276
|
+
|
|
2250
2277
|
class TestAgencyFilterDiagnostics:
|
|
2251
2278
|
"""`meta` from the API's agency-filter diagnostics.
|
|
2252
2279
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""The `obligations_by_fiscal_year(...)` expand on contracts, IDVs, OTAs and OT IDVs."""
|
|
2
|
+
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
from unittest.mock import Mock, patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from tango import TangoClient
|
|
9
|
+
from tango.models import IDV, OTA, OTIDV, Contract, Notice, Opportunity
|
|
10
|
+
from tango.shapes.parser import ShapeParser
|
|
11
|
+
|
|
12
|
+
SHAPE = "key,obligations_by_fiscal_year(fiscal_year,obligated)"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _mock(mock_request, payload):
|
|
16
|
+
response = Mock()
|
|
17
|
+
response.is_success = True
|
|
18
|
+
response.json.return_value = payload
|
|
19
|
+
response.content = b"{}"
|
|
20
|
+
mock_request.return_value = response
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _page(rows):
|
|
24
|
+
return {"count": len(rows), "next": None, "previous": None, "results": rows}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TestObligationsByFiscalYearShape:
|
|
28
|
+
@pytest.mark.parametrize("model", [Contract, IDV, OTA, OTIDV])
|
|
29
|
+
@pytest.mark.parametrize(
|
|
30
|
+
"shape",
|
|
31
|
+
[
|
|
32
|
+
SHAPE,
|
|
33
|
+
"key,obligations_by_fiscal_year(*)",
|
|
34
|
+
"key,obligations_by_fiscal_year",
|
|
35
|
+
],
|
|
36
|
+
)
|
|
37
|
+
def test_shape_validates(self, model, shape):
|
|
38
|
+
parser = ShapeParser(cache_enabled=False)
|
|
39
|
+
parser.validate(parser.parse(shape), model)
|
|
40
|
+
|
|
41
|
+
@pytest.mark.parametrize("model", [Contract, OTA])
|
|
42
|
+
def test_unknown_sub_field_is_rejected(self, model):
|
|
43
|
+
parser = ShapeParser(cache_enabled=False)
|
|
44
|
+
with pytest.raises(Exception, match="amount"):
|
|
45
|
+
parser.validate(parser.parse("key,obligations_by_fiscal_year(amount)"), model)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TestObligationsByFiscalYearResponses:
|
|
49
|
+
@pytest.mark.parametrize("method", ["list_contracts", "list_otas"])
|
|
50
|
+
@patch("tango.client.httpx.Client.request")
|
|
51
|
+
def test_list_parses_each_year(self, mock_request, method):
|
|
52
|
+
_mock(
|
|
53
|
+
mock_request,
|
|
54
|
+
_page(
|
|
55
|
+
[
|
|
56
|
+
{
|
|
57
|
+
"key": "K1",
|
|
58
|
+
"obligations_by_fiscal_year": [
|
|
59
|
+
{"fiscal_year": 2023, "obligated": 1000.0},
|
|
60
|
+
{"fiscal_year": 2024, "obligated": -250.5},
|
|
61
|
+
],
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
(row,) = getattr(TangoClient(api_key="k"), method)(shape=SHAPE).results
|
|
68
|
+
|
|
69
|
+
years = row["obligations_by_fiscal_year"]
|
|
70
|
+
assert [y["fiscal_year"] for y in years] == [2023, 2024]
|
|
71
|
+
assert [y["obligated"] for y in years] == [Decimal("1000.0"), Decimal("-250.5")]
|
|
72
|
+
assert all(isinstance(y["obligated"], Decimal) for y in years)
|
|
73
|
+
|
|
74
|
+
@pytest.mark.parametrize("method", ["list_idvs", "list_otidvs"])
|
|
75
|
+
@patch("tango.client.httpx.Client.request")
|
|
76
|
+
def test_cumulative_award_types_return_none(self, mock_request, method):
|
|
77
|
+
_mock(mock_request, _page([{"key": "K1", "obligations_by_fiscal_year": None}]))
|
|
78
|
+
|
|
79
|
+
(row,) = getattr(TangoClient(api_key="k"), method)(shape=SHAPE).results
|
|
80
|
+
|
|
81
|
+
assert row["obligations_by_fiscal_year"] is None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class TestAttachmentExtractionStatusShape:
|
|
85
|
+
@pytest.mark.parametrize("model", [Opportunity, Notice])
|
|
86
|
+
def test_shape_validates(self, model):
|
|
87
|
+
parser = ShapeParser(cache_enabled=False)
|
|
88
|
+
parser.validate(parser.parse("title,attachments(name,extraction_status)"), model)
|
|
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.16.0 → tango_python-1.18.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
|