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.
- usaspending_orm-0.7.3/.gitignore +6 -0
- usaspending_orm-0.7.3/CHANGELOG.md +81 -0
- usaspending_orm-0.7.3/CLAUDE.md +243 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/PKG-INFO +196 -42
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/README.md +185 -30
- usaspending_orm-0.7.3/api-docs-links.md +258 -0
- usaspending_orm-0.7.3/poetry.lock +585 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/pyproject.toml +49 -12
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/__init__.py +69 -67
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/cli/download_award.py +4 -7
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/client.py +204 -82
- usaspending_orm-0.7.3/src/usaspending/config.py +210 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/download/__init__.py +2 -2
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/download/job.py +33 -32
- usaspending_orm-0.7.3/src/usaspending/download/manager.py +248 -0
- usaspending_orm-0.7.3/src/usaspending/exceptions.py +295 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/logging_config.py +16 -22
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/__init__.py +58 -51
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/agency.py +107 -71
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/award.py +115 -133
- usaspending_orm-0.7.3/src/usaspending/models/award_account.py +203 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/award_factory.py +11 -30
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/award_types.py +58 -27
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/base_model.py +39 -34
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/contract.py +27 -26
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/district_spending.py +5 -5
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/download.py +12 -11
- usaspending_orm-0.7.3/src/usaspending/models/federal_account.py +136 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/funding.py +100 -51
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/grant.py +28 -23
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/idv.py +65 -29
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/lazy_record.py +14 -29
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/loan.py +17 -19
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/location.py +30 -39
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/period_of_performance.py +13 -17
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/recipient.py +26 -32
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/recipient_business_categories.py +5 -12
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/recipient_spending.py +9 -8
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/spending.py +10 -9
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/state_spending.py +4 -4
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/subaward.py +37 -37
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/subtier_agency.py +11 -12
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/models/transaction.py +5 -4
- usaspending_orm-0.7.3/src/usaspending/models/treasury_account_symbol.py +258 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/__init__.py +51 -37
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/agencies_search.py +83 -20
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/agency_award_summary.py +12 -12
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/agency_query.py +11 -13
- usaspending_orm-0.7.3/src/usaspending/queries/award_accounts_query.py +194 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/award_query.py +7 -4
- usaspending_orm-0.7.3/src/usaspending/queries/awarding_agencies_search.py +52 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/awards_search.py +76 -80
- usaspending_orm-0.7.3/src/usaspending/queries/base_query.py +141 -0
- usaspending_orm-0.7.3/src/usaspending/queries/client_side_query_builder.py +309 -0
- usaspending_orm-0.7.3/src/usaspending/queries/federal_accounts_query.py +205 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/filters.py +21 -71
- usaspending_orm-0.7.3/src/usaspending/queries/funding_agencies_search.py +52 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/funding_search.py +12 -18
- usaspending_orm-0.7.3/src/usaspending/queries/idv_child_awards.py +188 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/query_builder.py +199 -300
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/recipient_query.py +21 -24
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/recipients_search.py +10 -10
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/single_resource_base.py +23 -15
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/spending_search.py +17 -28
- usaspending_orm-0.7.3/src/usaspending/queries/sub_agency_query.py +210 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/subawards_search.py +32 -30
- usaspending_orm-0.7.3/src/usaspending/queries/tas_codes_query.py +213 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/queries/transactions_search.py +62 -47
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/__init__.py +14 -8
- usaspending_orm-0.7.3/src/usaspending/resources/agency_resource.py +203 -0
- usaspending_orm-0.7.3/src/usaspending/resources/award_accounts_resource.py +41 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/award_resource.py +12 -15
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/base_resource.py +1 -0
- usaspending_orm-0.7.3/src/usaspending/resources/download_resource.py +179 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/funding_resource.py +7 -4
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/recipients_resource.py +16 -13
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/spending_resource.py +3 -2
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/subawards_resource.py +4 -3
- usaspending_orm-0.7.3/src/usaspending/resources/tas_resource.py +77 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/resources/transactions_resource.py +3 -2
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/formatter.py +53 -154
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/rate_limit.py +7 -10
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/retry.py +22 -29
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/validations.py +32 -7
- usaspending_orm-0.7.3/tests/__init__.py +0 -0
- usaspending_orm-0.7.3/tests/conftest.py +202 -0
- usaspending_orm-0.7.3/tests/fixtures/agency.json +79 -0
- usaspending_orm-0.7.3/tests/fixtures/agency_autocomplete.json +387 -0
- usaspending_orm-0.7.3/tests/fixtures/agency_award_summary.json +8 -0
- usaspending_orm-0.7.3/tests/fixtures/agency_subagencies.json +116 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/accounts.json +32 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/award_funding_grant.json +241 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/contract.json +247 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/grant.json +180 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/idv.json +241 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/idv_awards.json +181 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/loan.json +140 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/search_results_contracts.json +376 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/search_results_grants.json +259 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/search_results_idvs.json +258 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/search_results_subawards.json +177 -0
- usaspending_orm-0.7.3/tests/fixtures/awards/transactions.json +50 -0
- usaspending_orm-0.7.3/tests/fixtures/download_assistance.json +42 -0
- usaspending_orm-0.7.3/tests/fixtures/download_search.json +42 -0
- usaspending_orm-0.7.3/tests/fixtures/download_status.json +10 -0
- usaspending_orm-0.7.3/tests/fixtures/recipient_university.json +75 -0
- usaspending_orm-0.7.3/tests/fixtures/recipients_search.json +45 -0
- usaspending_orm-0.7.3/tests/fixtures/spending_by_award_contracts.json +141 -0
- usaspending_orm-0.7.3/tests/fixtures/spending_by_district.json +88 -0
- usaspending_orm-0.7.3/tests/fixtures/spending_by_recipient.json +178 -0
- usaspending_orm-0.7.3/tests/fixtures/spending_by_state.json +25 -0
- usaspending_orm-0.7.3/tests/fixtures/tas_agencies.json +641 -0
- usaspending_orm-0.7.3/tests/fixtures/tas_codes.json +164 -0
- usaspending_orm-0.7.3/tests/fixtures/tas_federal_accounts.json +148 -0
- usaspending_orm-0.7.3/tests/fixtures/top_recipients_params.json +26 -0
- usaspending_orm-0.7.3/tests/fixtures/top_recipients_response.json +98 -0
- usaspending_orm-0.7.3/tests/mocks/README.md +320 -0
- usaspending_orm-0.7.3/tests/mocks/__init__.py +6 -0
- usaspending_orm-0.7.3/tests/mocks/mock_client.py +759 -0
- usaspending_orm-0.7.3/tests/mocks/response_builder.py +188 -0
- usaspending_orm-0.7.3/tests/mocks/test_mock_client.py +275 -0
- usaspending_orm-0.7.3/tests/models/__init__.py +1 -0
- usaspending_orm-0.7.3/tests/models/test_agency.py +376 -0
- usaspending_orm-0.7.3/tests/models/test_agency_subagencies.py +231 -0
- usaspending_orm-0.7.3/tests/models/test_agency_tas_integration.py +172 -0
- usaspending_orm-0.7.3/tests/models/test_award_account.py +282 -0
- usaspending_orm-0.7.3/tests/models/test_award_agency_integration.py +264 -0
- usaspending_orm-0.7.3/tests/models/test_award_common.py +266 -0
- usaspending_orm-0.7.3/tests/models/test_award_decimal_precision.py +160 -0
- usaspending_orm-0.7.3/tests/models/test_award_factory.py +235 -0
- usaspending_orm-0.7.3/tests/models/test_award_lazy_loading.py +225 -0
- usaspending_orm-0.7.3/tests/models/test_award_office_integration.py +172 -0
- usaspending_orm-0.7.3/tests/models/test_award_type_constants.py +442 -0
- usaspending_orm-0.7.3/tests/models/test_award_types.py +280 -0
- usaspending_orm-0.7.3/tests/models/test_base_model.py +623 -0
- usaspending_orm-0.7.3/tests/models/test_district_spending.py +146 -0
- usaspending_orm-0.7.3/tests/models/test_federal_account.py +159 -0
- usaspending_orm-0.7.3/tests/models/test_funding.py +422 -0
- usaspending_orm-0.7.3/tests/models/test_lazy_load.py +233 -0
- usaspending_orm-0.7.3/tests/models/test_location.py +284 -0
- usaspending_orm-0.7.3/tests/models/test_period_of_performance.py +213 -0
- usaspending_orm-0.7.3/tests/models/test_recipient.py +682 -0
- usaspending_orm-0.7.3/tests/models/test_recipient_business_categories.py +790 -0
- usaspending_orm-0.7.3/tests/models/test_recipient_spending.py +183 -0
- usaspending_orm-0.7.3/tests/models/test_spending.py +87 -0
- usaspending_orm-0.7.3/tests/models/test_state_spending.py +45 -0
- usaspending_orm-0.7.3/tests/models/test_subaward.py +334 -0
- usaspending_orm-0.7.3/tests/models/test_subtier_agency.py +166 -0
- usaspending_orm-0.7.3/tests/models/test_transaction.py +219 -0
- usaspending_orm-0.7.3/tests/models/test_treasury_account_symbol.py +215 -0
- usaspending_orm-0.7.3/tests/queries/test_agencies_search.py +361 -0
- usaspending_orm-0.7.3/tests/queries/test_agency_award_summary.py +270 -0
- usaspending_orm-0.7.3/tests/queries/test_agency_query.py +231 -0
- usaspending_orm-0.7.3/tests/queries/test_award_accounts_query.py +279 -0
- usaspending_orm-0.7.3/tests/queries/test_awards_search.py +889 -0
- usaspending_orm-0.7.3/tests/queries/test_client_side_query_builder.py +159 -0
- usaspending_orm-0.7.3/tests/queries/test_federal_accounts_query.py +488 -0
- usaspending_orm-0.7.3/tests/queries/test_filters.py +487 -0
- usaspending_orm-0.7.3/tests/queries/test_funding_search.py +263 -0
- usaspending_orm-0.7.3/tests/queries/test_idv_child_awards.py +411 -0
- usaspending_orm-0.7.3/tests/queries/test_query_builder.py +159 -0
- usaspending_orm-0.7.3/tests/queries/test_query_builder_list_behavior.py +379 -0
- usaspending_orm-0.7.3/tests/queries/test_query_builder_pagination.py +406 -0
- usaspending_orm-0.7.3/tests/queries/test_recipient_query.py +143 -0
- usaspending_orm-0.7.3/tests/queries/test_recipients_search.py +468 -0
- usaspending_orm-0.7.3/tests/queries/test_search_query_builder.py +616 -0
- usaspending_orm-0.7.3/tests/queries/test_single_resource_base.py +29 -0
- usaspending_orm-0.7.3/tests/queries/test_spending_search.py +234 -0
- usaspending_orm-0.7.3/tests/queries/test_spending_search_count.py +309 -0
- usaspending_orm-0.7.3/tests/queries/test_sub_agency_query.py +246 -0
- usaspending_orm-0.7.3/tests/queries/test_subawards_search.py +204 -0
- usaspending_orm-0.7.3/tests/queries/test_tas_codes_query.py +237 -0
- usaspending_orm-0.7.3/tests/queries/test_transactions_search.py +126 -0
- usaspending_orm-0.7.3/tests/resources/test_agency_resource.py +333 -0
- usaspending_orm-0.7.3/tests/resources/test_award_resource.py +375 -0
- usaspending_orm-0.7.3/tests/resources/test_funding_resource.py +79 -0
- usaspending_orm-0.7.3/tests/resources/test_recipients_resource.py +29 -0
- usaspending_orm-0.7.3/tests/resources/test_spending_resource.py +48 -0
- usaspending_orm-0.7.3/tests/resources/test_subawards_resource.py +103 -0
- usaspending_orm-0.7.3/tests/resources/test_tas_resource.py +130 -0
- usaspending_orm-0.7.3/tests/resources/test_transactions_resource.py +64 -0
- usaspending_orm-0.7.3/tests/test_award_accounts_integration.py +159 -0
- usaspending_orm-0.7.3/tests/test_cache_fallback.py +122 -0
- usaspending_orm-0.7.3/tests/test_client.py +413 -0
- usaspending_orm-0.7.3/tests/test_client_caching.py +69 -0
- usaspending_orm-0.7.3/tests/test_client_funding.py +202 -0
- usaspending_orm-0.7.3/tests/test_client_rate_limit.py +66 -0
- usaspending_orm-0.7.3/tests/test_client_security.py +59 -0
- usaspending_orm-0.7.3/tests/test_client_transactions.py +37 -0
- usaspending_orm-0.7.3/tests/test_config.py +142 -0
- usaspending_orm-0.7.3/tests/test_download_resource.py +584 -0
- usaspending_orm-0.7.3/tests/test_exceptions.py +312 -0
- usaspending_orm-0.7.3/tests/test_integration.py +210 -0
- usaspending_orm-0.7.3/tests/test_logging_config.py +292 -0
- usaspending_orm-0.7.3/tests/test_mock_client_example.py +233 -0
- usaspending_orm-0.7.3/tests/test_readme_examples.py +107 -0
- usaspending_orm-0.7.3/tests/test_spending_integration.py +54 -0
- usaspending_orm-0.7.3/tests/utils/__init__.py +5 -0
- usaspending_orm-0.7.3/tests/utils/decimal_helpers.py +50 -0
- usaspending_orm-0.7.3/tests/utils/test_formatter.py +301 -0
- usaspending_orm-0.7.3/tests/utils/test_rate_limit.py +362 -0
- usaspending_orm-0.7.3/tests/utils/test_retry.py +124 -0
- usaspending_orm-0.7.3/tests/utils/test_retry_session_reset.py +354 -0
- usaspending_orm-0.7.3/tests/utils/test_text_formatter.py +313 -0
- usaspending_orm-0.7.3/tests/utils/test_validations.py +226 -0
- usaspending_orm-0.7.3/uv.lock +544 -0
- usaspending_orm-0.7.0/src/usaspending/config.py +0 -119
- usaspending_orm-0.7.0/src/usaspending/download/manager.py +0 -140
- usaspending_orm-0.7.0/src/usaspending/exceptions.py +0 -71
- usaspending_orm-0.7.0/src/usaspending/queries/awarding_agencies_search.py +0 -16
- usaspending_orm-0.7.0/src/usaspending/queries/funding_agencies_search.py +0 -20
- usaspending_orm-0.7.0/src/usaspending/queries/sub_agency_query.py +0 -177
- usaspending_orm-0.7.0/src/usaspending/resources/agency_resource.py +0 -105
- usaspending_orm-0.7.0/src/usaspending/resources/download_resource.py +0 -102
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/LICENSE +0 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/cli/__init__.py +0 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/__init__.py +0 -0
- {usaspending_orm-0.7.0 → usaspending_orm-0.7.3}/src/usaspending/utils/special_cases.yaml +0 -0
|
@@ -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.**
|