usaspending-orm 0.9.0__tar.gz → 0.9.1__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 (288) hide show
  1. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/.gitignore +1 -0
  2. usaspending_orm-0.9.1/.readthedocs.yaml +17 -0
  3. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/CHANGELOG.md +47 -0
  4. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/LICENSE +1 -1
  5. usaspending_orm-0.9.1/PKG-INFO +153 -0
  6. usaspending_orm-0.9.1/README.md +124 -0
  7. usaspending_orm-0.9.1/docs/explanation/caching.md +115 -0
  8. usaspending_orm-0.9.1/docs/explanation/data-model.md +52 -0
  9. usaspending_orm-0.9.1/docs/explanation/query-execution.md +68 -0
  10. usaspending_orm-0.9.1/docs/getting-started/core-concepts.md +77 -0
  11. usaspending_orm-0.9.1/docs/getting-started/installation.md +47 -0
  12. usaspending_orm-0.9.1/docs/getting-started/quickstart.md +81 -0
  13. usaspending_orm-0.9.1/docs/guides/production.md +106 -0
  14. usaspending_orm-0.9.1/docs/guides/related-data.md +61 -0
  15. usaspending_orm-0.9.1/docs/guides/search-awards.md +166 -0
  16. usaspending_orm-0.9.1/docs/guides/search-transactions.md +71 -0
  17. usaspending_orm-0.9.1/docs/guides/spending-and-downloads.md +119 -0
  18. usaspending_orm-0.9.1/docs/index.md +56 -0
  19. usaspending_orm-0.9.1/docs/reference/client.md +41 -0
  20. usaspending_orm-0.9.1/docs/reference/configuration.md +60 -0
  21. usaspending_orm-0.9.1/docs/reference/models.md +48 -0
  22. usaspending_orm-0.9.1/docs/reference/queries.md +55 -0
  23. usaspending_orm-0.9.1/docs/usaspending-api/endpoint-mapping.md +54 -0
  24. usaspending_orm-0.9.1/docs/usaspending-api/limitations.md +59 -0
  25. usaspending_orm-0.9.1/docs/usaspending-api/terminology.md +55 -0
  26. usaspending_orm-0.9.1/mkdocs.yml +109 -0
  27. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/pyproject.toml +11 -2
  28. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/client.py +17 -1
  29. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/download/job.py +11 -3
  30. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/__init__.py +2 -0
  31. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/agency.py +2 -39
  32. usaspending_orm-0.9.1/src/usaspending/models/def_code.py +36 -0
  33. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/download.py +6 -2
  34. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/loan.py +3 -3
  35. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/agencies_search.py +26 -7
  36. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/agency_award_summary.py +5 -4
  37. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/awards_search.py +2 -1
  38. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/base_query.py +12 -1
  39. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/client_side_query_builder.py +2 -18
  40. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/filters.py +86 -11
  41. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/mixins.py +32 -1
  42. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/query_builder.py +55 -41
  43. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/sub_agency_query.py +5 -1
  44. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/__init__.py +2 -0
  45. usaspending_orm-0.9.1/src/usaspending/resources/references_resource.py +21 -0
  46. usaspending_orm-0.9.1/src/usaspending/utils/payloads.py +34 -0
  47. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/conftest.py +31 -31
  48. usaspending_orm-0.9.1/tests/fixtures/def_codes.json +29 -0
  49. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/public_api_surface.json +14 -0
  50. usaspending_orm-0.9.1/tests/markdown_examples.py +86 -0
  51. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/mocks/README.md +3 -3
  52. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/mocks/mock_client.py +3 -1
  53. usaspending_orm-0.9.0/tests/volatile_fields.py → usaspending_orm-0.9.1/tests/model_contracts.py +122 -65
  54. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_category_registry.py +6 -4
  55. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_common.py +1 -5
  56. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_types.py +9 -0
  57. usaspending_orm-0.9.1/tests/models/test_def_code.py +52 -0
  58. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_lazy_load.py +19 -15
  59. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_location.py +114 -57
  60. usaspending_orm-0.9.1/tests/models/test_model_field_contracts.py +159 -0
  61. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_recipient.py +25 -50
  62. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_recipient_spending.py +28 -38
  63. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_search_projection.py +47 -32
  64. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_subaward.py +2 -9
  65. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_transaction.py +85 -75
  66. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_agencies_search.py +123 -1
  67. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_agency_award_summary.py +6 -4
  68. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_filters.py +87 -2
  69. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_search_query_builder.py +111 -2
  70. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_subawards_search.py +2 -9
  71. usaspending_orm-0.9.1/tests/resources/test_references_resource.py +92 -0
  72. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/snapshot_support.py +4 -6
  73. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_client.py +0 -7
  74. usaspending_orm-0.9.1/tests/test_documentation.py +246 -0
  75. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_download_resource.py +57 -4
  76. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_integration.py +7 -5
  77. usaspending_orm-0.9.1/tests/test_live_contract_integration.py +286 -0
  78. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_readme_examples.py +11 -18
  79. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/uv.lock +383 -1
  80. usaspending_orm-0.9.0/PKG-INFO +0 -586
  81. usaspending_orm-0.9.0/README.md +0 -557
  82. usaspending_orm-0.9.0/api-docs-links.md +0 -276
  83. usaspending_orm-0.9.0/tests/fixtures/golden/agency.json +0 -74
  84. usaspending_orm-0.9.0/tests/fixtures/golden/award_account_first_result.json +0 -29
  85. usaspending_orm-0.9.0/tests/fixtures/golden/award_contract.json +0 -190
  86. usaspending_orm-0.9.0/tests/fixtures/golden/award_contract_awarding_agency.json +0 -74
  87. usaspending_orm-0.9.0/tests/fixtures/golden/award_contract_period_of_performance.json +0 -15
  88. usaspending_orm-0.9.0/tests/fixtures/golden/award_contract_place_of_performance.json +0 -23
  89. usaspending_orm-0.9.0/tests/fixtures/golden/award_contract_recipient.json +0 -51
  90. usaspending_orm-0.9.0/tests/fixtures/golden/award_grant.json +0 -198
  91. usaspending_orm-0.9.0/tests/fixtures/golden/award_idv.json +0 -190
  92. usaspending_orm-0.9.0/tests/fixtures/golden/award_loan.json +0 -191
  93. usaspending_orm-0.9.0/tests/fixtures/golden/award_parent_of_contract.json +0 -136
  94. usaspending_orm-0.9.0/tests/fixtures/golden/funding_first_result.json +0 -35
  95. usaspending_orm-0.9.0/tests/fixtures/golden/idv_child_award_first_result.json +0 -192
  96. usaspending_orm-0.9.0/tests/fixtures/golden/recipient.json +0 -60
  97. usaspending_orm-0.9.0/tests/fixtures/golden/search_contract_first_result.json +0 -190
  98. usaspending_orm-0.9.0/tests/fixtures/golden/search_subaward_first_result.json +0 -91
  99. usaspending_orm-0.9.0/tests/fixtures/golden/spending_by_recipient_first_result.json +0 -68
  100. usaspending_orm-0.9.0/tests/fixtures/golden/spending_by_state_first_result.json +0 -17
  101. usaspending_orm-0.9.0/tests/fixtures/golden/transaction_first_result.json +0 -18
  102. usaspending_orm-0.9.0/tests/models/test_volatile_field_mapping.py +0 -177
  103. usaspending_orm-0.9.0/tests/test_golden_master_integration.py +0 -707
  104. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/__init__.py +0 -0
  105. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/cli/__init__.py +0 -0
  106. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/cli/download_award.py +0 -0
  107. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/config.py +0 -0
  108. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/download/__init__.py +0 -0
  109. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/download/manager.py +0 -0
  110. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/exceptions.py +0 -0
  111. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/logging_config.py +0 -0
  112. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/award.py +0 -0
  113. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/award_account.py +0 -0
  114. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/award_factory.py +0 -0
  115. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/award_identifier.py +0 -0
  116. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/award_types.py +0 -0
  117. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/base_model.py +0 -0
  118. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/contract.py +0 -0
  119. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/district_spending.py +0 -0
  120. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/federal_account.py +0 -0
  121. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/funding.py +0 -0
  122. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/grant.py +0 -0
  123. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/idv.py +0 -0
  124. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/lazy_record.py +0 -0
  125. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/location.py +0 -0
  126. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/period_of_performance.py +0 -0
  127. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/procurement_award.py +0 -0
  128. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/recipient.py +0 -0
  129. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/recipient_business_categories.py +0 -0
  130. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/recipient_spending.py +0 -0
  131. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/spending.py +0 -0
  132. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/state_spending.py +0 -0
  133. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/subaward.py +0 -0
  134. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/subtier_agency.py +0 -0
  135. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/transaction.py +0 -0
  136. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/models/treasury_account_symbol.py +0 -0
  137. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/__init__.py +0 -0
  138. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/agency_query.py +0 -0
  139. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/award_accounts_query.py +0 -0
  140. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/award_query.py +0 -0
  141. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/award_transactions_search.py +0 -0
  142. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/awarding_agencies_search.py +0 -0
  143. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/federal_accounts_query.py +0 -0
  144. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/filter_tree_query.py +0 -0
  145. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/funding_agencies_search.py +0 -0
  146. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/funding_search.py +0 -0
  147. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/idv_child_awards.py +0 -0
  148. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/recipient_query.py +0 -0
  149. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/recipients_search.py +0 -0
  150. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/single_resource_base.py +0 -0
  151. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/spending_search.py +0 -0
  152. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/subawards_search.py +0 -0
  153. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/tas_agencies_query.py +0 -0
  154. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/tas_codes_query.py +0 -0
  155. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/queries/transactions_search.py +0 -0
  156. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/agency_resource.py +0 -0
  157. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/award_accounts_resource.py +0 -0
  158. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/award_resource.py +0 -0
  159. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/base_resource.py +0 -0
  160. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/download_resource.py +0 -0
  161. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/funding_resource.py +0 -0
  162. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/recipients_resource.py +0 -0
  163. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/spending_resource.py +0 -0
  164. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/subawards_resource.py +0 -0
  165. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/tas_resource.py +0 -0
  166. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/resources/transactions_resource.py +0 -0
  167. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/utils/__init__.py +0 -0
  168. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/utils/dates.py +0 -0
  169. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/utils/numbers.py +0 -0
  170. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/utils/rate_limit.py +0 -0
  171. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/utils/retry.py +0 -0
  172. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/utils/special_cases.yaml +0 -0
  173. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/utils/textcase.py +0 -0
  174. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/src/usaspending/utils/validations.py +0 -0
  175. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/__init__.py +0 -0
  176. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/agency.json +0 -0
  177. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/agency_autocomplete.json +0 -0
  178. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/agency_award_summary.json +0 -0
  179. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/agency_subagencies.json +0 -0
  180. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/accounts.json +0 -0
  181. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/award_funding_grant.json +0 -0
  182. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/contract.json +0 -0
  183. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/grant.json +0 -0
  184. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/idv.json +0 -0
  185. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/idv_awards.json +0 -0
  186. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/loan.json +0 -0
  187. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/search_results_contracts.json +0 -0
  188. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/search_results_grants.json +0 -0
  189. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/search_results_idvs.json +0 -0
  190. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/search_results_subawards.json +0 -0
  191. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/awards/transactions.json +0 -0
  192. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/download_assistance.json +0 -0
  193. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/download_search.json +0 -0
  194. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/download_status.json +0 -0
  195. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/recipient_university.json +0 -0
  196. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/recipients_search.json +0 -0
  197. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/spending_by_award_contracts.json +0 -0
  198. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/spending_by_district.json +0 -0
  199. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/spending_by_recipient.json +0 -0
  200. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/spending_by_state.json +0 -0
  201. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/spending_by_transaction.json +0 -0
  202. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/spending_by_transaction_count.json +0 -0
  203. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/spending_by_transaction_mixed.json +0 -0
  204. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/tas_agencies.json +0 -0
  205. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/tas_codes.json +0 -0
  206. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/tas_federal_accounts.json +0 -0
  207. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/top_recipients_params.json +0 -0
  208. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/fixtures/top_recipients_response.json +0 -0
  209. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/mocks/__init__.py +0 -0
  210. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/mocks/response_builder.py +0 -0
  211. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/mocks/test_mock_client.py +0 -0
  212. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/__init__.py +0 -0
  213. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_agency.py +0 -0
  214. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_agency_subagencies.py +0 -0
  215. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_agency_tas_integration.py +0 -0
  216. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_account.py +0 -0
  217. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_agency_integration.py +0 -0
  218. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_decimal_precision.py +0 -0
  219. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_factory.py +0 -0
  220. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_identifier.py +0 -0
  221. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_lazy_loading.py +0 -0
  222. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_office_integration.py +0 -0
  223. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_award_type_constants.py +0 -0
  224. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_base_model.py +0 -0
  225. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_district_spending.py +0 -0
  226. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_federal_account.py +0 -0
  227. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_funding.py +0 -0
  228. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_period_of_performance.py +0 -0
  229. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_recipient_business_categories.py +0 -0
  230. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_spending.py +0 -0
  231. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_state_spending.py +0 -0
  232. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_subtier_agency.py +0 -0
  233. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_transaction_search_projection.py +0 -0
  234. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/models/test_treasury_account_symbol.py +0 -0
  235. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_agency_query.py +0 -0
  236. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_award_accounts_query.py +0 -0
  237. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_award_transactions_search.py +0 -0
  238. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_awards_search.py +0 -0
  239. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_client_side_query_builder.py +0 -0
  240. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_count_respects_limits.py +0 -0
  241. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_federal_accounts_query.py +0 -0
  242. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_funding_search.py +0 -0
  243. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_idv_child_awards.py +0 -0
  244. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_query_builder.py +0 -0
  245. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_query_builder_list_behavior.py +0 -0
  246. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_query_builder_pagination.py +0 -0
  247. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_recipient_query.py +0 -0
  248. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_recipients_search.py +0 -0
  249. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_single_resource_base.py +0 -0
  250. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_spending_search.py +0 -0
  251. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_spending_search_count.py +0 -0
  252. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_sub_agency_query.py +0 -0
  253. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_tas_agencies_query.py +0 -0
  254. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_tas_codes_query.py +0 -0
  255. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/queries/test_transactions_search.py +0 -0
  256. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/resources/test_agency_resource.py +0 -0
  257. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/resources/test_award_resource.py +0 -0
  258. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/resources/test_funding_resource.py +0 -0
  259. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/resources/test_recipients_resource.py +0 -0
  260. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/resources/test_spending_resource.py +0 -0
  261. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/resources/test_subawards_resource.py +0 -0
  262. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/resources/test_tas_resource.py +0 -0
  263. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/resources/test_transactions_resource.py +0 -0
  264. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_award_accounts_integration.py +0 -0
  265. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_cache_fallback.py +0 -0
  266. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_characterization.py +0 -0
  267. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_client_caching.py +0 -0
  268. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_client_funding.py +0 -0
  269. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_client_rate_limit.py +0 -0
  270. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_client_security.py +0 -0
  271. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_client_transactions.py +0 -0
  272. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_config.py +0 -0
  273. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_exceptions.py +0 -0
  274. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_logging_config.py +0 -0
  275. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_mock_client_example.py +0 -0
  276. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_public_api_surface.py +0 -0
  277. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/test_spending_integration.py +0 -0
  278. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/__init__.py +0 -0
  279. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/decimal_helpers.py +0 -0
  280. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_dates.py +0 -0
  281. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_doctests.py +0 -0
  282. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_numbers.py +0 -0
  283. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_rate_limit.py +0 -0
  284. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_retry.py +0 -0
  285. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_retry_session_reset.py +0 -0
  286. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_special_cases_data.py +0 -0
  287. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_textcase.py +0 -0
  288. {usaspending_orm-0.9.0 → usaspending_orm-0.9.1}/tests/utils/test_validations.py +0 -0
