Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
fe0eb40
[DEV-14145] Use isinstance() instead of type is
aguest-kc Dec 11, 2025
2a226bd
[DEV-14145] Add DuckDB for file A
aguest-kc Dec 11, 2025
b07651c
Merge branch 'qat' into ftr/dev-14145-duckdb-file-a-downloads
aguest-kc Dec 16, 2025
920cbc9
[DEV-14145] black fixes
aguest-kc Dec 16, 2025
146493f
Merge branch 'qat' into ftr/dev-14145-duckdb-file-a-downloads
aguest-kc Dec 16, 2025
34190b7
[DEV-14094] initial work for EMR downloads
sethstoudenmier Dec 31, 2025
5f49a1d
[DEV-14094] set retry policy to 2
sethstoudenmier Jan 2, 2026
766ffb0
[DEV-14110] initial_report_date and last_modified_date changed to Dat…
loreleitrimberger Jan 5, 2026
ce680e7
[DEV-14110] update transaction_delta_view in migration
loreleitrimberger Jan 6, 2026
826f1ac
[DEV-14094] update sparkSubmit
sethstoudenmier Jan 6, 2026
20aaa3d
Merge branch 'qat' into ftr/dev-14145-duckdb-file-a-downloads
aguest-kc Jan 7, 2026
ba1b194
[DEV-14145] flake8 fix
aguest-kc Jan 7, 2026
bef41a2
[DEV-14110] split up migrations to avoid race condition
loreleitrimberger Jan 7, 2026
d46fd08
[DEV-14110] change DateType to TimestampType last_modified_date
loreleitrimberger Jan 7, 2026
70a24b6
Merge pull request #4573 from fedspendingtransparency/qat
aguest-kc Jan 9, 2026
89909e4
[DEV-14110] update types
loreleitrimberger Jan 9, 2026
46ea86b
[DEV-14110] fix transaction_search df and update tests
loreleitrimberger Jan 9, 2026
0f7ed93
Merge tag 'qat' of https://github.com/fedspendingtransparency/usaspen…
sethstoudenmier Jan 13, 2026
d1ecdc6
[DEV-14094] comment out retry policy
sethstoudenmier Jan 13, 2026
0e19cd5
Merge pull request #4571 from fedspendingtransparency/ftr/dev-14094-s…
sethstoudenmier Jan 23, 2026
37c7b0b
[DEV-14110] - updating fixtures
zachflanders-frb Jan 23, 2026
bca13bd
Merge branch 'ftr/dev-14110-transaction-search-datetime' of https://g…
zachflanders-frb Jan 23, 2026
34acab5
[DEV-14110] - updating fixtures and orm logic to return datetime
zachflanders-frb Jan 23, 2026
98a5e35
Merge remote-tracking branch 'origin/qat' into ftr/dev-14145-duckdb-f…
aguest-kc Jan 26, 2026
d4f55bf
Merge branch 'qat' into ftr/dev-14145-duckdb-file-a-downloads
aguest-kc Jan 26, 2026
37f59cf
Merge branch 'ftr/dev-14145-duckdb-file-a-downloads' of https://githu…
aguest-kc Jan 26, 2026
31bf105
[DEV-14110] - updating fixtures in conftest
zachflanders-frb Jan 26, 2026
f901da3
[DEV-14094] Update to older syntax and fix TODOs
sethstoudenmier Jan 26, 2026
0241486
[DEV-12858] Add and configure ruff linter
aguest-kc Jan 26, 2026
72a7bf3
Merge pull request #4581 from fedspendingtransparency/ftr/dev-14094-u…
sethstoudenmier Jan 26, 2026
a1d393e
[DEV-12858] Add flake8-bugber rules
aguest-kc Jan 26, 2026
bc5064c
[DEV-12858] Log changed files
aguest-kc Jan 26, 2026
83c74a9
[DEV-12858] Check if changed files is an empty string
aguest-kc Jan 26, 2026
c4da924
[DEV-14110] - add missing migration and update column type
zachflanders-frb Jan 26, 2026
8972c09
[DEV-14110] - update migration to be consistent with model
zachflanders-frb Jan 26, 2026
f82a47f
[DEV-12858] Update workflow comments
aguest-kc Jan 27, 2026
19d339c
[DEV-12858] Ruff linter fix
aguest-kc Jan 27, 2026
181d2c9
[DEV-12858] Remove black and flake8
aguest-kc Jan 27, 2026
6d34b83
[DEV-12858] Add ruff to pre-commit and clean up workflow
aguest-kc Jan 27, 2026
fd3ac6f
[DEV-12858] Add type annotation linting rules
aguest-kc Jan 27, 2026
ec830fc
[DEV-12858] Update files as test for ruff linter
aguest-kc Jan 27, 2026
07cfecc
[DEV-14145] Fix last_modified_date column type
aguest-kc Jan 27, 2026
8a00484
Merge pull request #4584 from fedspendingtransparency/ftr/dev-14094-s…
sethstoudenmier Jan 28, 2026
86ce55d
Merge branch 'qat' into ftr/dev-14145-duckdb-file-a-downloads
aguest-kc Jan 28, 2026
5130212
[DEV-14145] Fix merge conflict
aguest-kc Jan 28, 2026
0829bbd
[DEV-14145] Remove blank line
aguest-kc Jan 28, 2026
c404f73
Merge branch 'qat' into ftr/dev-12858-add-ruff
aguest-kc Jan 28, 2026
16aeed3
[DEV-14110] - update to consistently return dates via the API
zachflanders-frb Jan 28, 2026
b75d263
Merge branch 'qat' into ftr/dev-14110-transaction-search-datetime
zachflanders-frb Jan 28, 2026
b7b929a
Merge pull request #4563 from fedspendingtransparency/ftr/dev-14145-d…
aguest-kc Jan 28, 2026
c3a1a52
[DEV-14110] - update transaction search dataframe
zachflanders-frb Jan 28, 2026
dd3415f
Merge branch 'ftr/dev-14110-transaction-search-datetime' of https://g…
zachflanders-frb Jan 28, 2026
1c2054e
Merge branch 'qat' into ftr/dev-14110-transaction-search-datetime
zachflanders-frb Jan 28, 2026
9bc7e56
Merge pull request #4570 from fedspendingtransparency/ftr/dev-14110-t…
zachflanders-frb Jan 29, 2026
6780389
Merge branch 'qat' into ftr/dev-12858-add-ruff
aguest-kc Jan 29, 2026
9c47648
Merge pull request #4582 from fedspendingtransparency/ftr/dev-12858-a…
aguest-kc Jan 29, 2026
4c9d4d5
Fix formatting errors for the staging deploy
sethstoudenmier Jan 29, 2026
c6d0cbc
Merge pull request #4587 from fedspendingtransparency/fix-formatting-…
sethstoudenmier Jan 29, 2026
8c56255
[DEV-14146] Update use of config for local in Spark
sethstoudenmier Feb 3, 2026
df8224c
Merge pull request #4590 from fedspendingtransparency/fix/dev-14146-u…
sethstoudenmier Feb 5, 2026
6b7af17
[DEV-14451] Add new assistance type codes
aguest-kc Feb 5, 2026
aaac2b6
[DEV-14451] Ruff ignore files with test data
aguest-kc Feb 5, 2026
9203d0f
[DEV-14451] Ruff fix
aguest-kc Feb 5, 2026
0816926
[DEV-14451] Test fixes
aguest-kc Feb 5, 2026
b799dcd
Updating table spec to use dataclasses
zachflanders-frb Feb 5, 2026
1cd32ae
Merge branch 'qat' into ftr/dev-14451-new-assistance-type-codes
aguest-kc Feb 5, 2026
7577cfd
Merge pull request #4592 from fedspendingtransparency/ftr/dev-14451-n…
aguest-kc Feb 5, 2026
be94f13
Addressing ruff issues
zachflanders-frb Feb 5, 2026
53d8ff5
Addressing ruff issues
zachflanders-frb Feb 5, 2026
3800222
Fixing tests
zachflanders-frb Feb 6, 2026
cbdf3a0
Updating default custom_schema value
zachflanders-frb Feb 6, 2026
6b55ae0
Merge branch 'ftr/table-spec-dataclass' into ftr/dev-14453-transactio…
zachflanders-frb Feb 6, 2026
f89c21b
cleaning up tests
zachflanders-frb Feb 6, 2026
c37c31a
resolving variables for rdd.map
zachflanders-frb Feb 6, 2026
855270b
Merge branch 'qat' into ftr/table-spec-dataclass
zachflanders-frb Feb 6, 2026
9f60457
Merge branch 'ftr/table-spec-dataclass' into ftr/dev-14453-transactio…
zachflanders-frb Feb 6, 2026
2f10336
[DEV-14453] WIP
zachflanders-frb Feb 11, 2026
d2bb7cf
[DEV-14453] - Reworking loaders to add partitions and use CDF
zachflanders-frb Feb 19, 2026
19539c3
[DEV-14453] - Adding deletes to transaction normalized mixin
zachflanders-frb Feb 23, 2026
679cfd8
[DEV-14453] - Update date parse util
zachflanders-frb Feb 23, 2026
e677507
[DEV-14453] - Update date parse util
zachflanders-frb Feb 25, 2026
33534d7
[DEV-14453] - Update save mode for detached award procurement
zachflanders-frb Feb 25, 2026
4d7678a
[DEV-14453] - Update date parse util
zachflanders-frb Feb 25, 2026
b3877e0
[DEV-14453] - Update column handling for pyspark 3.4
zachflanders-frb Feb 26, 2026
c359d4a
[DEV-14453] - Adding more logging
zachflanders-frb Mar 2, 2026
7f07242
[DEV-14453] - Update insert and delete dfs to just get new rows
zachflanders-frb Mar 19, 2026
be1ff6d
[DEV-14453] - removing counts to speed up job
zachflanders-frb Mar 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions .github/workflows/code-style-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ jobs:
- name: Checkout Source Repository
uses: actions/checkout@v4

