usaspending-orm 0.7.0__tar.gz → 0.7.3__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 (218) hide show
  1. usaspending_orm-0.7.3/.gitignore +6 -0
  2. usaspending_orm-0.7.3/CHANGELOG.md +81 -0
  3. usaspending_orm-0.7.3/CLAUDE.md +243 -0
  4. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/PKG-INFO +196 -42
  5. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/README.md +185 -30
  6. usaspending_orm-0.7.3/api-docs-links.md +258 -0
  7. usaspending_orm-0.7.3/poetry.lock +585 -0
  8. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/pyproject.toml +49 -12
  9. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/__init__.py +69 -67
  10. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/cli/download_award.py +4 -7
  11. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/client.py +204 -82
  12. usaspending_orm-0.7.3/src/usaspending/config.py +210 -0
  13. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/download/__init__.py +2 -2
  14. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/download/job.py +33 -32
  15. usaspending_orm-0.7.3/src/usaspending/download/manager.py +248 -0
  16. usaspending_orm-0.7.3/src/usaspending/exceptions.py +295 -0
  17. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/logging_config.py +16 -22
  18. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/__init__.py +58 -51
  19. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/agency.py +107 -71
  20. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/award.py +115 -133
  21. usaspending_orm-0.7.3/src/usaspending/models/award_account.py +203 -0
  22. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/award_factory.py +11 -30
  23. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/award_types.py +58 -27
  24. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/base_model.py +39 -34
  25. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/contract.py +27 -26
  26. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/district_spending.py +5 -5
  27. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/download.py +12 -11
  28. usaspending_orm-0.7.3/src/usaspending/models/federal_account.py +136 -0
  29. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/funding.py +100 -51
  30. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/grant.py +28 -23
  31. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/idv.py +65 -29
  32. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/lazy_record.py +14 -29
  33. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/loan.py +17 -19
  34. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/location.py +30 -39
  35. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/period_of_performance.py +13 -17
  36. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/recipient.py +26 -32
  37. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/recipient_business_categories.py +5 -12
  38. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/recipient_spending.py +9 -8
  39. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/spending.py +10 -9
  40. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/state_spending.py +4 -4
  41. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/subaward.py +37 -37
  42. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/subtier_agency.py +11 -12
  43. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/transaction.py +5 -4
  44. usaspending_orm-0.7.3/src/usaspending/models/treasury_account_symbol.py +258 -0
  45. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/__init__.py +51 -37
  46. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/agencies_search.py +83 -20
  47. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/agency_award_summary.py +12 -12
  48. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/agency_query.py +11 -13
  49. usaspending_orm-0.7.3/src/usaspending/queries/award_accounts_query.py +194 -0
  50. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/award_query.py +7 -4
  51. usaspending_orm-0.7.3/src/usaspending/queries/awarding_agencies_search.py +52 -0
  52. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/awards_search.py +76 -80
  53. usaspending_orm-0.7.3/src/usaspending/queries/base_query.py +141 -0
  54. usaspending_orm-0.7.3/src/usaspending/queries/client_side_query_builder.py +309 -0
  55. usaspending_orm-0.7.3/src/usaspending/queries/federal_accounts_query.py +205 -0
  56. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/filters.py +21 -71
  57. usaspending_orm-0.7.3/src/usaspending/queries/funding_agencies_search.py +52 -0
  58. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/funding_search.py +12 -18
  59. usaspending_orm-0.7.3/src/usaspending/queries/idv_child_awards.py +188 -0
  60. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/query_builder.py +199 -300
  61. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/recipient_query.py +21 -24
  62. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/recipients_search.py +10 -10
  63. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/single_resource_base.py +23 -15
  64. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/spending_search.py +17 -28
  65. usaspending_orm-0.7.3/src/usaspending/queries/sub_agency_query.py +210 -0
  66. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/subawards_search.py +32 -30
  67. usaspending_orm-0.7.3/src/usaspending/queries/tas_codes_query.py +213 -0
  68. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/transactions_search.py +62 -47
  69. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/__init__.py +14 -8
  70. usaspending_orm-0.7.3/src/usaspending/resources/agency_resource.py +203 -0
  71. usaspending_orm-0.7.3/src/usaspending/resources/award_accounts_resource.py +41 -0
  72. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/award_resource.py +12 -15
  73. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/base_resource.py +1 -0
  74. usaspending_orm-0.7.3/src/usaspending/resources/download_resource.py +179 -0
  75. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/funding_resource.py +7 -4
  76. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/recipients_resource.py +16 -13
  77. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/spending_resource.py +3 -2
  78. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/subawards_resource.py +4 -3
  79. usaspending_orm-0.7.3/src/usaspending/resources/tas_resource.py +77 -0
  80. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/transactions_resource.py +3 -2
  81. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/formatter.py +53 -154
  82. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/rate_limit.py +7 -10
  83. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/retry.py +22 -29
  84. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/validations.py +32 -7
  85. usaspending_orm-0.7.3/tests/__init__.py +0 -0
  86. usaspending_orm-0.7.3/tests/conftest.py +202 -0
  87. usaspending_orm-0.7.3/tests/fixtures/agency.json +79 -0
  88. usaspending_orm-0.7.3/tests/fixtures/agency_autocomplete.json +387 -0
  89. usaspending_orm-0.7.3/tests/fixtures/agency_award_summary.json +8 -0
  90. usaspending_orm-0.7.3/tests/fixtures/agency_subagencies.json +116 -0
  91. usaspending_orm-0.7.3/tests/fixtures/awards/accounts.json +32 -0
  92. usaspending_orm-0.7.3/tests/fixtures/awards/award_funding_grant.json +241 -0
  93. usaspending_orm-0.7.3/tests/fixtures/awards/contract.json +247 -0
  94. usaspending_orm-0.7.3/tests/fixtures/awards/grant.json +180 -0
  95. usaspending_orm-0.7.3/tests/fixtures/awards/idv.json +241 -0
  96. usaspending_orm-0.7.3/tests/fixtures/awards/idv_awards.json +181 -0
  97. usaspending_orm-0.7.3/tests/fixtures/awards/loan.json +140 -0
  98. usaspending_orm-0.7.3/tests/fixtures/awards/search_results_contracts.json +376 -0
  99. usaspending_orm-0.7.3/tests/fixtures/awards/search_results_grants.json +259 -0
  100. usaspending_orm-0.7.3/tests/fixtures/awards/search_results_idvs.json +258 -0
  101. usaspending_orm-0.7.3/tests/fixtures/awards/search_results_subawards.json +177 -0
  102. usaspending_orm-0.7.3/tests/fixtures/awards/transactions.json +50 -0
  103. usaspending_orm-0.7.3/tests/fixtures/download_assistance.json +42 -0
  104. usaspending_orm-0.7.3/tests/fixtures/download_search.json +42 -0
  105. usaspending_orm-0.7.3/tests/fixtures/download_status.json +10 -0
  106. usaspending_orm-0.7.3/tests/fixtures/recipient_university.json +75 -0
  107. usaspending_orm-0.7.3/tests/fixtures/recipients_search.json +45 -0
  108. usaspending_orm-0.7.3/tests/fixtures/spending_by_award_contracts.json +141 -0
  109. usaspending_orm-0.7.3/tests/fixtures/spending_by_district.json +88 -0
  110. usaspending_orm-0.7.3/tests/fixtures/spending_by_recipient.json +178 -0
  111. usaspending_orm-0.7.3/tests/fixtures/spending_by_state.json +25 -0
  112. usaspending_orm-0.7.3/tests/fixtures/tas_agencies.json +641 -0
  113. usaspending_orm-0.7.3/tests/fixtures/tas_codes.json +164 -0
  114. usaspending_orm-0.7.3/tests/fixtures/tas_federal_accounts.json +148 -0
  115. usaspending_orm-0.7.3/tests/fixtures/top_recipients_params.json +26 -0
  116. usaspending_orm-0.7.3/tests/fixtures/top_recipients_response.json +98 -0
  117. usaspending_orm-0.7.3/tests/mocks/README.md +320 -0
  118. usaspending_orm-0.7.3/tests/mocks/__init__.py +6 -0
  119. usaspending_orm-0.7.3/tests/mocks/mock_client.py +759 -0
  120. usaspending_orm-0.7.3/tests/mocks/response_builder.py +188 -0
  121. usaspending_orm-0.7.3/tests/mocks/test_mock_client.py +275 -0
  122. usaspending_orm-0.7.3/tests/models/__init__.py +1 -0
  123. usaspending_orm-0.7.3/tests/models/test_agency.py +376 -0
  124. usaspending_orm-0.7.3/tests/models/test_agency_subagencies.py +231 -0
  125. usaspending_orm-0.7.3/tests/models/test_agency_tas_integration.py +172 -0
  126. usaspending_orm-0.7.3/tests/models/test_award_account.py +282 -0
  127. usaspending_orm-0.7.3/tests/models/test_award_agency_integration.py +264 -0
  128. usaspending_orm-0.7.3/tests/models/test_award_common.py +266 -0
  129. usaspending_orm-0.7.3/tests/models/test_award_decimal_precision.py +160 -0
  130. usaspending_orm-0.7.3/tests/models/test_award_factory.py +235 -0
  131. usaspending_orm-0.7.3/tests/models/test_award_lazy_loading.py +225 -0
  132. usaspending_orm-0.7.3/tests/models/test_award_office_integration.py +172 -0
  133. usaspending_orm-0.7.3/tests/models/test_award_type_constants.py +442 -0
  134. usaspending_orm-0.7.3/tests/models/test_award_types.py +280 -0
  135. usaspending_orm-0.7.3/tests/models/test_base_model.py +623 -0
  136. usaspending_orm-0.7.3/tests/models/test_district_spending.py +146 -0
  137. usaspending_orm-0.7.3/tests/models/test_federal_account.py +159 -0
  138. usaspending_orm-0.7.3/tests/models/test_funding.py +422 -0
  139. usaspending_orm-0.7.3/tests/models/test_lazy_load.py +233 -0
  140. usaspending_orm-0.7.3/tests/models/test_location.py +284 -0
  141. usaspending_orm-0.7.3/tests/models/test_period_of_performance.py +213 -0
  142. usaspending_orm-0.7.3/tests/models/test_recipient.py +682 -0
  143. usaspending_orm-0.7.3/tests/models/test_recipient_business_categories.py +790 -0
  144. usaspending_orm-0.7.3/tests/models/test_recipient_spending.py +183 -0
  145. usaspending_orm-0.7.3/tests/models/test_spending.py +87 -0
  146. usaspending_orm-0.7.3/tests/models/test_state_spending.py +45 -0
  147. usaspending_orm-0.7.3/tests/models/test_subaward.py +334 -0
  148. usaspending_orm-0.7.3/tests/models/test_subtier_agency.py +166 -0
  149. usaspending_orm-0.7.3/tests/models/test_transaction.py +219 -0
  150. usaspending_orm-0.7.3/tests/models/test_treasury_account_symbol.py +215 -0
  151. usaspending_orm-0.7.3/tests/queries/test_agencies_search.py +361 -0
  152. usaspending_orm-0.7.3/tests/queries/test_agency_award_summary.py +270 -0
  153. usaspending_orm-0.7.3/tests/queries/test_agency_query.py +231 -0
  154. usaspending_orm-0.7.3/tests/queries/test_award_accounts_query.py +279 -0
  155. usaspending_orm-0.7.3/tests/queries/test_awards_search.py +889 -0
  156. usaspending_orm-0.7.3/tests/queries/test_client_side_query_builder.py +159 -0
  157. usaspending_orm-0.7.3/tests/queries/test_federal_accounts_query.py +488 -0
  158. usaspending_orm-0.7.3/tests/queries/test_filters.py +487 -0
  159. usaspending_orm-0.7.3/tests/queries/test_funding_search.py +263 -0
  160. usaspending_orm-0.7.3/tests/queries/test_idv_child_awards.py +411 -0
  161. usaspending_orm-0.7.3/tests/queries/test_query_builder.py +159 -0
  162. usaspending_orm-0.7.3/tests/queries/test_query_builder_list_behavior.py +379 -0
  163. usaspending_orm-0.7.3/tests/queries/test_query_builder_pagination.py +406 -0
  164. usaspending_orm-0.7.3/tests/queries/test_recipient_query.py +143 -0
  165. usaspending_orm-0.7.3/tests/queries/test_recipients_search.py +468 -0
  166. usaspending_orm-0.7.3/tests/queries/test_search_query_builder.py +616 -0
  167. usaspending_orm-0.7.3/tests/queries/test_single_resource_base.py +29 -0
  168. usaspending_orm-0.7.3/tests/queries/test_spending_search.py +234 -0
  169. usaspending_orm-0.7.3/tests/queries/test_spending_search_count.py +309 -0
  170. usaspending_orm-0.7.3/tests/queries/test_sub_agency_query.py +246 -0
  171. usaspending_orm-0.7.3/tests/queries/test_subawards_search.py +204 -0
  172. usaspending_orm-0.7.3/tests/queries/test_tas_codes_query.py +237 -0
  173. usaspending_orm-0.7.3/tests/queries/test_transactions_search.py +126 -0
  174. usaspending_orm-0.7.3/tests/resources/test_agency_resource.py +333 -0
  175. usaspending_orm-0.7.3/tests/resources/test_award_resource.py +375 -0
  176. usaspending_orm-0.7.3/tests/resources/test_funding_resource.py +79 -0
  177. usaspending_orm-0.7.3/tests/resources/test_recipients_resource.py +29 -0
  178. usaspending_orm-0.7.3/tests/resources/test_spending_resource.py +48 -0
  179. usaspending_orm-0.7.3/tests/resources/test_subawards_resource.py +103 -0
  180. usaspending_orm-0.7.3/tests/resources/test_tas_resource.py +130 -0
  181. usaspending_orm-0.7.3/tests/resources/test_transactions_resource.py +64 -0
  182. usaspending_orm-0.7.3/tests/test_award_accounts_integration.py +159 -0
  183. usaspending_orm-0.7.3/tests/test_cache_fallback.py +122 -0
  184. usaspending_orm-0.7.3/tests/test_client.py +413 -0
  185. usaspending_orm-0.7.3/tests/test_client_caching.py +69 -0
  186. usaspending_orm-0.7.3/tests/test_client_funding.py +202 -0
  187. usaspending_orm-0.7.3/tests/test_client_rate_limit.py +66 -0
  188. usaspending_orm-0.7.3/tests/test_client_security.py +59 -0
  189. usaspending_orm-0.7.3/tests/test_client_transactions.py +37 -0
  190. usaspending_orm-0.7.3/tests/test_config.py +142 -0
  191. usaspending_orm-0.7.3/tests/test_download_resource.py +584 -0
  192. usaspending_orm-0.7.3/tests/test_exceptions.py +312 -0
  193. usaspending_orm-0.7.3/tests/test_integration.py +210 -0
  194. usaspending_orm-0.7.3/tests/test_logging_config.py +292 -0
  195. usaspending_orm-0.7.3/tests/test_mock_client_example.py +233 -0
  196. usaspending_orm-0.7.3/tests/test_readme_examples.py +107 -0
  197. usaspending_orm-0.7.3/tests/test_spending_integration.py +54 -0
  198. usaspending_orm-0.7.3/tests/utils/__init__.py +5 -0
  199. usaspending_orm-0.7.3/tests/utils/decimal_helpers.py +50 -0
  200. usaspending_orm-0.7.3/tests/utils/test_formatter.py +301 -0
  201. usaspending_orm-0.7.3/tests/utils/test_rate_limit.py +362 -0
  202. usaspending_orm-0.7.3/tests/utils/test_retry.py +124 -0
  203. usaspending_orm-0.7.3/tests/utils/test_retry_session_reset.py +354 -0
  204. usaspending_orm-0.7.3/tests/utils/test_text_formatter.py +313 -0
  205. usaspending_orm-0.7.3/tests/utils/test_validations.py +226 -0
  206. usaspending_orm-0.7.3/uv.lock +544 -0
  207. usaspending_orm-0.7.0/src/usaspending/config.py +0 -119
  208. usaspending_orm-0.7.0/src/usaspending/download/manager.py +0 -140
  209. usaspending_orm-0.7.0/src/usaspending/exceptions.py +0 -71
  210. usaspending_orm-0.7.0/src/usaspending/queries/awarding_agencies_search.py +0 -16
  211. usaspending_orm-0.7.0/src/usaspending/queries/funding_agencies_search.py +0 -20
  212. usaspending_orm-0.7.0/src/usaspending/queries/sub_agency_query.py +0 -177
  213. usaspending_orm-0.7.0/src/usaspending/resources/agency_resource.py +0 -105
  214. usaspending_orm-0.7.0/src/usaspending/resources/download_resource.py +0 -102
  215. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/LICENSE +0 -0
  216. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/cli/__init__.py +0 -0
  217. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/__init__.py +0 -0
  218. {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/special_cases.yaml +0 -0
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ .venv
3
+ __pycache__
4
+ .*_cache
5
+ repomix*
6
+ dist/
@@ -0,0 +1,81 @@
1
+ # Changelog
2
+
3
+ All notable changes to the USASpending ORM library are documented here.
4
+ The format loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and the project adheres to [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.7.3] - 2026-07-05
8
+
9
+ ### Added
10
+
11
+ - `AwardsSearch.object_classes(*codes)`: filter awards by federal object class codes (per Office of Management and Budget Circular A-11) on the `/search/spending_by_award/` and `/search/spending_by_award_count/` endpoints. Pass codes such as `"10"` or `"252"`, not names; multiple codes use OR logic.
12
+ - `SubAwardsSearch.object_classes()` raises `ValidationError`. The USASpending API accepts the `object_classes` filter for award searches only and returns HTTP 422 when it is combined with `spending_level=subawards`.
13
+ - `client.downloads.search()` emits a `UserWarning` when the query contains an `object_classes` filter, because the `/api/v2/download/search/` endpoint drops the key. The filter is still forwarded unmodified.
14
+ - Known upstream limitation as of 2026-07-05: the production API accepts `object_classes` but the rollout is incomplete. The search endpoint returns zero results for any object class, the count endpoint does not narrow, and the subawards rejection is not yet enforced server side. The filter should begin returning data once USAspending finishes deploying the feature and populating its award index.
15
+ - `tests/test_readme_examples.py`: integration tests that extract the README's Python code blocks and execute the runnable ones verbatim against the live API, so broken or rotted examples fail mechanically. A network-free guard in the default suite catches extraction drift. The live `client` fixture moved to `tests/conftest.py` and is now shared with `tests/test_integration.py`.
16
+
17
+ ### Documentation
18
+
19
+ - Corrected the `api-docs-links.md` subawards entry: `SubAwardsSearch` POSTs `/api/v2/search/spending_by_award/` with `subawards=true` and `spending_level=subawards` (inheriting `AwardsSearch`) rather than calling `/api/v2/subawards/`.
20
+ - Added missing `api-docs-links.md` entries for `/api/v2/idvs/awards/` (IDV child awards) and the TAS filter-tree endpoints (`/api/v2/references/filter_tree/tas/` and its `{toptier_code}/` and `{toptier_code}/{federal_account}/` variants).
21
+ - An upstream API compatibility review of USASpending API releases from April through June 2026 found no breaking changes for this library. The 0.7.2 release already handles the `spending_by_award` Pydantic migration (HTTP 422 validation errors), the `program_activities` filter rename, and the new F001 through F010 assistance type codes.
22
+ - Revalidated all README examples against live USAspending data. Fixed two broken chains (`location.full_address` is actually `location.formatted_address`; a subaward's place of performance is on the subaward, not its recipient), refreshed stale sample outputs, and added examples for the `client.spending` category rollups and the list-style `len(query)` interface.
23
+
24
+ ## [0.7.2] - 2026-06-05
25
+
26
+ ### Added
27
+
28
+ - `client.downloads.search(query, ...)` backed by the new `/api/v2/download/search/` endpoint, which bundles award, transaction, and subaward data into a single download built from an awards search query. Supports `file_format`, `spending_level`, `columns`, and `limit`.
29
+ - `QueryBuilder.to_filters_payload()`: public accessor returning the assembled API `filters` object for a query without executing a search.
30
+
31
+ ### Changed
32
+
33
+ - HTTP 422 (Unprocessable Entity) validation responses are now surfaced as `APIError` with the response detail instead of a generic `HTTPError`. This aligns with the USASpending API's move to Pydantic request validation on `/search/spending_by_award/`.
34
+
35
+ ### Deprecated
36
+
37
+ - `program_activity()` is deprecated and now forwards to `program_activities()`, emitting a `DeprecationWarning`. The USASpending API removed the `program_activity` filter from `/search/spending_by_award/` in favor of `program_activities`. Existing calls continue to work; integer codes are forwarded as string `code` values.
38
+
39
+ ## [0.7.1] - 2026-04-16
40
+
41
+ ### Added
42
+
43
+ - Public export of `DetachedInstanceError` so callers can `from usaspending import DetachedInstanceError` as documented in the README.
44
+ - `config.allowed_download_hosts`: an allow-list of hostnames the library will fetch binary downloads from. Defaults to `{"api.usaspending.gov", "files.usaspending.gov"}`.
45
+ - `config.validate()` now rejects malformed `base_url`, CR/LF in `user_agent`, and empty `cache_dir`.
46
+
47
+ ### Changed
48
+
49
+ - `ValidationError` now inherits from both `USASpendingError` and the built-in `ValueError`. Callers that previously caught `ValueError` for invalid parameters continue to work unchanged; new code can catch the library-specific `ValidationError`.
50
+ - `RateLimiter` now raises `ValidationError` (rather than a bare `ValueError`) for invalid `max_calls`/`period` arguments. Non-breaking due to the dual inheritance above.
51
+ - `RecipientsResource.find_by_recipient_id` is now annotated as non-Optional. This matches its long-standing behavior of raising on miss via the direct-ID lookup path; runtime behavior is unchanged. `find_by_duns` and `find_by_uei` remain Optional because they use the search-delegation path.
52
+ - `Agency.get_obligations` return annotation corrected from `float | None` to `Decimal | None` to match actual runtime type.
53
+ - `Agency.total_obligations` now applies `Decimal` coercion to stored values to match its declared return type.
54
+ - `TransactionsSearch._award_id` and `FundingSearch._award_id` annotated as `str | None` rather than `str` (they are always `None` until set).
55
+ - `time_period()` now rejects date ranges where `end_date` is earlier than `start_date`.
56
+
57
+ ### Fixed
58
+
59
+ - `to_date()` now extracts the `date` portion from `datetime` inputs instead of passing them through unchanged.
60
+ - `IDVChildAwardsSearch._clone()` no longer silently drops `_filter_objects`, `_max_pages`, `_order_by`, and `_order_direction` when chaining.
61
+ - `SubAwardsSearch._clone()` now delegates to `super()._clone()` so base-class state changes propagate.
62
+ - `AwardAccountsQuery._clone()` no longer copies a stale `_cached_count` across filter changes.
63
+ - `Agency.latest_action_date` no longer crashes when the award-summary endpoint returns no data.
64
+ - `round_to_millions()` cleaned up redundant disjunct in threshold check.
65
+ - Removed unused `DEFAULT_KEEP_UPPERCASE` set, which also contained a latent missing-comma bug that concatenated two entries.
66
+ - Fixed malformed `Raises:` block in `AwardResource.find_by_generated_id` docstring.
67
+ - `Agency.id` was missing its return-type annotation.
68
+
69
+ ### Security
70
+
71
+ - Binary downloads (`_download_binary_file`) now require `https` and a hostname on `config.allowed_download_hosts`, mitigating SSRF if API responses are tampered with.
72
+ - File-backed cache directory is now created with `0700` and tightened to `0700` if it already exists with looser bits. Protects the pickle-backed cache on shared hosts.
73
+ - ZIP extraction creates the extract directory with `0700`, detects absolute paths with stdlib `posixpath.isabs` / `ntpath.isabs` (covers Windows drive letters and UNC prefixes), and uses `normpath`-based prefix comparison for traversal detection.
74
+
75
+ ### Removed
76
+
77
+ - Dead code: `get_past_fiscal_years`, `custom_titlecase_callback`, `parse_agency_type`, `parse_agency_tier`, `QueryBuilder._fetch_page`, empty `AwardsSearch.__init__`, redundant `AwardsSearch._clone` override, unreachable `try/except` in `_derived_award_identifier`.
78
+
79
+ ## [0.7.0] - 2026-04-12
80
+
81
+ Previous release. See git history for details.
@@ -0,0 +1,243 @@
1
+ # claude.md
2
+
3
+ ## Project Overview
4
+
5
+ USASpending ORM is a Python ORM library for the USAspending.gov API, providing a modern, client-centric interface with query builders and automatic pagination.
6
+
7
+ ## USASpending API Reference Documentation
8
+
9
+ - See `api-docs-links.md` for official endpoint documentation links
10
+ - Use `context7 MCP` to access the API documentation for the USASpending project and for any external libraries referenced in this codebase
11
+
12
+ ## Architecture Principles
13
+
14
+ ### Agency-agnostic implementation
15
+
16
+ - Designed to work with any agency's data
17
+ - No hardcoded agency logic
18
+ - Provides generic filters and helper methods
19
+
20
+ ### Client-Centric Design
21
+
22
+ - All operations flow through a central `USASpendingClient` client
23
+ - Resources accessed as properties: `client.awards`, `client.recipients`, etc.
24
+ - No global state or session variables
25
+ - Thread-safe through instance-based design
26
+
27
+ ### Query Builder Pattern
28
+
29
+ - Inspired by ActiveRecord and Django ORM syntax
30
+ - Chainable, immutable query construction via `_clone()` method
31
+ - Lazy evaluation - queries execute only when iterated
32
+ - Standard python List-like interface for results will fire relevant API calls (e.g. `len(client.awards)` fires off an API call to a `count` endpoint, for example)
33
+
34
+ ### Resource Organization
35
+
36
+ - Resources grouped in `resources/` directory
37
+ - Each resource inherits from `BaseResource`
38
+ - Resources create and return appropriate query builders
39
+ - Clean separation between resources and queries
40
+
41
+ ### Models and Data Structures
42
+
43
+ - Inspired by ActiveRecord and Django ORM structure
44
+ - Data models in `models/` directory
45
+ - Use composition for nested structures
46
+ - Raw API data stored in internal `_data` attribute and exposed via `raw()` method in `BaseModel`
47
+ - Properties provide access to structured data
48
+ - Properties use the `_lazy_get()` method to fetch data lazily for models inheriting from `LazyRecord`
49
+ - Models can chain their associations as QueryBuilder objects for one-to-many associations (e.g. `award.recipient.location.city`
50
+ - Models load related one-to-one associations as related model objects (e.g. `award.recipient`)
51
+ - Models provide a consistent API to underlying property names given the API's sometimes inconsistent naming conventions
52
+
53
+ ## Code Style and Standards
54
+
55
+ ### Python Guidelines
56
+
57
+ - Follow PEP 8 guidelines
58
+ - Follow code style in the linting settings in `pyproject.toml`
59
+ - FOLLOW BEST PRACTICES OBJECT-ORIENTED DESIGN
60
+ - DON'T REPEAT YOURSELF (DRY)
61
+ - Single Responsibility Principle
62
+ - Don't over-engineer: keep it simple, stupid (KISS)
63
+
64
+ ### Type Hints
65
+
66
+ - Use `from __future__ import annotations` for forward references
67
+ - Add type hints to ALL function signatures
68
+ - Use `TypeVar` and `Generic` for query builders
69
+ - Prefer `Optional[T]` over `Union[T, None]`
70
+
71
+ ### Project Structure
72
+
73
+ ```
74
+ src/usaspending/
75
+ ├── client.py # Main USASpendingClient
76
+ ├── cli/ # CLI tools (e.g., download_award)
77
+ ├── config.py # Configuration settings
78
+ ├── download/ # Download job management
79
+ ├── logging_config.py # Custom logger configuration
80
+ ├── exceptions.py # Custom exceptions
81
+ ├── resources/ # Resource classes
82
+ ├── queries/ # Query builders
83
+ ├── models/ # Data models
84
+ └── utils/ # Utilities (retry, rate limit)
85
+ ```
86
+
87
+ ## Testing Strategy
88
+
89
+ ### Test Organization
90
+
91
+ ```
92
+ tests/
93
+ ├── conftest.py # Shared fixtures
94
+ ├── test_client.py # Client tests
95
+ ├── queries/ # Query builder tests
96
+ ├── models/ # Model tests
97
+ ├── resources/ # Resource tests
98
+ ├── utils/ # Utility tests
99
+ ├── mocks/ # Mock client and response builders
100
+ └── fixtures/ # Real-world POST-header and response JSON data from USASpending API
101
+ ```
102
+
103
+ ### Testing Principles
104
+
105
+ - Use `pytest` for test framework and implement pytest best practices
106
+ - Always integrate fixture data from `tests/fixtures/` into tests
107
+ - Aim for >80% test coverage
108
+ - Mock API client using the `mock_usa_client()` method and other helps in `tests/mocks/`
109
+ - Use helper methods to load fixtures and the mock client object in `tests/conftest.py`
110
+
111
+ ## Quick Commands
112
+
113
+ - Run tests: `uv run pytest`
114
+ - Run integration tests: `uv run pytest -m integration`
115
+ - Lint: `uv run ruff check src/ tests/`
116
+ - Format: `uv run ruff format src/ tests/`
117
+ - No Justfile in this project
118
+
119
+ ## Implementation Patterns
120
+
121
+ ### Configuration
122
+
123
+ - Uses a global `config` object
124
+ - No environment variables in library code
125
+
126
+ ### Resource Classes
127
+
128
+ - Lazy-loaded via property descriptors
129
+ - Stored in `_resources` dict
130
+ - Return query builder instances
131
+ - Handle resource-specific logic
132
+
133
+ ### Query Builders
134
+
135
+ - Hierarchy: `BaseQuery[T]` -> `QueryBuilder[T]` -> `SearchQueryBuilder[T]`; also `ClientSideQueryBuilder[T]` (extends `BaseQuery`)
136
+ - `QueryBuilder[T]` handles paginated API queries; `ClientSideQueryBuilder[T]` handles client-side filtering
137
+ - Implement abstract methods:
138
+ - `_endpoint()`: API endpoint
139
+ - `_build_payload()`: Request payload
140
+ - `_transform_result()`: Result transformation
141
+ - `_clone()`: Return cloned instance
142
+ - `__iter__()`: Iterable interface
143
+ - All filter methods return cloned instances
144
+
145
+ ### Caching
146
+
147
+ - Implemented using `cachier` python library via `cachier` decorator
148
+ - Supports file (default, via pickle) and memory backends
149
+ - Dynamically reconfigurable at runtime via observer pattern (`register_cache_settings_observer` in `config.py`); cachier decorator is rebuilt when settings change
150
+ - Client uses cache-with-fallback: tries cached response first, falls back to uncached on failure
151
+ - Cache configurable via the global `config` object set in `src/usaspending/config.py`:
152
+ - `cache_enabled`: Enable/disable caching (default: False)
153
+ - `cache_ttl`: `timedelta` TTL (default: 1 week); `configure()` accepts seconds as `int`/`float`
154
+ - `cache_timeout`: Seconds to wait for cache entry processing (default: 60)
155
+ - `cache_dir`: Directory for file-based cache (default: "~/.cache/usaspending")
156
+ - `cache_backend`: Backend type ('file' or 'memory', default: 'file')
157
+ - `cache_namespace`: Namespace for cache keys (default: 'usaspending-orm')
158
+
159
+ ### Logging
160
+
161
+ - Implemented via custom `USASpendingLogger` class using Python's `logging` module
162
+ - Log all API requests and responses, including total counts of API calls
163
+ - Log query execution times
164
+ - Implement variable log levels (DEBUG, INFO, WARNING, ERROR, CRITICAL)
165
+
166
+ ## Development Workflow
167
+
168
+ ### Adding New Features
169
+
170
+ 1. Define interface in resource class
171
+ 2. Create query builder if needed
172
+ 3. Write tests first (TDD)
173
+ 4. Implement with full type hints
174
+ 5. Add to `__all__` exports
175
+ 6. Document in docstrings
176
+
177
+ ### Code Review Checklist
178
+
179
+ - [ ] All methods have type hints
180
+ - [ ] Docstrings follow Google style
181
+ - [ ] Proper exception handling
182
+ - [ ] PEP 8 pythonic code style
183
+ - [ ] Code is DRY, object-oriented, clear and maintainable
184
+ - [ ] Passes `ruff` linting and formatting check
185
+
186
+ ## Error Handling
187
+
188
+ ### Exception Hierarchy
189
+
190
+ - `USASpendingError` - Base exception
191
+ - `APIError` - API response errors
192
+ - `HTTPError` - Network/transport layer errors (retryable 5xx)
193
+ - `RateLimitError` - Rate limit exceeded
194
+ - `ValidationError` - Invalid parameters
195
+ - `DetachedInstanceError` - Lazy-loading on closed/detached client
196
+ - `ConfigurationError` - Invalid configuration settings
197
+ - `DownloadError` - File download/extraction failures
198
+
199
+ ### Retry Logic
200
+
201
+ - Implemented in `RetryHandler`
202
+ - Exponential backoff
203
+ - Configurable max attempts
204
+ - Only retry on specific errors
205
+
206
+ ## Documentation Standards
207
+
208
+ ### Docstring Requirements
209
+
210
+ - Google style format
211
+ - Include parameter types
212
+ - Document return values
213
+ - Add usage examples
214
+ - Note any side effects
215
+
216
+ ## Release Process
217
+
218
+ ### Quality Gates
219
+
220
+ - 100% public API documented
221
+ - Type hints pass mypy
222
+ - Tests pass with >80% coverage
223
+ - No TODO/FIXME in code
224
+
225
+ ### Versioning Strategy
226
+
227
+ - Semantic versioning
228
+ - Alpha releases initially
229
+ - Document all changes
230
+ - Migration guides for major versions
231
+
232
+ ## Special Instructions
233
+
234
+ - **Use full agency names and not acronyms in examples and docstrings. For example always use `National Aeronautics and Space Administration` instead of `NASA` when referencing the space agency.**
235
+ - **This file is committed to the repository and so should never include any secrets.**
236
+ - **Always read `README.md` before making changes.**
237
+ - **Cross-reference:** Also read `api-docs-links.md` for detailed contributor guidelines.
238
+ - **When adding new features, update all relevant docs, tests, and requirements files.**
239
+ - **All code must be Python 3.9+ compatible.**
240
+ - **When in doubt, prefer explicit, readable code over cleverness.**
241
+ - **Never use non-ASCII characters or the em dash.**
242
+ - **When referencing/calling external libraries, use `context7 MCP` to get latest documentation.**
243
+ - **All new code must have full type annotations and Google-style docstrings.**