@@ -4,6 +4,7 @@ __pycache__
4
4
  .*_cache
5
5
  repomix*
6
6
  dist/
7
+ site/
7
8
  .claude/
8
9
  /~/
9
10
  .coverage
@@ -0,0 +1,17 @@
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-24.04
5
+ tools:
6
+ python: "3.13"
7
+
8
+ python:
9
+ install:
10
+ - method: uv
11
+ command: sync
12
+ groups:
13
+ - docs
14
+
15
+ mkdocs:
16
+ configuration: mkdocs.yml
17
+ fail_on_warning: true
@@ -4,6 +4,53 @@ All notable changes to the USASpending ORM library are documented here.
4
4
  The format loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
5
  and the project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.9.1] - 2026-08-27
8
+
9
+ ### Added
10
+
11
+ - `client.references.def_codes()`: fetches the API's current Disaster Emergency
12
+ Fund Code reference data from `/api/v2/references/def_codes/` as `DefCode`
13
+ models. DEF codes change as legislation is enacted, so discover them at
14
+ runtime instead of maintaining a local list; the `def_codes(...)` search
15
+ filter itself remains network-free, and its docstring no longer carries a
16
+ hardcoded code list. `DefCode` moved to `usaspending/models/def_code.py` and
17
+ is exported from `usaspending.models`; the legacy
18
+ `usaspending.models.agency.DefCode` import path still resolves to the same
19
+ class.
20
+ - Client-side validation of classification-filter complexity, mirroring the
21
+ API's hard-coded bounds as reviewed against upstream on 2026-08-25.
22
+ `naics_codes()` rejects more than 200 combined require/exclude codes.
23
+ `psc_codes()` rejects more than 200 simple codes, more than 100 hierarchical
24
+ paths per side, more than 200 combined paths after upstream's PSC Tier-1
25
+ group expansion, and paths deeper than 10 levels. `tas_codes()` enforces the
26
+ same per-side, combined, and depth bounds. Oversized filters now raise
27
+ `ValidationError` at construction instead of failing at the API.
28
+ - MkDocs documentation site (getting-started guides, API reference, and the
29
+ upstream endpoint mapping) with Read the Docs configuration.
30
+
31
+ ### Changed
32
+
33
+ - `client.agencies.search()` now follows the shared collection semantics.
34
+ `page_size(n)` maps to the endpoint's `limit` parameter (default 100, capped
35
+ at 500) instead of a fixed internal limit of 100; the upstream limit applies
36
+ independently to the toptier, subtier, and office buckets, so one request can
37
+ return up to `3n` rows. `limit(n)` bounds the flattened result consistently
38
+ across `all()`, `count()`, `len()`, indexing, and slicing, and indexing reads
39
+ the single flattened response rather than translating indices into pages the
40
+ endpoint does not have. Zero bounds (`limit(0)`, `max_pages(0)`) resolve
41
+ without a request.
42
+ - `naics_codes()`, `psc_codes()`, and `tas_codes()` copy their inputs, so
43
+ mutating a caller-owned list after building a query no longer alters the
44
+ filter.
45
+
46
+ ### Documentation
47
+
48
+ - Download failure text (`job.error_message`, `DownloadStatus.message`) is
49
+ documented as opaque server-provided text: it may be generic and can change
50
+ without notice, so application control flow should depend on `job.state`.
51
+ When a failed job carries no server message, `job.error_message` is
52
+ `"API reported failure."`.
53
+
7
54
  ## [0.9.0] - 2026-07-30