- name: Get Changed Python Files
id: changed-python-files
uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62
with:
files: |
**.py
separator: " "

- name: Check If `changed-python-files` Is An Empty String
if: steps.changed-python-files.outputs.all_changed_files == ''
run: echo "No changed files detected"

- name: Set Combined ENV
run: |
echo "DATA_BROKER_DATABASE_URL=postgres://$BROKER_DB_USER:$BROKER_DB_PASSWORD@$BROKER_DB_HOST:$BROKER_DB_PORT/$BROKER_DB_NAME" >> $GITHUB_ENV
Expand All @@ -52,11 +64,10 @@ jobs:
- name: Init Python Environment
uses: ./.github/actions/init-python-environment

- name: Run Flake8
run: flake8

- name: Run Black
run: black --check --diff .
# changed-python-files could be an empty string, which would cause `ruff check` to be run against the entire project.
- name: Run Ruff Linter
if: steps.changed-python-files.outputs.all_changed_files != ''
run: ruff check ${{ steps.changed-python-files.outputs.all_changed_files }}

- name: Run Check For Endpoint Documentation
run: python manage.py check_for_endpoint_documentation
Expand Down
17 changes: 5 additions & 12 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,9 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: debug-statements
- repo: https://github.com/pycqa/flake8.git
rev: 7.1.0
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.14
hooks:
- id: flake8
language_version: python3.10.12
- repo: https://github.com/psf/black
rev: 24.10.0
hooks:
- id: black
language_version: python3.10.12
additional_dependencies:
- "click==8.0.4"
- id: ruff-check
types_or: [ python, pyi ] # avoid linting other python file types like Jupyter notebooks
77 changes: 68 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ readme = 'README.md'
license = "CC0-1.0"
license-files = ["LICENSE"]
requires-python = '>=3.10'
classifiers=[
classifiers = [
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
Expand Down Expand Up @@ -97,11 +97,9 @@ dependencies = [

[project.optional-dependencies]
dev = [
"black==24.10.0",
"click==8.1.7",
"docker==7.0.0",
"dredd-hooks==0.2.0",
"flake8==7.1.0",
"importlib-metadata==8.5.0",
"mock==5.1.*",
"model-bakery==1.17.*",
Expand All @@ -112,6 +110,7 @@ dev = [
"pytest-django==4.8.*",
"pytest-pretty==1.2.*",
"pytest-xdist==3.5.*",
"ruff==0.14.14",
]
spark = [
"delta-spark==3.2.*",
Expand All @@ -138,14 +137,13 @@ DJANGO_SETTINGS_MODULE = "usaspending_api.settings"
addopts = "--cov=usaspending_api"
markers = [
"signal_handling: Mark all tests that import the signal library and invoke signals. This MUST be done on the main thread, and can cause errors if pytest-xdist subordinates parellel test sessions to background threads.",

# These are "auto" marked based on fixture usage. See conftest.py pytest_collection_modifyitems
"spark: Mark all tests using the spark fixture. Can be selected with -m spark or deselected with -m (not spark)",
"database: Mark all integration tests using a database. Can be selected with -m database or deselected with -m (not database)",
"elasticsearch: Mark all integration tests using Elasticsearch. Can be selected with -m database or deselected with -m (not elasticsearch)",
]
pythonpath = [
"."
"."
]

[tool.coverage.run]
Expand All @@ -163,7 +161,68 @@ exclude_lines = [
"pragma: no cover"
]

[tool.black]
line-length = 120
target-version = ['py310']
exclude = '/(\.git|\.venv|venv|migrations)/'
[tool.ruff.lint]
preview = true # enable new rules
exclude = [
'.git',
'.venv',
'venv',
'**/migrations/**',
'build',
'usaspending_api.egg-info'
]

select = [
"PLR0913", # max arguments in function
"PLR0904", # max number of public methods
"PLR0911", # max number of return statements
"PLR0916", # max number of boolean expressions
"PLR0915", # max number of lines in a function
"PLR0912", # max number of logical branches in a function
"PLR1702", # max number of nested blocks
"C901", # cognitive complexity (functions)
"I001", # unsorted imports
"B", # flake8 bugbear
"E", # pycodestyle errors
"F", # pyflakes
"W", # pycodestyle warnings
"ANN001", # missing type annotation for function argument
"ANN201", # missing return type annotation for public function or method
"ANN202", # missing return type annotation for private function or method
]
ignore = [
"E203", # whitespace before punctuation
]

pylint.max-args = 6
pylint.max-public-methods = 20
pylint.max-returns = 3
pylint.max-bool-expr = 8
pylint.max-statements = 45
pylint.max-branches = 10
pylint.max-nested-blocks = 5
mccabe.max-complexity = 15
pycodestyle.max-line-length = 120

[tool.ruff.lint.per-file-ignores]
"**/tests/**/test*.py" = [
"ANN001", # missing-type-function-argument; avoid conflict with fixtures
"ANN201", # missing-return-type-undocumented-public-function; avoid conflict with test case return values
"ANN202", # missing-return-type-undocumented-private-function; avoid conflict with test case return values
"PLR0913", # too-many-arguments; avoid conflict with too many fixtures
"PLR0915", # too-many-statements; avoid conflict with long fixtures
]
"**/conftest*.py" = [
"ANN001", # missing-type-function-argument; avoid conflict with fixtures
"ANN201", # missing-return-type-undocumented-public-function; avoid conflict with test case return values
"ANN202", # missing-return-type-undocumented-private-function; avoid conflict with test case return values
"PLR0913", # too-many-arguments; avoid conflict with too many fixtures
"PLR0915", # too-many-statements; avoid conflict with long fixtures
]
"**/tests/**/data/**.py" = [
"ANN001", # missing-type-function-argument; avoid conflict with fixtures
"ANN201", # missing-return-type-undocumented-public-function; avoid conflict with test case return values
"ANN202", # missing-return-type-undocumented-private-function; avoid conflict with test case return values
"PLR0913", # too-many-arguments; avoid conflict with too many fixtures
"PLR0915", # too-many-statements; avoid conflict with long fixtures
]
5 changes: 3 additions & 2 deletions usaspending_api/accounts/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import datetime


TAS_COMPONENT_TO_FIELD_MAPPING = {
"ata": "allocation_transfer_agency_id",
"aid": "agency_id",
Expand All @@ -12,7 +11,9 @@
}


def start_and_end_dates_from_fyq(fiscal_year, fiscal_quarter):
def start_and_end_dates_from_fyq(
fiscal_year: int, fiscal_quarter: int
) -> tuple[datetime.date, datetime.date]:
if fiscal_quarter == 1:
start_date = datetime.date(fiscal_year - 1, 10, 1)
end_date = datetime.date(fiscal_year - 1, 12, 31)
Expand Down
3 changes: 2 additions & 1 deletion usaspending_api/awards/delta_models/awards.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"generated_unique_award_id": "STRING NOT NULL",
"id": "LONG",
"is_fpds": "BOOLEAN NOT NULL",
"last_modified_date": "DATE",
"last_modified_date": "TIMESTAMP",
"latest_transaction_id": "LONG",
"non_federal_funding_amount": "NUMERIC(23,2)",
"officer_1_amount": "NUMERIC(23,2)",
Expand Down Expand Up @@ -55,4 +55,5 @@
)
USING DELTA
LOCATION 's3a://{{SPARK_S3_BUCKET}}/{{DELTA_LAKE_S3_PATH}}/{{DESTINATION_DATABASE}}/{{DESTINATION_TABLE}}'
TBLPROPERTIES (delta.enableChangeDataFeed = true)
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("awards", "0114_alter_ctodlinkageupdates_award_id"),
]

operations = [
migrations.AlterField(
model_name="transactionnormalized",
name="last_modified_date",
field=models.DateTimeField(null=True),
),
]
70 changes: 53 additions & 17 deletions usaspending_api/awards/models/transaction_normalized.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import os

from django.db import models

from django.contrib.postgres.fields import ArrayField
from django.db import models


class TransactionNormalized(models.Model):
id = models.BigAutoField(primary_key=True)
award = models.ForeignKey(
"search.AwardSearch", on_delete=models.DO_NOTHING, help_text="The award which this transaction is contained in"
"search.AwardSearch",
on_delete=models.DO_NOTHING,
help_text="The award which this transaction is contained in",
)
usaspending_unique_transaction_id = models.TextField(
blank=True,
Expand All @@ -29,17 +30,25 @@ class TransactionNormalized(models.Model):
help_text="The plain text description of the transaction type",
)
period_of_performance_start_date = models.DateField(
verbose_name="Period of Performance Start Date", null=True, help_text="The period of performance start date"
verbose_name="Period of Performance Start Date",
null=True,
help_text="The period of performance start date",
)
period_of_performance_current_end_date = models.DateField(
verbose_name="Period of Performance Current End Date",
null=True,
help_text="The current end date of the period of performance",
)
action_date = models.DateField(
verbose_name="Transaction Date", help_text="The date this transaction was actioned", db_index=True
verbose_name="Transaction Date",
help_text="The date this transaction was actioned",
db_index=True,
)
action_type = models.TextField(
blank=True,
null=True,
help_text="The type of transaction. For example, A, B, C, D",
)
action_type = models.TextField(blank=True, null=True, help_text="The type of transaction. For example, A, B, C, D")
action_type_description = models.TextField(blank=True, null=True)
federal_action_obligation = models.DecimalField(
max_digits=23,
Expand Down Expand Up @@ -90,22 +99,36 @@ class TransactionNormalized(models.Model):
null=True,
help_text="The agency which is funding this transaction",
)
description = models.TextField(null=True, help_text="The description of this transaction")
last_modified_date = models.DateField(
description = models.TextField(
null=True, help_text="The description of this transaction"
)
last_modified_date = models.DateTimeField(
blank=True, null=True, help_text="The date this transaction was last modified"
)
certified_date = models.DateField(blank=True, null=True, help_text="The date this transaction was certified")
certified_date = models.DateField(
blank=True, null=True, help_text="The date this transaction was certified"
)
create_date = models.DateTimeField(
auto_now_add=True, blank=True, null=True, help_text="The date this transaction was created in the API"
auto_now_add=True,
blank=True,
null=True,
help_text="The date this transaction was created in the API",
)
update_date = models.DateTimeField(
auto_now=True, null=True, help_text="The last time this transaction was updated in the API", db_index=True
auto_now=True,
null=True,
help_text="The last time this transaction was updated in the API",
db_index=True,
)
fiscal_year = models.IntegerField(
blank=True, null=True, help_text="Fiscal Year calculated based on Action Date"
)
fiscal_year = models.IntegerField(blank=True, null=True, help_text="Fiscal Year calculated based on Action Date")
transaction_unique_id = models.TextField(
blank=False, null=False, default="NONE", verbose_name="Transaction Unique ID"
)
is_fpds = models.BooleanField(blank=False, null=False, default=False, verbose_name="Is FPDS")
is_fpds = models.BooleanField(
blank=False, null=False, default=False, verbose_name="Is FPDS"
)
funding_amount = models.DecimalField(
max_digits=23,
decimal_places=2,
Expand All @@ -114,7 +137,11 @@ class TransactionNormalized(models.Model):
help_text="Assistance data variable. non_federal_funding_amount + federal_action_obligation",
)
non_federal_funding_amount = models.DecimalField(
max_digits=23, decimal_places=2, blank=True, null=True, help_text="Assistance Data variable."
max_digits=23,
decimal_places=2,
blank=True,
null=True,
help_text="Assistance Data variable.",
)
unique_award_key = models.TextField(null=True, db_index=True) # From broker.
business_categories = ArrayField(models.TextField(), default=list)
Expand Down Expand Up @@ -149,9 +176,18 @@ class Meta:
vw_transaction_normalized_sql = f"""
CREATE OR REPLACE VIEW rpt.vw_transaction_normalized AS
SELECT
{(','+os.linesep+' '*12).join([
(v+(f'::{NORM_CASTED_COL_MAP[k]}' if k in NORM_CASTED_COL_MAP else '')).ljust(62)+' AS '+k.ljust(48)
for k, v in NORM_TO_TRANSACTION_SEARCH_COL_MAP.items()])}
{
("," + os.linesep + " " * 12).join(
[
(
v + (f"::{NORM_CASTED_COL_MAP[k]}" if k in NORM_CASTED_COL_MAP else "")
).ljust(62)
+ " AS "
+ k.ljust(48)
for k, v in NORM_TO_TRANSACTION_SEARCH_COL_MAP.items()
]
)
}
FROM
rpt.transaction_search;
"""
Loading
Loading