tango-python 1.7.0__tar.gz → 1.9.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.
Files changed (207) hide show
  1. {tango_python-1.7.0 → tango_python-1.9.0}/CHANGELOG.md +21 -0
  2. {tango_python-1.7.0 → tango_python-1.9.0}/PKG-INFO +10 -1
  3. {tango_python-1.7.0 → tango_python-1.9.0}/README.md +9 -0
  4. {tango_python-1.7.0 → tango_python-1.9.0}/docs/API_REFERENCE.md +205 -0
  5. {tango_python-1.7.0 → tango_python-1.9.0}/docs/WEBHOOKS.md +2 -0
  6. {tango_python-1.7.0 → tango_python-1.9.0}/pyproject.toml +1 -1
  7. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/check_filter_shape_conformance.py +2 -0
  8. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/check_shape_coverage.py +2 -0
  9. {tango_python-1.7.0 → tango_python-1.9.0}/tango/__init__.py +11 -1
  10. {tango_python-1.7.0 → tango_python-1.9.0}/tango/client.py +416 -51
  11. {tango_python-1.7.0 → tango_python-1.9.0}/tango/exceptions.py +10 -0
  12. {tango_python-1.7.0 → tango_python-1.9.0}/tango/models.py +188 -0
  13. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/explicit_schemas.py +171 -0
  14. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/generated_overlay.py +41 -19
  15. tango_python-1.9.0/tests/test_ebuy.py +322 -0
  16. tango_python-1.9.0/tests/test_federal_register.py +233 -0
  17. tango_python-1.9.0/tests/test_organization_scope.py +107 -0
  18. {tango_python-1.7.0 → tango_python-1.9.0}/.gitignore +0 -0
  19. {tango_python-1.7.0 → tango_python-1.9.0}/LICENSE +0 -0
  20. {tango_python-1.7.0 → tango_python-1.9.0}/docs/CLIENT.md +0 -0
  21. {tango_python-1.7.0 → tango_python-1.9.0}/docs/DYNAMIC_MODELS.md +0 -0
  22. {tango_python-1.7.0 → tango_python-1.9.0}/docs/ERRORS.md +0 -0
  23. {tango_python-1.7.0 → tango_python-1.9.0}/docs/PAGINATION.md +0 -0
  24. {tango_python-1.7.0 → tango_python-1.9.0}/docs/SHAPES.md +0 -0
  25. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/README.md +0 -0
  26. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/fetch_api_schema.py +0 -0
  27. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/generate_schemas_from_api.py +0 -0
  28. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/generate_shape_overlay.py +0 -0
  29. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/pr_review.py +0 -0
  30. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/probe_shape_types.py +0 -0
  31. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/refresh_contract.py +0 -0
  32. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/smoke_api_parity.py +0 -0
  33. {tango_python-1.7.0 → tango_python-1.9.0}/scripts/test_production.py +0 -0
  34. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/__init__.py +0 -0
  35. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/factory.py +0 -0
  36. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/generator.py +0 -0
  37. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/models.py +0 -0
  38. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/parser.py +0 -0
  39. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/schema.py +0 -0
  40. {tango_python-1.7.0 → tango_python-1.9.0}/tango/shapes/types.py +0 -0
  41. {tango_python-1.7.0 → tango_python-1.9.0}/tango/webhooks/__init__.py +0 -0
  42. {tango_python-1.7.0 → tango_python-1.9.0}/tango/webhooks/cli.py +0 -0
  43. {tango_python-1.7.0 → tango_python-1.9.0}/tango/webhooks/receiver.py +0 -0
  44. {tango_python-1.7.0 → tango_python-1.9.0}/tango/webhooks/signing.py +0 -0
  45. {tango_python-1.7.0 → tango_python-1.9.0}/tango/webhooks/simulate.py +0 -0
  46. {tango_python-1.7.0 → tango_python-1.9.0}/tests/__init__.py +0 -0
  47. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestAgenciesIntegration.test_get_agency +0 -0
  48. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestAgenciesIntegration.test_list_agencies +0 -0
  49. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_field_type_validation +0 -0
  50. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestBusinessTypesIntegration.test_business_type_parsing_consistency +0 -0
  51. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestBusinessTypesIntegration.test_list_business_types +0 -0
  52. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_combined_filters_work_together +0 -0
  53. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_contract_cursor_pagination +0 -0
  54. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_contract_data_object_parsing +0 -0
  55. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_contract_field_types +0 -0
  56. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[keyword-software] +0 -0
  57. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_filter_parameter_mappings[psc_code-R425] +0 -0
  58. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_awarding_agency_filter +0 -0
  59. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_date_range_filter +0 -0
  60. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_flat +0 -0
  61. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_naics_code_filter +0 -0
  62. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[custom-key,piid,recipient(display_name),total_contract_value,award_date] +0 -0
  63. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[default-None] +0 -0
  64. {tango_python-1.7.0 → tango_python-1.9.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
  65. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_list_contracts_with_shapes[minimal-key,piid,award_date,recipient(display_name),description,total_contract_value] +0 -0
  66. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_new_expiring_filters +0 -0
  67. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_new_fiscal_year_range_filters +0 -0
  68. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_new_identifier_filters +0 -0
  69. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_search_contracts_with_filters +0 -0
  70. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_search_filters_object_with_new_parameters +0 -0
  71. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[asc-] +0 -0
  72. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestContractsIntegration.test_sort_and_order_mapped_to_ordering[desc--] +0 -0
  73. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_contracts +0 -0
  74. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_api_schema_stability_detection_entities +0 -0
  75. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_date_field_parsing_edge_cases +0 -0
  76. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_decimal_field_parsing_edge_cases +0 -0
  77. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_empty_list_responses +0 -0
  78. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_entity_parsing_with_various_address_formats +0 -0
  79. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_flattened_responses_with_flat_lists +0 -0
  80. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_list_field_parsing_consistency +0 -0
  81. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_nested_objects_with_missing_data +0 -0
  82. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_null_missing_fields_in_contracts +0 -0
  83. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEdgeCasesIntegration.test_parsing_with_minimal_shape_sparse_data +0 -0
  84. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_entity_field_types +0 -0
  85. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_entity_location_parsing +0 -0
  86. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_entity_parsing_with_business_types +0 -0
  87. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_entity_with_various_identifiers +0 -0
  88. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_budget_flows +0 -0
  89. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_get_entity_by_uei +0 -0
  90. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_flat +0 -0
  91. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_search +0 -0
  92. {tango_python-1.7.0 → tango_python-1.9.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
  93. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[custom-uei,legal_business_name,cage_code] +0 -0
  94. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
  95. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestEntitiesIntegration.test_list_entities_with_shapes[with_address-uei,legal_business_name,cage_code,business_types,physical_address] +0 -0
  96. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestForecastsIntegration.test_forecast_field_types +0 -0
  97. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[custom-id,title,anticipated_award_date] +0 -0
  98. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[default-None] +0 -0
  99. {tango_python-1.7.0 → tango_python-1.9.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
  100. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestForecastsIntegration.test_list_forecasts_with_shapes[minimal-id,title,anticipated_award_date,fiscal_year,naics_code,status] +0 -0
  101. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestGrantsIntegration.test_grant_field_types +0 -0
  102. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestGrantsIntegration.test_grant_pagination +0 -0
  103. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[custom-grant_id,title,opportunity_number] +0 -0
  104. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[default-None] +0 -0
  105. {tango_python-1.7.0 → tango_python-1.9.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
  106. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestGrantsIntegration.test_list_grants_with_shapes[minimal-grant_id,opportunity_number,title,status(-),agency_code] +0 -0
  107. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestIDVsIntegration.test_get_idv_uses_default_shape +0 -0
  108. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_awards_uses_default_shape +0 -0
  109. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_child_idvs_uses_default_shape +0 -0
  110. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestIDVsIntegration.test_list_idv_transactions +0 -0
  111. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestIDVsIntegration.test_list_idvs_uses_default_shape_and_keyset_params +0 -0
  112. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_code +0 -0
  113. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_agency_name_text +0 -0
  114. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating +0 -0
  115. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_cio_rating_max +0 -0
  116. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_performance_risk +0 -0
  117. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_type_of_investment +0 -0
  118. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_filter_by_updated_time_range +0 -0
  119. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_funding_and_cio_evaluation_expansions +0 -0
  120. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_get_itdashboard_investment_by_uii +0 -0
  121. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_itdashboard_pagination +0 -0
  122. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_search +0 -0
  123. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[custom-uii,agency_name,investment_title,updated_time] +0 -0
  124. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestITDashboardIntegration.test_list_itdashboard_investments_with_shapes[default-None] +0 -0
  125. {tango_python-1.7.0 → tango_python-1.9.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
  126. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestNaicsIntegration.test_list_naics +0 -0
  127. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[custom-notice_id,title,solicitation_number] +0 -0
  128. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[default-None] +0 -0
  129. {tango_python-1.7.0 → tango_python-1.9.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
  130. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestNoticesIntegration.test_list_notices_with_shapes[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
  131. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestNoticesIntegration.test_notice_field_types +0 -0
  132. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestNoticesIntegration.test_notice_pagination +0 -0
  133. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestNoticesIntegration.test_notice_with_meta_fields +0 -0
  134. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOTAsIntegration.test_get_ota +0 -0
  135. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOTAsIntegration.test_list_otas +0 -0
  136. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOTIDVsIntegration.test_get_otidv +0 -0
  137. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOTIDVsIntegration.test_list_otidvs +0 -0
  138. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOfficesIntegration.test_get_office +0 -0
  139. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOfficesIntegration.test_list_offices +0 -0
  140. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[custom-opportunity_id,title,solicitation_number] +0 -0
  141. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[default-None] +0 -0
  142. {tango_python-1.7.0 → tango_python-1.9.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
  143. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOpportunitiesIntegration.test_list_opportunities_with_shapes[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
  144. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOpportunitiesIntegration.test_opportunity_field_types +0 -0
  145. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOrganizationsIntegration.test_get_organization +0 -0
  146. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestOrganizationsIntegration.test_list_organizations +0 -0
  147. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestProtestsIntegration.test_get_protest_by_case_id +0 -0
  148. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_filter +0 -0
  149. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[custom-case_id,title,source_system,outcome] +0 -0
  150. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[default-None] +0 -0
  151. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestProtestsIntegration.test_list_protests_with_shapes[minimal-case_id,case_number,title,source_system,outcome,filed_date] +0 -0
  152. {tango_python-1.7.0 → tango_python-1.9.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
  153. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestProtestsIntegration.test_protest_pagination +0 -0
  154. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestSubawardsIntegration.test_list_subawards +0 -0
  155. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[custom-key,piid,description] +0 -0
  156. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[minimal-key,piid,award_date,recipient(display_name),description,total_contract_value] +0 -0
  157. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestTypeHintsIntegration.test_contracts_dict_access[ultra_minimal-key,piid,recipient(display_name),total_contract_value] +0 -0
  158. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[minimal-uei,legal_business_name,cage_code,business_types] +0 -0
  159. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestTypeHintsIntegration.test_entities_dict_access[with_address-uei,legal_business_name,cage_code,business_types,physical_address] +0 -0
  160. {tango_python-1.7.0 → tango_python-1.9.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
  161. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestTypeHintsIntegration.test_notices_dict_access[minimal-notice_id,title,solicitation_number,posted_date] +0 -0
  162. {tango_python-1.7.0 → tango_python-1.9.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
  163. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestTypeHintsIntegration.test_opportunities_dict_access[minimal-opportunity_id,title,solicitation_number,response_deadline,active] +0 -0
  164. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_supports_joiner_and_flat_lists +0 -0
  165. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestVehiclesIntegration.test_get_vehicle_with_metrics_expansion +0 -0
  166. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_awardees_uses_default_shape +0 -0
  167. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicle_orders_uses_default_shape +0 -0
  168. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_uses_default_shape_and_search +0 -0
  169. {tango_python-1.7.0 → tango_python-1.9.0}/tests/cassettes/TestVehiclesIntegration.test_list_vehicles_with_ordering +0 -0
  170. {tango_python-1.7.0 → tango_python-1.9.0}/tests/conftest.py +0 -0
  171. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/README.md +0 -0
  172. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/__init__.py +0 -0
  173. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/conftest.py +0 -0
  174. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_agencies_integration.py +0 -0
  175. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_contracts_integration.py +0 -0
  176. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_edge_cases_integration.py +0 -0
  177. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_entities_integration.py +0 -0
  178. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_forecasts_integration.py +0 -0
  179. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_grants_integration.py +0 -0
  180. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_itdashboard_integration.py +0 -0
  181. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_naics_integration.py +0 -0
  182. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_notices_integration.py +0 -0
  183. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_offices_integration.py +0 -0
  184. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_opportunities_integration.py +0 -0
  185. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_organizations_integration.py +0 -0
  186. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_otas_otidvs_integration.py +0 -0
  187. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_protests_integration.py +0 -0
  188. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_reference_data_integration.py +0 -0
  189. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_subawards_integration.py +0 -0
  190. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/test_vehicles_idvs_integration.py +0 -0
  191. {tango_python-1.7.0 → tango_python-1.9.0}/tests/integration/validation.py +0 -0
  192. {tango_python-1.7.0 → tango_python-1.9.0}/tests/production/__init__.py +0 -0
  193. {tango_python-1.7.0 → tango_python-1.9.0}/tests/production/conftest.py +0 -0
  194. {tango_python-1.7.0 → tango_python-1.9.0}/tests/production/test_production_smoke.py +0 -0
  195. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_api_parity.py +0 -0
  196. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_client.py +0 -0
  197. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_contract_appeals.py +0 -0
  198. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_dibbs_exclusions_sbir.py +0 -0
  199. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_models.py +0 -0
  200. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_opportunity_attachments.py +0 -0
  201. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_shape_coverage_gate.py +0 -0
  202. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_shapes.py +0 -0
  203. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_sled.py +0 -0
  204. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_webhooks_cli.py +0 -0
  205. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_webhooks_receiver.py +0 -0
  206. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_webhooks_signing.py +0 -0
  207. {tango_python-1.7.0 → tango_python-1.9.0}/tests/test_webhooks_simulate.py +0 -0
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.9.0] - 2026-09-28
11
+
12
+ ### Added
13
+ - **GSA eBuy requests** (Tango API 5.1.0). Four methods over the `/api/ebuy/` resource: `list_ebuy_requests()`, `get_ebuy_request()`, `get_ebuy_attachment_url()` and `get_ebuy_access()`, plus `EbuyRequest` / `EbuyAttachment` schemas, an `EbuyAccess` result type, and the `EBUY_REQUESTS_MINIMAL` / `EBUY_REQUESTS_COMPREHENSIVE` defaults. These are the RFQs, RFPs and RFIs posted to GSA eBuy. All fourteen of the API's filters are explicit named parameters, including `search` (which also matches attachment text), `reference_number`, `sin`, `agency` and `contract_number`.
14
+
15
+ Access is scoped to your account: you see only requests posted under the GSA schedule contracts linked to it, and the endpoints require the Pro tier or above. With no linked contract, `list_ebuy_requests()` returns an empty page rather than an error, so `get_ebuy_access()` reports whether access is enabled, why not (`tier_required` or `no_contract_grant`), and which contracts are linked. `status` is frozen at the last state a request was seen in, because a request that closes stops appearing rather than getting a final row; read `last_seen` for staleness. `get_ebuy_attachment_url()` returns the short-lived signed URL the API redirects to without downloading the document, and raises the new `TangoAttachmentLinkError` (a `TangoValidationError`) with the link on `.url` when the entry is an external link rather than a stored document. The `agency` filter requires Tango API 5.3.0.
16
+ - **`alerts.ebuy_request.match` is an alertable event type.** `create_webhook_alert(query_type="ebuy_request", ...)` works.
17
+
18
+ ## [1.8.0] - 2026-09-28
19
+
20
+ ### Added
21
+ - **Federal Register documents** (Tango API 5.3.0). Two methods over the new `/api/federal_register/` resource: `list_federal_register_documents()` and `get_federal_register_document()`, plus a `FederalRegisterDocument` schema and the `FEDERAL_REGISTER_MINIMAL` / `FEDERAL_REGISTER_COMPREHENSIVE` defaults. These are the rules, proposed rules, notices and presidential documents published in the Federal Register since 1994. All seventeen of the API's filters are explicit named parameters, including `comments_open`, `cfr_title` / `cfr_part`, `rin`, and both `agency` (a Tango organization, including its sub-agencies) and `fr_agency` (the Federal Register's own agency slug).
22
+
23
+ `get_federal_register_document()` takes the document's `uuid`, not its `document_number`, because a document number is not unique on its own: the Federal Register reused some before 2016. Look a document up by number with `list_federal_register_documents(document_number=...)`. `full_text` is available on the detail method only when named in `shape`, and neither default shape includes it, since it can run to several MB. `ordering="rank"` requires a non-empty `search`, matching the API.
24
+ - **`alerts.federal_register.match` is an alertable event type.** `create_webhook_alert(query_type="federal_register", ...)` works.
25
+ - **`agency` filter on `list_budget_accounts()`, `list_exclusions()` and `list_itdashboard_investments()`** (Tango API 5.3.0). It takes a Tango agency name, abbreviation, code or organization key (e.g. `EPA`) and matches the whole organization subtree, so a department includes its sub-agencies; OR several with `|`. On exclusions it scopes by the excluding agency. On IT Dashboard it is available at every plan.
26
+ - **The `organization` expand is accepted on budget accounts, exclusions, SBIR topics and SBIR solicitations**, along with the `organization_id` field on budget accounts and exclusions. `organization(...)` carries `agency_code`, `agency_name`, `department_code`, `department_name`, `office_code`, `office_name` and `organization_id`. The SDK rejected these shapes client-side before. The default shapes are unchanged.
27
+
28
+ ### Fixed
29
+ - **`list_itdashboard_investments()` documents the API's current filter tiers.** `agency_name` is available at every plan, not Business+ only.
30
+
10
31
  ## [1.7.0] - 2026-09-23
11
32
 
12
33
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tango-python
3
- Version: 1.7.0
3
+ Version: 1.9.0
4
4
  Summary: Python SDK for the Tango API
5
5
  Project-URL: Homepage, https://github.com/makegov/tango-python
6
6
  Project-URL: Documentation, https://docs.makegov.com/tango-python
@@ -308,6 +308,15 @@ protests = client.list_protests(source_system="gao", outcome="Sustained", limit=
308
308
  protest = client.get_protest("CASE_UUID")
309
309
  ```
310
310
 
311
+ ### GSA eBuy
312
+
313
+ ```python
314
+ access = client.get_ebuy_access() # scoped to the schedule contracts linked to your account
315
+ requests = client.list_ebuy_requests(status="Open", sin="54151S", limit=25)
316
+ request = client.get_ebuy_request("RFQ1835158")
317
+ url = client.get_ebuy_attachment_url("RFQ1835158", doc_seq_num=1) # short-lived signed URL
318
+ ```
319
+
311
320
  ### GSA eLibrary Contracts
312
321
 
313
322
  ```python
@@ -254,6 +254,15 @@ protests = client.list_protests(source_system="gao", outcome="Sustained", limit=
254
254
  protest = client.get_protest("CASE_UUID")
255
255
  ```
256
256
 
257
+ ### GSA eBuy
258
+
259
+ ```python
260
+ access = client.get_ebuy_access() # scoped to the schedule contracts linked to your account
261
+ requests = client.list_ebuy_requests(status="Open", sin="54151S", limit=25)
262
+ request = client.get_ebuy_request("RFQ1835158")
263
+ url = client.get_ebuy_attachment_url("RFQ1835158", doc_seq_num=1) # short-lived signed URL
264
+ ```
265
+
257
266
  ### GSA eLibrary Contracts
258
267
 
259
268
  ```python
@@ -23,6 +23,8 @@ Complete reference for all Tango Python SDK methods and functionality.
23
23
  - [GSA eLibrary Contracts](#gsa-elibrary-contracts)
24
24
  - [Protests](#protests)
25
25
  - [Contract Appeals](#contract-appeals)
26
+ - [Federal Register](#federal-register)
27
+ - [GSA eBuy](#gsa-ebuy)
26
28
  - [Budget](#budget)
27
29
  - [Business Types](#business-types)
28
30
  - [NAICS](#naics)
@@ -1315,6 +1317,93 @@ appeal = client.get_contract_appeal(
1315
1317
 
1316
1318
  ---
1317
1319
 
1320
+ ## Federal Register
1321
+
1322
+ Federal Register documents — rules, proposed rules, notices and presidential documents published since 1994.
1323
+
1324
+ A document is identified by `uuid`. `document_number` is not unique on its own: the Federal Register reused some numbers before 2016, so `document_number=` can return more than one document.
1325
+
1326
+ ### list_federal_register_documents()
1327
+
1328
+ List documents with filtering and shaping.
1329
+
1330
+ ```python
1331
+ documents = client.list_federal_register_documents(
1332
+ page=1,
1333
+ limit=25,
1334
+ shape=ShapeConfig.FEDERAL_REGISTER_MINIMAL,
1335
+ # Filter parameters (all optional)
1336
+ search=None,
1337
+ document_number=None,
1338
+ type=None,
1339
+ agency=None,
1340
+ fr_agency=None,
1341
+ publication_date_after=None,
1342
+ publication_date_before=None,
1343
+ effective_on_after=None,
1344
+ effective_on_before=None,
1345
+ comments_close_on_after=None,
1346
+ comments_close_on_before=None,
1347
+ comments_open=None,
1348
+ cfr_title=None,
1349
+ cfr_part=None,
1350
+ significant=None,
1351
+ rin=None,
1352
+ executive_order_number=None,
1353
+ ordering=None,
1354
+ )
1355
+ ```
1356
+
1357
+ **Filter Parameters:**
1358
+ - `search` - Ranked full-text search over the title, abstract and action; wrap in double quotes for a phrase
1359
+ - `document_number` - Exact FR document number, e.g. `"2016-31922"`; OR several with `|`
1360
+ - `type` - `"Notice"`, `"Rule"`, `"Proposed Rule"`, `"Presidential Document"`, `"Correction"`, `"Sunshine Act Document"` or `"Uncategorized Document"` (case-insensitive); OR several with `|`. An unknown type is an error, not an empty page. Documents published before 2008 are mostly `Uncategorized Document`, so a type filter undercounts that era
1361
+ - `agency` - A Tango agency name, abbreviation, code or organization key, e.g. `"EPA"`. Matches a document when any agency it lists falls within that organization, so a department includes its sub-agencies; OR several with `|`
1362
+ - `fr_agency` - The Federal Register's own agency slug, e.g. `"environmental-protection-agency"`; OR several with `|`
1363
+ - `publication_date_after` / `publication_date_before` - Publication date range (`YYYY-MM-DD`)
1364
+ - `effective_on_after` / `effective_on_before` - Effective date range (`YYYY-MM-DD`)
1365
+ - `comments_close_on_after` / `comments_close_on_before` - Comment-deadline range (`YYYY-MM-DD`)
1366
+ - `comments_open` - `True` for documents whose comment period closes today or later, `False` for those already closed; documents with no comment deadline match neither
1367
+ - `cfr_title` - A CFR title number, e.g. `"40"`
1368
+ - `cfr_part` - A CFR part number, e.g. `"52"`. Requires `cfr_title`, and both must match the same CFR reference, so `cfr_title="40", cfr_part="52"` finds 40 CFR 52
1369
+ - `significant` - Significant under Executive Order 12866
1370
+ - `rin` - A Regulation Identifier Number, e.g. `"2060-AV16"`; OR several with `|`
1371
+ - `executive_order_number` - Exact executive order number
1372
+ - `ordering` - `publication_date` (the default, as `-publication_date`), `effective_on`, `comments_close_on`, `document_number` or `rank`. `rank` requires a non-empty `search`
1373
+
1374
+ **Returns:** [PaginatedResponse](#paginatedresponse) with document dictionaries
1375
+
1376
+ **Example:**
1377
+ ```python
1378
+ documents = client.list_federal_register_documents(
1379
+ type="Proposed Rule",
1380
+ comments_open=True,
1381
+ agency="EPA",
1382
+ limit=25,
1383
+ )
1384
+
1385
+ for doc in documents.results:
1386
+ print(f"{doc['document_number']} ({doc['publication_date']}): {doc['title']}")
1387
+ print(f" comments close {doc['comments_close_on']}")
1388
+ ```
1389
+
1390
+ ### get_federal_register_document()
1391
+
1392
+ Get a single document by `uuid`. To look one up by its document number, use `list_federal_register_documents(document_number=...)`.
1393
+
1394
+ ```python
1395
+ document = client.get_federal_register_document(
1396
+ "DOCUMENT_UUID",
1397
+ shape=ShapeConfig.FEDERAL_REGISTER_COMPREHENSIVE,
1398
+ )
1399
+ ```
1400
+
1401
+ **Notes:**
1402
+ - `agencies`, `cfr_references`, `dockets` and `topics` are the Federal Register's own structures, served as published. `agencies` carries Federal Register agency slugs, not Tango organization keys.
1403
+ - `full_text`, the document's plain text, is available on this method only and only when named in `shape` (e.g. `shape="uuid,title,full_text"`). It can run to several MB, so neither default shape includes it.
1404
+
1405
+ ---
1406
+
1318
1407
  ## State & Local (SLED)
1319
1408
 
1320
1409
  State, local and education procurement — solicitations that never appear on SAM.gov because they were never federal. **Beta**: coverage is partial and grows one jurisdiction at a time.
@@ -1514,6 +1603,118 @@ forecast = client.get_sled_forecast("FORECAST_UUID")
1514
1603
 
1515
1604
  ---
1516
1605
 
1606
+ ## GSA eBuy
1607
+
1608
+ GSA eBuy requests for quotes, proposals and information (RFQs, RFPs, RFIs), keyed by `rfq_id`.
1609
+
1610
+ **Access is scoped to your account.** You see only requests posted under the GSA schedule contracts linked to your account, and the endpoints require the Pro tier or above (below it they return 403). With no linked contract, `list_ebuy_requests()` returns an empty page rather than an error, and `get_ebuy_request()` raises `TangoNotFoundError` for a request outside your scope, the same as for an id that does not exist. Use `get_ebuy_access()` to tell "no access" from "no matches".
1611
+
1612
+ ### list_ebuy_requests()
1613
+
1614
+ List requests with filtering and shaping.
1615
+
1616
+ ```python
1617
+ requests = client.list_ebuy_requests(
1618
+ page=1,
1619
+ limit=25,
1620
+ shape=ShapeConfig.EBUY_REQUESTS_MINIMAL,
1621
+ # Filter parameters (all optional)
1622
+ search=None,
1623
+ rfq_id=None,
1624
+ reference_number=None,
1625
+ request_type=None,
1626
+ status=None,
1627
+ sin=None,
1628
+ schedule=None,
1629
+ buyer_agency=None,
1630
+ agency=None,
1631
+ contract_number=None,
1632
+ issue_date_after=None,
1633
+ issue_date_before=None,
1634
+ close_date_after=None,
1635
+ close_date_before=None,
1636
+ ordering=None,
1637
+ )
1638
+ ```
1639
+
1640
+ **Filter Parameters:**
1641
+ - `search` - Full-text search over the title, description, reference number, request id and attachment text. Results rank by relevance unless `ordering` is given
1642
+ - `rfq_id` - Exact request id, e.g. `"RFQ1835158"`
1643
+ - `reference_number` - The buyer's own solicitation number; dashes are ignored
1644
+ - `request_type` - `"RFQ"`, `"RFP"` or `"RFI"`
1645
+ - `status` - `"Open"` or `"Cancelled"`, as last seen (see the note below)
1646
+ - `sin` - Special Item Number, e.g. `"54151S"`
1647
+ - `schedule` - GSA schedule
1648
+ - `buyer_agency` - The buyer agency as eBuy names it (free text)
1649
+ - `agency` - A Tango agency name, abbreviation, code or organization key, e.g. `"GSA"`. Matches the whole organization subtree, so a department includes its sub-agencies. Requires Tango API 5.3.0
1650
+ - `contract_number` - Narrow to requests posted under one of your own linked contracts. A contract not linked to your account returns an empty page, not an error
1651
+ - `issue_date_after` / `issue_date_before` - Issue date range (`YYYY-MM-DD`, inclusive)
1652
+ - `close_date_after` / `close_date_before` - Close date range (`YYYY-MM-DD`, inclusive)
1653
+ - `ordering` - `issue_date` (the default, as `-issue_date`), `close_date`, `last_seen` or `modified`; prefix `-` for descending
1654
+
1655
+ String filters accept several values joined with `|` (OR).
1656
+
1657
+ **Returns:** [PaginatedResponse](#paginatedresponse) with request dictionaries
1658
+
1659
+ **Example:**
1660
+ ```python
1661
+ requests = client.list_ebuy_requests(status="Open", sin="54151S", ordering="close_date")
1662
+
1663
+ for req in requests.results:
1664
+ print(f"{req['rfq_id']} closes {req['close_date']}: {req['title']}")
1665
+ print(f" last seen {req['last_seen']}")
1666
+ ```
1667
+
1668
+ **Notes:**
1669
+ - **`status` is frozen at the last state the request was seen in.** Only currently-active requests are carried, so a request that closes stops appearing rather than getting a final row. `Open` means "open the last time it was seen", not "open now"; read `last_seen` for staleness.
1670
+ - The contract number a request was posted under is never returned in any payload.
1671
+ - `buyer_agency_code` and some other buyer and contact fields are sparse on older requests.
1672
+
1673
+ ### get_ebuy_request()
1674
+
1675
+ Get a single request by `rfq_id`.
1676
+
1677
+ ```python
1678
+ request = client.get_ebuy_request(
1679
+ "RFQ1835158",
1680
+ shape=ShapeConfig.EBUY_REQUESTS_COMPREHENSIVE,
1681
+ )
1682
+
1683
+ for attachment in request["attachments"]:
1684
+ print(attachment["doc_seq_num"], attachment["doc_name"], attachment["is_link"])
1685
+ ```
1686
+
1687
+ The default shape returns every field plus two expands: `organization` (the buyer office, with the same seven keys as other resources' `organization` expand) and `attachments`. Each attachment carries `doc_seq_num`, `doc_name`, `doc_type`, `doc_path`, `is_link` and `doc_session_date`. `is_link=True` means `doc_path` is an outbound URL with no stored document behind it. `amendments`, `line_items` and `addresses` are lists of objects, served as eBuy publishes them.
1688
+
1689
+ ### get_ebuy_attachment_url()
1690
+
1691
+ Get a short-lived download URL for one stored attachment.
1692
+
1693
+ ```python
1694
+ url = client.get_ebuy_attachment_url("RFQ1835158", doc_seq_num=1)
1695
+ ```
1696
+
1697
+ **Returns:** The signed URL the API redirects to, as a string. The SDK reads the redirect without following it, so no document is downloaded. The URL expires after about five minutes: fetch it promptly, and call this again rather than storing it.
1698
+
1699
+ **Raises:**
1700
+ - `TangoAttachmentLinkError` (a `TangoValidationError`) - The entry is an external link (`is_link`), not a stored document. The link is on `error.url`
1701
+ - `TangoNotFoundError` - The request is unknown or outside your scope, the attachment does not exist, or its document has not been captured yet
1702
+
1703
+ ### get_ebuy_access()
1704
+
1705
+ Check whether your account can read eBuy requests.
1706
+
1707
+ ```python
1708
+ access = client.get_ebuy_access()
1709
+ if not access.enabled:
1710
+ print(access.reason) # "tier_required" or "no_contract_grant"
1711
+ print(access.contracts) # your own linked contracts, sorted
1712
+ ```
1713
+
1714
+ **Returns:** `EbuyAccess` with `enabled` (bool), `reason` (`"tier_required"`, `"no_contract_grant"` or `None`; `tier_required` wins when both apply) and `contracts` (list of str).
1715
+
1716
+ ---
1717
+
1517
1718
  ## Budget
1518
1719
 
1519
1720
  Federal account × fiscal year budget rollups, covering the full budget lifecycle (requested → enacted → apportioned → obligated → outlayed), pre-computed ratios and trends, the contract / assistance / unlinked breakdown, and request-vs-actual spend.
@@ -2311,6 +2512,10 @@ entity = client.get_entity("UEI_KEY", shape=ShapeConfig.ENTITIES_COMPREHENSIVE)
2311
2512
  | `PROTESTS_MINIMAL` | `list_protests` | case_id, case_number, title, source_system, outcome, filed_date |
2312
2513
  | `CONTRACT_APPEALS_MINIMAL` | `list_contract_appeals` | uuid, board, docket_numbers, decision_date, appellant, judge, decision_type, url |
2313
2514
  | `CONTRACT_APPEALS_COMPREHENSIVE` | `get_contract_appeal` | The list fields plus docket_raw, docket_source, decision_date_repaired, decision_type_raw, listing_year, first_listed_at, listed, text_status, text_char_count (omits `decision_text`, which needs an Enterprise plan) |
2515
+ | `FEDERAL_REGISTER_MINIMAL` | `list_federal_register_documents` | uuid, document_number, publication_date, type, subtype, title, abstract, action, agencies, cfr_references, citation, significant, comments_close_on, effective_on, html_url, pdf_url |
2516
+ | `FEDERAL_REGISTER_COMPREHENSIVE` | `get_federal_register_document` | The list fields plus dates, signing_date, start_page, end_page, volume, docket_ids, dockets, regulation_id_numbers, topics, correction_of, corrections, executive_order_number, presidential_document_number, proclamation_number, comment_url, regulations_dot_gov_url, raw_text_url, body_html_url (omits `full_text`) |
2517
+ | `EBUY_REQUESTS_MINIMAL` | `list_ebuy_requests` | rfq_id, request_type, title, schedule, sin, status, buyer_name, buyer_agency, buyer_agency_code, reference_number, issue_date, close_date, attachment_count, link_count, last_seen |
2518
+ | `EBUY_REQUESTS_COMPREHENSIVE` | `get_ebuy_request` | Every field, plus the `organization` and `attachments` expands |
2314
2519
  | `BUDGET_ACCOUNTS_MINIMAL` | `list_budget_accounts`, `get_budget_account` | id, federal_account_symbol, fiscal_year, agency_code/name, bureau_name, account_title, bea_category, on_off_budget, subfunction_code, lifecycle (requested/enacted/apportioned/obligated/outlayed/unobligated), contract & assistance rollups, key ratios, next-year growth |
2315
2520
  | `VEHICLE_ORDERS_MINIMAL` | `list_vehicle_orders` | key, piid, award_date, recipient(display_name,uei), total_contract_value, obligated |
2316
2521
  | `ITDASHBOARD_INVESTMENTS_MINIMAL` | `list_itdashboard_investments` | Minimal IT Dashboard investment fields |
@@ -89,6 +89,8 @@ tango webhooks list-event-types
89
89
  # alerts.dibbs_rfp.match DLA DIBBS RFP matched a saved alert
90
90
  # alerts.sled_opportunity.match State/local/education solicitation matched a saved alert
91
91
  # alerts.contract_appeal.match CBCA/ASBCA appeal decision matched a saved alert
92
+ # alerts.federal_register.match Federal Register document matched a saved alert
93
+ # alerts.ebuy_request.match GSA eBuy request matched a saved alert
92
94
  ```
93
95
 
94
96
  This list is served by the API, so it is always current — the SDK does not hardcode
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tango-python"
7
- version = "1.7.0"
7
+ version = "1.9.0"
8
8
  description = "Python SDK for the Tango API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -78,6 +78,8 @@ RESOURCE_TO_METHOD: dict[str, str | None] = {
78
78
  "sled/forecasts": "list_sled_forecasts",
79
79
  "protests": "list_protests",
80
80
  "contract_appeals": "list_contract_appeals",
81
+ "federal_register": "list_federal_register_documents",
82
+ "ebuy/requests": "list_ebuy_requests",
81
83
  "offices": "list_offices",
82
84
  "psc": "list_psc",
83
85
  "mas_sins": "list_mas_sins",
@@ -69,6 +69,8 @@ RESOURCE_TO_MODEL: dict[str, str] = {
69
69
  "budget_accounts": "BudgetAccount",
70
70
  "protests": "Protest",
71
71
  "contract_appeals": "ContractAppeal",
72
+ "federal_register": "FederalRegisterDocument",
73
+ "ebuy/requests": "EbuyRequest",
72
74
  "offices": "Office",
73
75
  "assistance_listings": "AssistanceListing",
74
76
  "business_types": "BusinessType",
@@ -3,6 +3,7 @@
3
3
  from .client import TangoClient
4
4
  from .exceptions import (
5
5
  TangoAPIError,
6
+ TangoAttachmentLinkError,
6
7
  TangoAuthError,
7
8
  TangoNotFoundError,
8
9
  TangoRateLimitError,
@@ -14,7 +15,11 @@ from .models import (
14
15
  DibbsAward,
15
16
  DibbsRfp,
16
17
  DibbsRfq,
18
+ EbuyAccess,
19
+ EbuyAttachment,
20
+ EbuyRequest,
17
21
  Exclusion,
22
+ FederalRegisterDocument,
18
23
  GsaElibraryContract,
19
24
  ITDashboardInvestment,
20
25
  PaginatedResponse,
@@ -54,19 +59,24 @@ from .webhooks import (
54
59
  )
55
60
  from .webhooks.receiver import Delivery, WebhookReceiver
56
61
 
57
- __version__ = "1.7.0"
62
+ __version__ = "1.9.0"
58
63
  __all__ = [
59
64
  "TangoClient",
60
65
  "TangoAPIError",
61
66
  "TangoAuthError",
62
67
  "TangoNotFoundError",
63
68
  "TangoValidationError",
69
+ "TangoAttachmentLinkError",
64
70
  "TangoRateLimitError",
65
71
  "RateLimitInfo",
66
72
  "ResolveCandidate",
67
73
  "ResolveResult",
68
74
  "BudgetAccount",
69
75
  "ContractAppeal",
76
+ "FederalRegisterDocument",
77
+ "EbuyAccess",
78
+ "EbuyAttachment",
79
+ "EbuyRequest",
70
80
  "DibbsAward",
71
81
  "DibbsRfp",
72
82
  "DibbsRfq",