8
55
 
9
56
  Adds the global transaction search: `client.transactions.search()` covers the
@@ -1,4 +1,4 @@
1
- Copyright 2025 Casey Dreier
1
+ Copyright 2025 Casey Dreier/The Planetary Society
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the “Software”), to deal
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.5
2
+ Name: usaspending-orm
3
+ Version: 0.9.1
4
+ Summary: A Python ORM wrapper for the USAspending.gov API with intuitive queries, automatic pagination, and smart caching
5
+ Project-URL: Homepage, https://github.com/planetary-society/usaspending-orm
6
+ Project-URL: Repository, https://github.com/planetary-society/usaspending-orm
7
+ Project-URL: Issues, https://github.com/planetary-society/usaspending-orm/issues
8
+ Project-URL: Documentation, https://github.com/planetary-society/usaspending-orm/blob/main/README.md
9
+ Author-email: Casey Dreier <casey.dreier@planetary.org>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api-wrapper,contracts,federal-spending,government-data,grants,orm,usaspending
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.9
24
+ Requires-Dist: cachier<5.0.0,>=4.1.0
25
+ Requires-Dist: pyyaml<7.0.0,>=6.0.2
26
+ Requires-Dist: requests<3.0.0,>=2.32.4
27
+ Requires-Dist: titlecase<3.0.0,>=2.4.1
28
+ Description-Content-Type: text/markdown
29
+
30
+ # USASpending ORM
31
+
32
+ [![Tests](https://github.com/planetary-society/usaspending-orm/actions/workflows/test.yml/badge.svg)](https://github.com/planetary-society/usaspending-orm/actions/workflows/test.yml)
33
+ [![PyPI](https://img.shields.io/pypi/v/usaspending-orm.svg)](https://pypi.org/project/usaspending-orm/)
34
+ [![Python](https://img.shields.io/pypi/pyversions/usaspending-orm.svg)](https://pypi.org/project/usaspending-orm/)
35
+
36
+ USASpending ORM is a typed, ORM-style Python interface to the
37
+ [USAspending.gov API](https://api.usaspending.gov/). It provides fluent query
38
+ builders and navigable models for federal awards, transactions, recipients,
39
+ agencies, spending summaries, Treasury Account Symbols, and bulk downloads.
40
+
41
+ The library is maintained by [The Planetary Society](https://www.planetary.org/).
42
+
43
+ ## Why use it?
44
+
45
+ - Express complex USAspending searches through chainable Python methods.
46
+ - Work with normalized models, `date` values, and exact `Decimal` amounts.
47
+ - Navigate from awards to recipients, agencies, transactions, funding, accounts,
48
+ and subawards.
49
+ - Retain the original API response through each model's `.raw` property.
50
+ - Use built-in pagination, retries, rate limiting, optional caching, and result
51
+ safeguards.
52
+
53
+ No API key is required.
54
+
55
+ ## Installation
56
+
57
+ ```console
58
+ python -m pip install usaspending-orm
59
+ ```
60
+
61
+ Requires Python 3.9 or newer.
62
+
63
+ ## Quickstart
64
+
65
+ ```python
66
+ from usaspending import USASpendingClient
67
+
68
+ with USASpendingClient() as client:
69
+ awards = (
70
+ client.awards.search()
71
+ .contracts()
72
+ .agency("National Aeronautics and Space Administration")
73
+ .recipient_search_text("Space Exploration Technologies")
74
+ .fiscal_year(2024)
75
+ .order_by("Award Amount", "desc")
76
+ .limit(5)
77
+ )
78
+
79
+ for award in awards:
80
+ amount = award.total_obligation or 0
81
+ print(f"{award.award_identifier}: {award.recipient.name} - ${amount:,.2f}")
82
+ ```
83
+
84
+ Queries are lazy. Building the chain makes no request; iteration, `.first()`,
85
+ `.all()`, `.count()`, `len(query)`, indexing, and truth-value testing execute
86
+ the appropriate USAspending operation.
87
+
88
+ ## Documentation
89
+
90
+ The full documentation covers:
91
+
92
+ - [installation and core concepts](docs/getting-started/installation.md);
93
+ - [award and transaction searches](docs/guides/search-awards.md);
94
+ - [sessions, lazy loading, caching, and production use](docs/guides/production.md);
95
+ - [generated Python API reference](docs/reference/client.md);
96
+ - [mappings to canonical USAspending endpoints](docs/usaspending-api/endpoint-mapping.md);
97
+ - [known upstream limits and contract differences](docs/usaspending-api/limitations.md).
98
+
99
+ The repository includes Read the Docs configuration for the published site.
100
+
101
+ ## Development
102
+
103
+ ```console
104
+ git clone https://github.com/planetary-society/usaspending-orm.git
105
+ cd usaspending-orm
106
+ uv sync --locked --group docs
107
+
108
+ uv run pytest -q
109
+ uv run ruff check src/ tests/
110
+ uv run ruff format --check src/ tests/
111
+ uv run --group docs mkdocs build --strict
112
+ ```
113
+
114
+ Integration tests make live USAspending requests and run separately:
115
+
116
+ ```console
117
+ uv run pytest -m integration -q
118
+ ```
119
+
120
+ Preview the documentation site locally with `uv run --group docs mkdocs serve`.
121
+
122
+ > **Note for contributors**
123
+ >
124
+ > Documentation examples are enforced, not just reviewed. `tests/test_documentation.py`
125
+ > compiles every fenced `python` block under `docs/`, checks that method names cited in
126
+ > prose exist on the public API, and executes most blocks against the live API under the
127
+ > `integration` marker. Adding or removing an example changes the runnable count, so
128
+ > update `_EXPECTED_RUNNABLE_BLOCKS` in the same change.
129
+ >
130
+ > The public API surface is snapshot-tested. When a deliberate change adds, removes, or
131
+ > alters a public callable, regenerate the fixture and review the diff:
132
+ >
133
+ > ```console
134
+ > USASPENDING_REGEN_API_SURFACE=1 uv run pytest tests/test_public_api_surface.py
135
+ > ```
136
+ >
137
+ > The published site builds from `.readthedocs.yaml`. To activate hosting: import
138
+ > `planetary-society/usaspending-orm` in Read the Docs, use `usaspending-orm` as the
139
+ > project slug, and enable pull-request builds. Keep `latest` as the default until a
140
+ > release tag contains the docs configuration, then make `stable` the default
141
+ > user-facing version while retaining `latest` for `main`.
142
+
143
+ ## Project status
144
+
145
+ The project is in beta. USAspending itself changes over time, and live federal
146
+ data is revised as agencies submit corrections. Counts and values shown in
147
+ examples should not be treated as permanent fixtures.
148
+
149
+ See [CHANGELOG.md](CHANGELOG.md) for release history and compatibility notes.
150
+
151
+ ## License
152
+
153
+ USASpending ORM is released under the [MIT License](LICENSE).
@@ -0,0 +1,124 @@
1
+ # USASpending ORM
2
+
3
+ [![Tests](https://github.com/planetary-society/usaspending-orm/actions/workflows/test.yml/badge.svg)](https://github.com/planetary-society/usaspending-orm/actions/workflows/test.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/usaspending-orm.svg)](https://pypi.org/project/usaspending-orm/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/usaspending-orm.svg)](https://pypi.org/project/usaspending-orm/)
6
+
7
+ USASpending ORM is a typed, ORM-style Python interface to the
8
+ [USAspending.gov API](https://api.usaspending.gov/). It provides fluent query
9
+ builders and navigable models for federal awards, transactions, recipients,
10
+ agencies, spending summaries, Treasury Account Symbols, and bulk downloads.
11
+
12
+ The library is maintained by [The Planetary Society](https://www.planetary.org/).
13
+
14
+ ## Why use it?
15
+
16
+ - Express complex USAspending searches through chainable Python methods.
17
+ - Work with normalized models, `date` values, and exact `Decimal` amounts.
18
+ - Navigate from awards to recipients, agencies, transactions, funding, accounts,
19
+ and subawards.
20
+ - Retain the original API response through each model's `.raw` property.
21
+ - Use built-in pagination, retries, rate limiting, optional caching, and result
22
+ safeguards.
23
+
24
+ No API key is required.
25
+
26
+ ## Installation
27
+
28
+ ```console
29
+ python -m pip install usaspending-orm
30
+ ```
31
+
32
+ Requires Python 3.9 or newer.
33
+
34
+ ## Quickstart
35
+
36
+ ```python
37
+ from usaspending import USASpendingClient
38
+
39
+ with USASpendingClient() as client:
40
+ awards = (
41
+ client.awards.search()
42
+ .contracts()
43
+ .agency("National Aeronautics and Space Administration")
44
+ .recipient_search_text("Space Exploration Technologies")
45
+ .fiscal_year(2024)
46
+ .order_by("Award Amount", "desc")
47
+ .limit(5)
48
+ )
49
+
50
+ for award in awards:
51
+ amount = award.total_obligation or 0
52
+ print(f"{award.award_identifier}: {award.recipient.name} - ${amount:,.2f}")
53
+ ```
54
+
55
+ Queries are lazy. Building the chain makes no request; iteration, `.first()`,
56
+ `.all()`, `.count()`, `len(query)`, indexing, and truth-value testing execute
57
+ the appropriate USAspending operation.
58
+
59
+ ## Documentation
60
+
61
+ The full documentation covers:
62
+
63
+ - [installation and core concepts](docs/getting-started/installation.md);
64
+ - [award and transaction searches](docs/guides/search-awards.md);
65
+ - [sessions, lazy loading, caching, and production use](docs/guides/production.md);
66
+ - [generated Python API reference](docs/reference/client.md);
67
+ - [mappings to canonical USAspending endpoints](docs/usaspending-api/endpoint-mapping.md);
68
+ - [known upstream limits and contract differences](docs/usaspending-api/limitations.md).
69
+
70
+ The repository includes Read the Docs configuration for the published site.
71
+
72
+ ## Development
73
+
74
+ ```console
75
+ git clone https://github.com/planetary-society/usaspending-orm.git
76
+ cd usaspending-orm
77
+ uv sync --locked --group docs
78
+
79
+ uv run pytest -q
80
+ uv run ruff check src/ tests/
81
+ uv run ruff format --check src/ tests/
82
+ uv run --group docs mkdocs build --strict
83
+ ```
84
+
85
+ Integration tests make live USAspending requests and run separately:
86
+
87
+ ```console
88
+ uv run pytest -m integration -q
89
+ ```
90
+
91
+ Preview the documentation site locally with `uv run --group docs mkdocs serve`.
92
+
93
+ > **Note for contributors**
94
+ >
95
+ > Documentation examples are enforced, not just reviewed. `tests/test_documentation.py`
96
+ > compiles every fenced `python` block under `docs/`, checks that method names cited in
97
+ > prose exist on the public API, and executes most blocks against the live API under the
98
+ > `integration` marker. Adding or removing an example changes the runnable count, so
99
+ > update `_EXPECTED_RUNNABLE_BLOCKS` in the same change.
100
+ >
101
+ > The public API surface is snapshot-tested. When a deliberate change adds, removes, or
102
+ > alters a public callable, regenerate the fixture and review the diff:
103
+ >
104
+ > ```console
105
+ > USASPENDING_REGEN_API_SURFACE=1 uv run pytest tests/test_public_api_surface.py
106
+ > ```
107
+ >
108
+ > The published site builds from `.readthedocs.yaml`. To activate hosting: import
109
+ > `planetary-society/usaspending-orm` in Read the Docs, use `usaspending-orm` as the
110
+ > project slug, and enable pull-request builds. Keep `latest` as the default until a
111
+ > release tag contains the docs configuration, then make `stable` the default
112
+ > user-facing version while retaining `latest` for `main`.
113
+
114
+ ## Project status
115
+
116
+ The project is in beta. USAspending itself changes over time, and live federal
117
+ data is revised as agencies submit corrections. Counts and values shown in
118
+ examples should not be treated as permanent fixtures.
119
+
120
+ See [CHANGELOG.md](CHANGELOG.md) for release history and compatibility notes.
121
+
122
+ ## License
123
+
124
+ USASpending ORM is released under the [MIT License](LICENSE).
@@ -0,0 +1,115 @@
1
+ # Caching
2
+
3
+ Caching is off by default. When enabled, the client stores successful API
4
+ responses and serves repeat requests from the store instead of the network.
5
+
6
+ ```python
7
+ from datetime import timedelta
8
+
9
+ from usaspending import USASpendingClient, config
10
+
11
+ config.configure(
12
+ cache_enabled=True,
13
+ cache_backend="file",
14
+ cache_ttl=timedelta(days=1),
15
+ )
16
+
17
+ with USASpendingClient() as client:
18
+ award = client.awards.find_by_award_id("80GSFC18C0008")
19
+ ```
20
+
21
+ Configure caching before creating a client. Settings are applied through an
22
+ observer, so a later `configure()` call rebuilds the cache wrapper rather than
23
+ leaving clients on stale settings.
24
+
25
+ ## What gets cached
26
+
27
+ The unit of caching is one HTTP request, not one query. A cache entry is keyed
28
+ on the endpoint and the full request payload, so two searches that differ in any
29
+ filter, sort, or page are separate entries, and a repeat of the identical
30
+ request is a hit.
31
+
32
+ Because the unit is the request, caching covers everything the library sends:
33
+ search pages, count calls, award detail lookups, and the follow-up requests
34
+ behind lazy relationships. A loop that reads `award.recipient.location` for many
35
+ awards still issues one request per award the first time, but pays nothing on a
36
+ second pass over the same awards.
37
+
38
+ Two things are deliberately not stored:
39
+
40
+ - **Failures.** Errors are never cached, so a transient outage does not poison
41
+ the store. The next call re-issues the request.
42
+ - **Empty results.** A response the client could not interpret is not stored,
43
+ and the request falls back to the network.
44
+
45
+ ## Cache misses are never fatal
46
+
47
+ Reading from the cache is best-effort. If the store is unreadable, locked, or
48
+ corrupt, the client logs a warning and issues the request normally. A broken
49
+ cache degrades performance, never correctness.
50
+
51
+ API errors are the exception to that fallback: `APIError`, `HTTPError`,
52
+ `RateLimitError`, and `ValidationError` propagate to the caller rather than
53
+ being retried uncached, because they describe the request rather than the cache.
54
+
55
+ ## Backends
56
+
57
+ `cache_backend="memory"` keeps entries in the process and discards them on exit.
58
+ It suits tests and short scripts, and avoids writing anything to disk.
59
+
60
+ `cache_backend="file"` is the default and writes pickled responses under
61
+ `cache_dir`, which defaults to `$XDG_CACHE_HOME/usaspending` or
62
+ `~/.cache/usaspending`. Entries survive the process, so a later run reuses what
63
+ an earlier one fetched. That is what makes an interrupted batch job cheap to
64
+ restart, and what lets a script re-run during development stop paying for the
65
+ same pages.
66
+
67
+ Reuse depends on the request serializing identically each time. The library
68
+ sorts the values of match-any filters for that reason, so a filter built from a
69
+ Python set produces the same request, and therefore the same cache entry, on
70
+ every run.
71
+
72
+ !!! warning "The file backend unpickles data it reads"
73
+
74
+ Unpickling executes code, so the cache directory is a trust boundary. The
75
+ library creates it with `0700` permissions and restores those permissions if
76
+ they have been widened, but do not point `cache_dir` at a shared,
77
+ world-writable, or otherwise untrusted location, and do not use a directory
78
+ another user can write to.
79
+
80
+ ## Expiry and namespaces
81
+
82
+ `cache_ttl` sets how long an entry stays fresh; the default is one week. An
83
+ entry older than the TTL is recomputed on next use. `configure()` accepts either
84
+ a `timedelta` or a number of seconds.
85
+
86
+ Federal spending data is revised after publication, so the TTL is a correctness
87
+ decision as much as a performance one. A long TTL on a reporting job can serve
88
+ figures that agencies have since corrected. Prefer hours or days for anything
89
+ whose numbers get published, and reserve a week for exploratory work.
90
+
91
+ `cache_namespace` is part of every key, so two projects sharing a `cache_dir` do
92
+ not read each other's entries. Change it to isolate a workload, or to abandon an
93
+ existing set of entries wholesale.
94
+
95
+ `cache_timeout` bounds how long a caller waits for another worker that is
96
+ already computing the same entry, which keeps concurrent callers from
97
+ stampeding the same request.
98
+
99
+ ## Clearing the cache
100
+
101
+ There is no public API for clearing the cache. With the file backend, delete the
102
+ files under `cache_dir`; with the memory backend, ending the process is enough.
103
+ Changing `cache_namespace` also abandons the previous entries without deleting
104
+ them.
105
+
106
+ ## Choosing a TTL
107
+
108
+ - Interactive analysis over a stable slice of history: hours to a day.
109
+ - Repeatedly re-running the same broad query while developing: a day or more,
110
+ since the point is to stop paying for the same pages.
111
+ - Anything producing published figures: short, or disabled, so a correction
112
+ upstream is not masked by a stale entry.
113
+
114
+ See [Production use](../guides/production.md) for how caching interacts with
115
+ rate limiting and long batch runs.
@@ -0,0 +1,52 @@
1
+ # USAspending data model
2
+
3
+ The library presents several related grains of federal spending data.
4
+
5
+ ## Prime awards
6
+
7
+ An award is the durable agreement between the federal government and a
8
+ recipient: a contract, grant, loan, direct payment, other assistance, or
9
+ Indefinite Delivery Vehicle. An award accumulates financial activity over its
10
+ lifetime.
11
+
12
+ `Award` and its subclasses normalize the details endpoint and expose
13
+ relationships such as recipient, agencies, period of performance, place of
14
+ performance, transactions, accounts, funding records, and subawards.
15
+
16
+ ## Transactions
17
+
18
+ A transaction is an action that changes or reports an award. Examples include
19
+ the initial obligation, a contract modification, an incremental funding
20
+ action, or a deobligation.
21
+
22
+ Transaction searches therefore have a different grain from award searches:
23
+
24
+ - award search returns one row per matching award;
25
+ - global transaction search returns one row per matching action;
26
+ - `award.transactions` returns actions belonging to one award.
27
+
28
+ Summing transaction amounts and reading an award's current total obligation are
29
+ different analytical operations.
30
+
31
+ ## Subawards
32
+
33
+ A subaward records funding passed from a prime recipient to another
34
+ organization. Subawards are reported separately and do not share every field or
35
+ filter available for prime awards.
36
+
37
+ ## Accounts and funding records
38
+
39
+ Federal accounts and Treasury Account Symbols describe the appropriations
40
+ accounts behind spending. Award funding records connect transactions to those
41
+ accounts and agencies. These records are useful when the question concerns
42
+ budget authority or the source of funds rather than only the recipient and
43
+ award.
44
+
45
+ ## Aggregations
46
+
47
+ Spending-by-category endpoints return grouped totals by dimensions such as
48
+ recipient or geography. Their rows are summaries, not awards, and use dedicated
49
+ models.
50
+
51
+ See [Terminology](../usaspending-api/terminology.md) for links to canonical
52
+ USAspending definitions.
@@ -0,0 +1,68 @@
1
+ # Query execution
2
+
3
+ Query builders separate request construction from execution.
4
+
5
+ ## Lazy construction
6
+
7
+ Filter, sort, and limit calls modify the builder without making an HTTP
8
+ request:
9
+
10
+ ```python
11
+ query = (
12
+ client.awards.search()
13
+ .contracts()
14
+ .agency("National Aeronautics and Space Administration")
15
+ .fiscal_year(2024)
16
+ .limit(25)
17
+ )
18
+ ```
19
+
20
+ The request begins when code:
21
+
22
+ - iterates over the query;
23
+ - calls `.all()`, `.first()`, or `.count()`;
24
+ - calls `len(query)`;
25
+ - indexes or slices the query;
26
+ - evaluates its truth value.
27
+
28
+ ## Pagination
29
+
30
+ Iteration requests pages as needed and stops when the API is exhausted or a
31
+ configured bound is reached. Query builders expose list-like operations, but
32
+ they do not pre-load the entire result set.
33
+
34
+ `.all()` materializes the bounded query into a list. Prefer iteration when
35
+ streaming pages is sufficient.
36
+
37
+ ## Count consistency
38
+
39
+ `count()` uses a companion endpoint when USAspending provides one. Library
40
+ limits are applied to the reported value so these expressions agree for a
41
+ bounded query:
42
+
43
+ ```python
44
+ query = client.awards.search().contracts().fiscal_year(2024).limit(10)
45
+
46
+ query.count()
47
+ len(query)
48
+ len(query.all())
49
+ ```
50
+
51
+ Some upstream search and count endpoints accept different filters. When a
52
+ correct count cannot be requested, the library raises `ValidationError` rather
53
+ than returning a misleading number.
54
+
55
+ ## Immutable chaining
56
+
57
+ Fluent methods return a clone with the new filter, sort, or bound. A partly
58
+ built query can therefore be used as an immutable template:
59
+
60
+ ```python
61
+ base = client.awards.search().contracts().fiscal_year(2024)
62
+ california = base.place_of_performance_locations(
63
+ {"country_code": "USA", "state_code": "CA"}
64
+ )
65
+ ```
66
+
67
+ After this call, `base` remains unchanged and `california` carries the added
68
+ location filter.
@@ -0,0 +1,77 @@
1
+ # Core concepts
2
+
3
+ ## Client
4
+
5
+ `USASpendingClient` owns the HTTP session, retry behavior, rate limiter, and
6
+ resource entry points. Prefer a `with` block so the session closes reliably.
7
+
8
+ ```python
9
+ from usaspending import USASpendingClient
10
+
11
+ with USASpendingClient() as client:
12
+ award = client.awards.find_by_award_id("80GSFC18C0008")
13
+ ```
14
+
15
+ ## Resources
16
+
17
+ Client properties group related upstream operations:
18
+
19
+ | Resource | Typical purpose |
20
+ | --------------------- | -------------------------------------------------- |
21
+ | `client.awards` | Find and search prime awards |
22
+ | `client.transactions` | Search transactions globally or for one award |
23
+ | `client.subawards` | Search subawards |
24
+ | `client.recipients` | Find and search recipient organizations |
25
+ | `client.agencies` | Agency summaries, subagencies, and office searches |
26
+ | `client.references` | Current API reference data, including DEF codes |
27
+ | `client.spending` | Aggregated spending by recipient or geography |
28
+ | `client.tas` | Treasury Account Symbol hierarchy |
29
+ | `client.downloads` | Queue server-side bulk exports |
30
+
31
+ ## Query builders
32
+
33
+ Calling `.search()` returns a fluent builder. Filter methods clone it and return
34
+ a new query, so a shared base query can safely feed consumers that need
35
+ different filters.
36
+
37
+ ```python
38
+ query = (
39
+ client.awards.search()
40
+ .contracts()
41
+ .agency("National Aeronautics and Space Administration")
42
+ .fiscal_year(2024)
43
+ .limit(25)
44
+ )
45
+ ```
46
+
47
+ Query builders handle pagination and expose a list-like interface, but they are
48
+ not in-memory lists. Some operations make separate API requests; see
49
+ [Query execution](../explanation/query-execution.md).
50
+
51
+ ## Models
52
+
53
+ Results are model objects such as `Award`, `Transaction`, `Recipient`, and
54
+ `Agency`. Models provide:
55
+
56
+ - normalized snake-case properties;
57
+ - parsed dates and decimal amounts;
58
+ - `.raw` access to the original response;
59
+ - related objects or query builders where the upstream data supports them.
60
+
61
+ Optional fields return `None` when the API does not report a value. A real
62
+ zero-dollar amount remains `Decimal("0.00")`.
63
+
64
+ ## Lazy loading and sessions
65
+
66
+ Some relationships require another API request. Access them while the creating
67
+ client is open. A model can be reattached to a new client when later lazy loads
68
+ are required:
69
+
70
+ ```python
71
+ with USASpendingClient() as client:
72
+ award = client.awards.find_by_award_id("80GSFC18C0008")
73
+
74
+ with USASpendingClient() as new_client:
75
+ award.reattach(new_client, recursive=True)
76
+ print(award.transactions.count())
77
+ ```