tango-python 1.10.0__tar.gz → 1.11.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.10.0 → tango_python-1.11.0}/CHANGELOG.md +6 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/PKG-INFO +1 -1
- {tango_python-1.10.0 → tango_python-1.11.0}/docs/API_REFERENCE.md +31 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/pyproject.toml +1 -1
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/__init__.py +1 -1
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/client.py +7 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/models.py +18 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/generated_overlay.py +27 -0
- tango_python-1.11.0/tests/test_opportunity_awards.py +136 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/.gitignore +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/LICENSE +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/README.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/docs/CLIENT.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/docs/DYNAMIC_MODELS.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/docs/ERRORS.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/docs/PAGINATION.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/docs/SHAPES.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/docs/WEBHOOKS.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/README.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/check_filter_shape_conformance.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/check_shape_coverage.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/fetch_api_schema.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/generate_schemas_from_api.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/generate_shape_overlay.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/pr_review.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/probe_shape_types.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/refresh_contract.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/smoke_api_parity.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/scripts/test_production.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/exceptions.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/__init__.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/explicit_schemas.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/factory.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/generator.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/models.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/parser.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/schema.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/shapes/types.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/webhooks/__init__.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/webhooks/cli.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/webhooks/receiver.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/webhooks/signing.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tango/webhooks/simulate.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/__init__.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestAgenciesIntegration.test_get_agency +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestAgenciesIntegration.test_list_agencies +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_field_type_validation +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_parsing_consistency +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestBusinessTypesIntegration.test_list_business_types +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_combined_filters_work_together +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_contract_cursor_pagination +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_contract_data_object_parsing +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_contract_field_types +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[keyword-software] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[psc_code-R425] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_awarding_agency_filter +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_date_range_filter +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_flat +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_naics_code_filter +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[default-None] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_new_expiring_filters +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_new_fiscal_year_range_filters +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_new_identifier_filters +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_search_contracts_with_filters +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_search_filters_object_with_new_parameters +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[asc-] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[desc--] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_contracts +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_entities +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_date_field_parsing_edge_cases +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_decimal_field_parsing_edge_cases +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_empty_list_responses +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_entity_parsing_with_various_address_formats +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_flattened_responses_with_flat_lists +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_list_field_parsing_consistency +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_nested_objects_with_missing_data +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_null_missing_fields_in_contracts +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_with_minimal_shape_sparse_data +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_entity_field_types +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_entity_location_parsing +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_entity_parsing_with_business_types +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_entity_with_various_identifiers +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_budget_flows +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_by_uei +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_flat +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_search +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[custom-uei,legal_business_name,cage_code] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestForecastsIntegration.test_forecast_field_types +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[custom-id,title,anticipated_award_date] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[default-None] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestGrantsIntegration.test_grant_field_types +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestGrantsIntegration.test_grant_pagination +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[custom-grant_id,title,opportunity_number] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[default-None] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[minimal-grant_id,opportunity_number,title,status(-),agency_code] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestIDVsIntegration.test_get_idv_uses_default_shape +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_awards_uses_default_shape +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_child_idvs_uses_default_shape +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_transactions +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestIDVsIntegration.test_list_idvs_uses_default_shape_and_keyset_params +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestNaicsIntegration.test_list_naics +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[custom-notice_id,title,solicitation_number] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[default-None] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestNoticesIntegration.test_notice_field_types +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestNoticesIntegration.test_notice_pagination +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestNoticesIntegration.test_notice_with_meta_fields +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOTAsIntegration.test_get_ota +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOTAsIntegration.test_list_otas +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOTIDVsIntegration.test_get_otidv +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOTIDVsIntegration.test_list_otidvs +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOfficesIntegration.test_get_office +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOfficesIntegration.test_list_offices +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[custom-opportunity_id,title,solicitation_number] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[default-None] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOpportunitiesIntegration.test_opportunity_field_types +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOrganizationsIntegration.test_get_organization +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestOrganizationsIntegration.test_list_organizations +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestProtestsIntegration.test_get_protest_by_case_id +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_filter +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[custom-case_id,title,source_system,outcome] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[default-None] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestProtestsIntegration.test_protest_pagination +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestSubawardsIntegration.test_list_subawards +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[custom-key,piid,description] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[ultra_minimal-key,piid,recipient(display_name),total_contract_value] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestTypeHintsIntegration.test_notices_dict_access[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.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.10.0 → tango_python-1.11.0}/tests/cassettes/TestTypeHintsIntegration.test_opportunities_dict_access[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_with_metrics_expansion +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_orders_uses_default_shape +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_with_ordering +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/conftest.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/README.md +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/__init__.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/conftest.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_agencies_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_contracts_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_edge_cases_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_entities_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_forecasts_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_grants_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_itdashboard_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_naics_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_notices_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_offices_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_opportunities_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_organizations_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_otas_otidvs_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_protests_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_reference_data_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_subawards_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/test_vehicles_idvs_integration.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/integration/validation.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/production/__init__.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/production/conftest.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/production/test_production_smoke.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_api_parity.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_client.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_contract_appeals.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_dibbs_exclusions_sbir.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_ebuy.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_federal_register.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_models.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_opportunity_attachments.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_organization_scope.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_shape_coverage_gate.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_shapes.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_sled.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_webhooks_cli.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_webhooks_receiver.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_webhooks_signing.py +0 -0
- {tango_python-1.10.0 → tango_python-1.11.0}/tests/test_webhooks_simulate.py +0 -0
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.11.0] - 2026-09-29
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Award fields on opportunities and notices** (Tango API 5.5.0) — new `awarded` / `awardee_uei` filters on `list_opportunities()`, plus award leaves and an `awards(...)` expand in the opportunity and notice shapes (see `docs/API_REFERENCE.md`).
|
|
15
|
+
|
|
10
16
|
## [1.10.0] - 2026-09-29
|
|
11
17
|
|
|
12
18
|
### Added
|
|
@@ -868,6 +868,8 @@ opportunities = client.list_opportunities(
|
|
|
868
868
|
# Filter parameters (all optional)
|
|
869
869
|
active=None,
|
|
870
870
|
agency=None,
|
|
871
|
+
awarded=None,
|
|
872
|
+
awardee_uei=None,
|
|
871
873
|
first_notice_date_after=None,
|
|
872
874
|
first_notice_date_before=None,
|
|
873
875
|
last_notice_date_after=None,
|
|
@@ -894,6 +896,8 @@ opportunities = client.list_opportunities(
|
|
|
894
896
|
**Filter Parameters:**
|
|
895
897
|
- `active` - Filter by active status (bool)
|
|
896
898
|
- `agency` - Filter by agency code
|
|
899
|
+
- `awarded` - Whether the opportunity has an award, either posted on it or linked to it (bool). Requires Tango API 5.5.0
|
|
900
|
+
- `awardee_uei` - Awardee UEI, case-insensitive; OR several with `|`. Requires Tango API 5.5.0
|
|
897
901
|
- `first_notice_date_after` / `first_notice_date_before` - First notice date range
|
|
898
902
|
- `last_notice_date_after` / `last_notice_date_before` - Last notice date range
|
|
899
903
|
- `naics` - NAICS code
|
|
@@ -947,6 +951,33 @@ for attachment in opp["attachments"]:
|
|
|
947
951
|
- A Free-plan request that names them gets the response without them, plus an entry in `meta.upgrade_hints`.
|
|
948
952
|
- There is no filter on document role.
|
|
949
953
|
|
|
954
|
+
**Award fields:**
|
|
955
|
+
|
|
956
|
+
Tango API 5.5.0 adds award information to opportunities.
|
|
957
|
+
None of it is in the SDK's default shape, so name the fields you want.
|
|
958
|
+
|
|
959
|
+
```python
|
|
960
|
+
opp = client.get_opportunity(
|
|
961
|
+
opportunity_id,
|
|
962
|
+
shape=(
|
|
963
|
+
"opportunity_id,title,awarded,award_date,award_amount,awardee,awardee_uei,"
|
|
964
|
+
"award_count,solicitation_opportunity_id,"
|
|
965
|
+
"awards(opportunity_id,notice_id,award_number,award_date,award_amount,awardee,awardee_uei)"
|
|
966
|
+
),
|
|
967
|
+
)
|
|
968
|
+
|
|
969
|
+
awarded = client.list_opportunities(
|
|
970
|
+
awardee_uei="ABCDEF123456",
|
|
971
|
+
shape="opportunity_id,title,award_date,awardee",
|
|
972
|
+
)
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
- `award_date`, `award_amount`, `awardee` and `awardee_uei` are filled only where SAM.gov posted an award notice; elsewhere they are null. `award_amount` is the text SAM.gov published, not a number.
|
|
976
|
+
- SAM.gov often posts an award as its own opportunity. When that award notice references its solicitation, the award's `solicitation_opportunity_id` points back to the solicitation, and the solicitation's `awards(...)` lists up to ten of the most recent linked awards; `award_count` is the full count. An award notice that does not reference its solicitation is not linked.
|
|
977
|
+
- `awarded` is true when the opportunity has an award of its own or has linked awards.
|
|
978
|
+
- The `awarded` and `awardee_uei` filters search every opportunity, not just active ones, so pass `active=True` to narrow to open opportunities.
|
|
979
|
+
- Notices accept `award_date`, `award_amount`, `awardee` and `awardee_uei` in `shape` too.
|
|
980
|
+
|
|
950
981
|
---
|
|
951
982
|
|
|
952
983
|
## Notices
|
|
@@ -2346,6 +2346,9 @@ class TangoClient:
|
|
|
2346
2346
|
search: str | None = None,
|
|
2347
2347
|
set_aside: str | None = None,
|
|
2348
2348
|
solicitation_number: str | None = None,
|
|
2349
|
+
*,
|
|
2350
|
+
awarded: bool | None = None,
|
|
2351
|
+
awardee_uei: str | None = None,
|
|
2349
2352
|
) -> PaginatedResponse:
|
|
2350
2353
|
"""
|
|
2351
2354
|
List contract opportunities/solicitations
|
|
@@ -2358,6 +2361,8 @@ class TangoClient:
|
|
|
2358
2361
|
flat_lists: If True, flatten arrays using indexed keys
|
|
2359
2362
|
active: Filter by active status
|
|
2360
2363
|
agency: Agency filter
|
|
2364
|
+
awarded: Filter by whether the opportunity has an award, either posted on it or linked to it from a separate award notice. Searches every opportunity rather than only active ones. Requires Tango API 5.5.0
|
|
2365
|
+
awardee_uei: Filter by the awardee's UEI (case-insensitive). OR several with ``|``. Searches every opportunity rather than only active ones. Requires Tango API 5.5.0
|
|
2361
2366
|
first_notice_date_after: First notice date after
|
|
2362
2367
|
first_notice_date_before: First notice date before
|
|
2363
2368
|
last_notice_date_after: Last notice date after
|
|
@@ -2387,6 +2392,8 @@ class TangoClient:
|
|
|
2387
2392
|
for key, val in (
|
|
2388
2393
|
("active", active),
|
|
2389
2394
|
("agency", agency),
|
|
2395
|
+
("awarded", awarded),
|
|
2396
|
+
("awardee_uei", awardee_uei),
|
|
2390
2397
|
("first_notice_date_after", first_notice_date_after),
|
|
2391
2398
|
("first_notice_date_before", first_notice_date_before),
|
|
2392
2399
|
("last_notice_date_after", last_notice_date_after),
|
|
@@ -565,6 +565,10 @@ class Opportunity:
|
|
|
565
565
|
Both must be named, e.g. ``attachments(name,url,doc_role,doc_role_alt)``, because ``attachments(*)`` does not include them.
|
|
566
566
|
An attachment Tango has not classified omits both keys rather than returning null, so read them with ``.get()``.
|
|
567
567
|
A Free-plan request that names them gets the response without them, plus an entry in ``meta.upgrade_hints``.
|
|
568
|
+
|
|
569
|
+
The award fields (``award_date``, ``award_amount``, ``awardee``, ``awardee_uei``) are filled only where SAM.gov posted an award notice, and ``award_amount`` is the text SAM.gov published, not a number.
|
|
570
|
+
SAM.gov often posts an award as its own opportunity; when that award notice references its solicitation, ``solicitation_opportunity_id`` points back to it, and the solicitation's ``awards(...)`` expand lists up to ten of the most recent linked awards, with ``award_count`` giving the full count.
|
|
571
|
+
An award notice that does not reference its solicitation is not linked.
|
|
568
572
|
"""
|
|
569
573
|
|
|
570
574
|
opportunity_id: str
|
|
@@ -575,6 +579,15 @@ class Opportunity:
|
|
|
575
579
|
active: bool | None = None
|
|
576
580
|
naics_code: str | None = None
|
|
577
581
|
psc_code: str | None = None
|
|
582
|
+
award_number: str | None = None
|
|
583
|
+
awarded: bool | None = None
|
|
584
|
+
award_date: date | None = None
|
|
585
|
+
award_amount: str | None = None
|
|
586
|
+
awardee: str | None = None
|
|
587
|
+
awardee_uei: str | None = None
|
|
588
|
+
award_count: int | None = None
|
|
589
|
+
solicitation_opportunity_id: str | None = None
|
|
590
|
+
awards: list[dict[str, Any]] | None = None
|
|
578
591
|
|
|
579
592
|
|
|
580
593
|
@dataclass
|
|
@@ -593,6 +606,11 @@ class Notice:
|
|
|
593
606
|
description: str | None = None
|
|
594
607
|
posted_date: datetime | None = None
|
|
595
608
|
naics_code: str | None = None
|
|
609
|
+
award_number: str | None = None
|
|
610
|
+
award_date: date | None = None
|
|
611
|
+
award_amount: str | None = None
|
|
612
|
+
awardee: str | None = None
|
|
613
|
+
awardee_uei: str | None = None
|
|
596
614
|
|
|
597
615
|
|
|
598
616
|
@dataclass
|
|
@@ -213,6 +213,16 @@ AWARDS_SCHEMA: dict[str, FieldSchema] = {
|
|
|
213
213
|
"transactions": FieldSchema(name="transactions", type=str, is_optional=True, is_list=False),
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
AWARDS2_SCHEMA: dict[str, FieldSchema] = {
|
|
217
|
+
"award_amount": FieldSchema(name="award_amount", type=str, is_optional=True, is_list=False),
|
|
218
|
+
"award_date": FieldSchema(name="award_date", type=date, is_optional=True, is_list=False),
|
|
219
|
+
"award_number": FieldSchema(name="award_number", type=str, is_optional=True, is_list=False),
|
|
220
|
+
"awardee": FieldSchema(name="awardee", type=str, is_optional=True, is_list=False),
|
|
221
|
+
"awardee_uei": FieldSchema(name="awardee_uei", type=str, is_optional=True, is_list=False),
|
|
222
|
+
"notice_id": FieldSchema(name="notice_id", type=str, is_optional=True, is_list=False),
|
|
223
|
+
"opportunity_id": FieldSchema(name="opportunity_id", type=str, is_optional=True, is_list=False),
|
|
224
|
+
}
|
|
225
|
+
|
|
216
226
|
BUDGET_APPROPRIATION_SCHEMA: dict[str, FieldSchema] = {
|
|
217
227
|
"cgac": FieldSchema(name="cgac", type=int, is_optional=True, is_list=False),
|
|
218
228
|
"fiscal_year": FieldSchema(name="fiscal_year", type=int, is_optional=True, is_list=False),
|
|
@@ -1112,6 +1122,7 @@ GENERATED_NESTED: dict[str, dict[str, FieldSchema]] = {
|
|
|
1112
1122
|
"AwardingOffice": AWARDING_OFFICE_SCHEMA,
|
|
1113
1123
|
"AwardingOffice2": AWARDING_OFFICE2_SCHEMA,
|
|
1114
1124
|
"Awards": AWARDS_SCHEMA,
|
|
1125
|
+
"Awards2": AWARDS2_SCHEMA,
|
|
1115
1126
|
"BudgetAppropriation": BUDGET_APPROPRIATION_SCHEMA,
|
|
1116
1127
|
"BudgetSpending": BUDGET_SPENDING_SCHEMA,
|
|
1117
1128
|
"Children": CHILDREN_SCHEMA,
|
|
@@ -2228,6 +2239,10 @@ GENERATED_OVERLAY: dict[str, dict[str, FieldSchema]] = {
|
|
|
2228
2239
|
is_list=True,
|
|
2229
2240
|
nested_model="Attachments",
|
|
2230
2241
|
),
|
|
2242
|
+
"award_amount": FieldSchema(name="award_amount", type=str, is_optional=True, is_list=False),
|
|
2243
|
+
"award_date": FieldSchema(name="award_date", type=date, is_optional=True, is_list=False),
|
|
2244
|
+
"awardee": FieldSchema(name="awardee", type=str, is_optional=True, is_list=False),
|
|
2245
|
+
"awardee_uei": FieldSchema(name="awardee_uei", type=str, is_optional=True, is_list=False),
|
|
2231
2246
|
"meta": FieldSchema(
|
|
2232
2247
|
name="meta", type=dict, is_optional=True, is_list=False, nested_model="Meta"
|
|
2233
2248
|
),
|
|
@@ -2476,6 +2491,15 @@ GENERATED_OVERLAY: dict[str, dict[str, FieldSchema]] = {
|
|
|
2476
2491
|
is_list=False,
|
|
2477
2492
|
nested_model="Attachments5",
|
|
2478
2493
|
),
|
|
2494
|
+
"award_amount": FieldSchema(name="award_amount", type=str, is_optional=True, is_list=False),
|
|
2495
|
+
"award_count": FieldSchema(name="award_count", type=int, is_optional=True, is_list=False),
|
|
2496
|
+
"award_date": FieldSchema(name="award_date", type=date, is_optional=True, is_list=False),
|
|
2497
|
+
"awarded": FieldSchema(name="awarded", type=bool, is_optional=True, is_list=False),
|
|
2498
|
+
"awardee": FieldSchema(name="awardee", type=str, is_optional=True, is_list=False),
|
|
2499
|
+
"awardee_uei": FieldSchema(name="awardee_uei", type=str, is_optional=True, is_list=False),
|
|
2500
|
+
"awards": FieldSchema(
|
|
2501
|
+
name="awards", type=dict, is_optional=True, is_list=True, nested_model="Awards2"
|
|
2502
|
+
),
|
|
2479
2503
|
"department": FieldSchema(
|
|
2480
2504
|
name="department",
|
|
2481
2505
|
type=dict,
|
|
@@ -2529,6 +2553,9 @@ GENERATED_OVERLAY: dict[str, dict[str, FieldSchema]] = {
|
|
|
2529
2553
|
nested_model="CodeDescription",
|
|
2530
2554
|
),
|
|
2531
2555
|
"snippet": FieldSchema(name="snippet", type=str, is_optional=True, is_list=False),
|
|
2556
|
+
"solicitation_opportunity_id": FieldSchema(
|
|
2557
|
+
name="solicitation_opportunity_id", type=str, is_optional=True, is_list=False
|
|
2558
|
+
),
|
|
2532
2559
|
},
|
|
2533
2560
|
"Organization": {
|
|
2534
2561
|
"aac_code": FieldSchema(name="aac_code", type=str, is_optional=True, is_list=False),
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Award fields on opportunities and notices, the `awards(...)` expand, and the `awarded` / `awardee_uei` filters."""
|
|
2
|
+
|
|
3
|
+
from datetime import date
|
|
4
|
+
from unittest.mock import Mock, patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from tango import TangoClient
|
|
9
|
+
from tango.models import Notice, Opportunity
|
|
10
|
+
from tango.shapes.parser import ShapeParser
|
|
11
|
+
|
|
12
|
+
AWARD_LEAVES = "award_date,award_amount,awardee,awardee_uei"
|
|
13
|
+
OPPORTUNITY_AWARD_SHAPE = (
|
|
14
|
+
f"opportunity_id,awarded,{AWARD_LEAVES},award_count,solicitation_opportunity_id,awards(*)"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _mock(mock_request, payload):
|
|
19
|
+
response = Mock()
|
|
20
|
+
response.is_success = True
|
|
21
|
+
response.json.return_value = payload
|
|
22
|
+
response.content = b"{}"
|
|
23
|
+
mock_request.return_value = response
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _page(results):
|
|
27
|
+
return {"count": len(results), "next": None, "previous": None, "results": results}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestAwardShapes:
|
|
31
|
+
@pytest.mark.parametrize(
|
|
32
|
+
"shape",
|
|
33
|
+
[
|
|
34
|
+
OPPORTUNITY_AWARD_SHAPE,
|
|
35
|
+
"opportunity_id,awards(opportunity_id,notice_id,award_number,award_date,award_amount,awardee,awardee_uei)",
|
|
36
|
+
],
|
|
37
|
+
)
|
|
38
|
+
def test_opportunity_award_shape_validates(self, shape):
|
|
39
|
+
parser = ShapeParser(cache_enabled=False)
|
|
40
|
+
parser.validate(parser.parse(shape), Opportunity)
|
|
41
|
+
|
|
42
|
+
def test_notice_award_shape_validates(self):
|
|
43
|
+
parser = ShapeParser(cache_enabled=False)
|
|
44
|
+
parser.validate(parser.parse(f"notice_id,award_number,{AWARD_LEAVES}"), Notice)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TestAwardResponses:
|
|
48
|
+
@patch("tango.client.httpx.Client.request")
|
|
49
|
+
def test_get_opportunity_parses_award_fields_and_linked_awards(self, mock_request):
|
|
50
|
+
_mock(
|
|
51
|
+
mock_request,
|
|
52
|
+
{
|
|
53
|
+
"opportunity_id": "solicitation-1",
|
|
54
|
+
"awarded": True,
|
|
55
|
+
"award_date": None,
|
|
56
|
+
"award_amount": None,
|
|
57
|
+
"awardee": None,
|
|
58
|
+
"awardee_uei": None,
|
|
59
|
+
"award_count": 12,
|
|
60
|
+
"solicitation_opportunity_id": None,
|
|
61
|
+
"awards": [
|
|
62
|
+
{
|
|
63
|
+
"opportunity_id": "award-1",
|
|
64
|
+
"notice_id": "notice-1",
|
|
65
|
+
"award_number": "W912-26-C-0001",
|
|
66
|
+
"award_date": "2026-08-14",
|
|
67
|
+
"award_amount": "$1,250,000.00",
|
|
68
|
+
"awardee": "Example Corp",
|
|
69
|
+
"awardee_uei": "ABCDEF123456",
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
row = TangoClient(api_key="k").get_opportunity(
|
|
75
|
+
"solicitation-1", shape=OPPORTUNITY_AWARD_SHAPE
|
|
76
|
+
)
|
|
77
|
+
assert row["awarded"] is True
|
|
78
|
+
assert row["award_count"] == 12
|
|
79
|
+
assert row["awards"][0]["award_number"] == "W912-26-C-0001"
|
|
80
|
+
assert row["awards"][0]["award_amount"] == "$1,250,000.00"
|
|
81
|
+
assert row["awards"][0]["awardee_uei"] == "ABCDEF123456"
|
|
82
|
+
|
|
83
|
+
@patch("tango.client.httpx.Client.request")
|
|
84
|
+
def test_list_notices_returns_award_fields(self, mock_request):
|
|
85
|
+
shape = f"notice_id,{AWARD_LEAVES}"
|
|
86
|
+
_mock(
|
|
87
|
+
mock_request,
|
|
88
|
+
_page(
|
|
89
|
+
[
|
|
90
|
+
{
|
|
91
|
+
"notice_id": "notice-1",
|
|
92
|
+
"award_date": "2026-08-14",
|
|
93
|
+
"award_amount": "1250000",
|
|
94
|
+
"awardee": "Example Corp",
|
|
95
|
+
"awardee_uei": "ABCDEF123456",
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
),
|
|
99
|
+
)
|
|
100
|
+
page = TangoClient(api_key="k").list_notices(shape=shape)
|
|
101
|
+
assert page.results[0]["award_date"] == date(2026, 8, 14)
|
|
102
|
+
assert page.results[0]["award_amount"] == "1250000"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class TestAwardFilters:
|
|
106
|
+
@patch("tango.client.httpx.Client.request")
|
|
107
|
+
def test_list_opportunities_sends_award_filters(self, mock_request):
|
|
108
|
+
_mock(mock_request, _page([]))
|
|
109
|
+
TangoClient(api_key="k").list_opportunities(
|
|
110
|
+
awarded=True, awardee_uei="ABCDEF123456|abcdef654321"
|
|
111
|
+
)
|
|
112
|
+
params = mock_request.call_args.kwargs["params"]
|
|
113
|
+
assert params["awarded"] is True
|
|
114
|
+
assert params["awardee_uei"] == "ABCDEF123456|abcdef654321"
|
|
115
|
+
|
|
116
|
+
@patch("tango.client.httpx.Client.request")
|
|
117
|
+
def test_list_opportunities_sends_awarded_false(self, mock_request):
|
|
118
|
+
_mock(mock_request, _page([]))
|
|
119
|
+
TangoClient(api_key="k").list_opportunities(awarded=False)
|
|
120
|
+
params = mock_request.call_args.kwargs["params"]
|
|
121
|
+
assert params["awarded"] is False
|
|
122
|
+
assert "awardee_uei" not in params
|
|
123
|
+
|
|
124
|
+
@patch("tango.client.httpx.Client.request")
|
|
125
|
+
def test_existing_positional_arguments_keep_their_meaning(self, mock_request):
|
|
126
|
+
_mock(mock_request, _page([]))
|
|
127
|
+
TangoClient(api_key="k").list_opportunities(
|
|
128
|
+
1, 25, None, False, False, None, None, "2026-08-01"
|
|
129
|
+
)
|
|
130
|
+
params = mock_request.call_args.kwargs["params"]
|
|
131
|
+
assert params["first_notice_date_after"] == "2026-08-01"
|
|
132
|
+
assert "awarded" not in params
|
|
133
|
+
|
|
134
|
+
def test_award_filters_are_keyword_only(self):
|
|
135
|
+
with pytest.raises(TypeError):
|
|
136
|
+
TangoClient(api_key="k").list_opportunities(*([None] * 21), True)
|
|
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.10.0 → tango_python-1.11.0}/tests/cassettes/TestAgenciesIntegration.test_get_agency
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|