Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
9c41cd7
Merge pull request #4636 from fedspendingtransparency/fix/dev-15051-h…
sethstoudenmier Apr 23, 2026
232fd8b
Merge pull request #4644 from fedspendingtransparency/staging
aguest-kc Apr 28, 2026
4ee6775
Merge pull request #4649 from fedspendingtransparency/fix/dev-15111-c…
sethstoudenmier May 5, 2026
4a8b217
[DEV-13899] Update Django and DjangoRestFramework versions
aguest-kc May 7, 2026
8b135fd
[DEV-13899] Remove deprecated index_together
aguest-kc May 7, 2026
06d934c
[DEV-13899] Update OpClass import
aguest-kc May 7, 2026
d5591b8
[DEV-13899] Rename old index_together index
aguest-kc May 7, 2026
021e7a0
[DEV-13899] Ruff fixes
aguest-kc May 7, 2026
7b15504
[DEV-13899] Revert uv.lock revision number
aguest-kc May 7, 2026
6a20723
[DEV-13899] Ignore migrations in ruff Github action
aguest-kc May 7, 2026
e438dfd
[DEV-13899] Update to support Django 5.2 SQL alias changes
aguest-kc May 7, 2026
6cf3e61
[DEV-13899] Ruff fixes
aguest-kc May 7, 2026
f18c966
[DEV-13899] Fixing downloads
aguest-kc May 11, 2026
13a1ee0
Merge pull request #4662 from fedspendingtransparency/staging
zachflanders-frb May 20, 2026
d37518c
Merge branch 'qat' into ftr/dev-13899-django-5.2-upgrade
aguest-kc May 26, 2026
8fb7c69
[DEV-13899] Ruff fixes
aguest-kc May 26, 2026
30b5371
[DEV-13899] Revert download_generation.py changes
aguest-kc May 27, 2026
17f8ea9
[DEV-13899] Fix tests
aguest-kc Jun 1, 2026
1794e59
Merge branch 'qat' into ftr/dev-13899-django-5.2-upgrade
aguest-kc Jun 2, 2026
f62ae34
Merge pull request #4672 from fedspendingtransparency/staging
aguest-kc Jun 9, 2026
ba1aff3
[DEV-13899] Fixed nulls_last ordering error
DavidMikolaKC Jun 16, 2026
e58ce65
[DEV-14823] update unique constraint on gtas table
james-at-kc Jun 17, 2026
78e0826
[DEV-13899] Ruff Lint Fix
DavidMikolaKC Jun 17, 2026
3266cde
[DEV-13899] Resolved Duplicate Historical Lookup Keys
DavidMikolaKC Jun 22, 2026
e6394aa
Merge branch 'qat' of https://github.com/fedspendingtransparency/usas…
DavidMikolaKC Jun 22, 2026
f52126a
Added missing exceptions for python strings
DavidMikolaKC Jun 22, 2026
d6e56f7
[DEV-13899] Fixed Improper Group By Replacement Indexing
DavidMikolaKC Jun 23, 2026
8884c29
[Dev-13899] Ruff Lint Fixes
DavidMikolaKC Jun 23, 2026
3a05a8b
[Dev-13899] Value Error Fix
DavidMikolaKC Jun 23, 2026
ec49ec0
[DEV-15167] initial commit
james-at-kc Jun 24, 2026
41965ef
Merge branch 'qat' into ftr/14823-unique-constraint-gtas
james-at-kc Jun 24, 2026
ff3689b
Merge branch 'qat' into ftr/14823-unique-constraint-gtas
james-at-kc Jun 24, 2026
d5346c3
Merge branch 'qat' into ftr/14823-unique-constraint-gtas
james-at-kc Jun 25, 2026
3b9c535
[DEV-14679] - add filter search assistant
zachflanders-frb Jun 29, 2026
2575587
Merge pull request #4682 from fedspendingtransparency/staging
zachflanders-frb Jun 30, 2026
7415445
Merge branch 'qat' into ftr/dev-13899-django-5.2-upgrade
aguest-kc Jun 30, 2026
bb84126
[DEV-15167] unit and integration tests
james-at-kc Jul 1, 2026
19e3bd2
Merge branch 'qat' into ftr/DEV-15167-implement-recipient-lookup-tool
james-at-kc Jul 1, 2026
efbf73e
[DEV-15167] ruff merged
james-at-kc Jul 1, 2026
5bea068
Merge pull request #4654 from fedspendingtransparency/ftr/dev-13899-d…
zachflanders-frb Jul 1, 2026
e9a840d
Merge branch 'qat' into ftr/14823-unique-constraint-gtas
aguest-kc Jul 1, 2026
05a7958
[dev-15167] adjust tests
james-at-kc Jul 1, 2026
9b25117
Merge branch 'qat' into ftr/DEV-15167-implement-recipient-lookup-tool
james-at-kc Jul 1, 2026
02a5329
Merge pull request #4676 from fedspendingtransparency/ftr/14823-uniqu…
aguest-kc Jul 1, 2026
9d34af6
[DEV-14679] Add search assistant
zachflanders-frb Jul 6, 2026
2b46213
OPS-2991 Updated 8 calls to cursor.execute() with parameters instead …
gregrholden Jul 6, 2026
0f197ab
[OPS-2987] - fix hierarchical filter
zachflanders-frb Jul 6, 2026
c99652c
[OPS-2991] Updating query values to ints from strings for use in inpu…
gregrholden Jul 6, 2026
5c057fb
[OPS-2987] - add tests
zachflanders-frb Jul 6, 2026
bc44eda
[OPS-2987] - style fix
zachflanders-frb Jul 6, 2026
57394ab
[DEV-14679] fix failing test
zachflanders-frb Jul 6, 2026
13e32a4
[OPS-2989] initial with unit tests
james-at-kc Jul 7, 2026
b807fcb
[OPS-2989] adjust unit tests
james-at-kc Jul 7, 2026
33e2afc
Merge branch 'qat' into ftr/DEV-15167-implement-recipient-lookup-tool
aguest-kc Jul 7, 2026
969d51c
Merge branch 'qat' into dev-14679-implement-search-assistant
zachflanders-frb Jul 7, 2026
e6fe5fd
[OPS-2987] - fix issue with hierarchical filters that were not direct…
zachflanders-frb Jul 7, 2026
57bbb41
Merge branch 'qat' into bug/OPS-2991-parameterizing-sql-in-f-strings
aguest-kc Jul 7, 2026
e849d70
Merge pull request #4685 from fedspendingtransparency/bug/OPS-2991-pa…
aguest-kc Jul 8, 2026
9660acd
Merge branch 'qat' into fix/ops-2987-hierarchical-filter
aguest-kc Jul 8, 2026
4939308
[DEV-15434] Added check for Recipient Count View
DavidMikolaKC Jul 8, 2026
9437283
Merge branch 'qat' into ftr/DEV-15167-implement-recipient-lookup-tool
aguest-kc Jul 9, 2026
0237e6a
[DEV-15167] peer review changes
james-at-kc Jul 9, 2026
fd888f5
[DEV-15167] peer review changes 2
james-at-kc Jul 9, 2026
b5e5438
Merge branch 'qat' into dev-14679-implement-search-assistant
aguest-kc Jul 9, 2026
822b14a
[DEV-15167] peer review changes 3
james-at-kc Jul 9, 2026
d3134d6
[DEV-15167] update integration tests
james-at-kc Jul 9, 2026
e2e146a
[OPS-2987] - update error handling and validation
zachflanders-frb Jul 9, 2026
21c3c53
[DEV-15167] update db model test
james-at-kc Jul 9, 2026
908d441
[OPS-2989] adjust unit tests
james-at-kc Jul 10, 2026
7a2148a
Merge branch 'qat' into ftr/OPS-2989-Mitigate-Download-generation-SQL
james-at-kc Jul 10, 2026
7637621
[DEV-15460] mitigate python stack trace returned to download user
james-at-kc Jul 10, 2026
2b8a5f2
[DEV-15434] Circular Import Removed
DavidMikolaKC Jul 10, 2026
d5d7a3f
[OPS-2987] - update tests
zachflanders-frb Jul 13, 2026
7479d84
[DEV-15494] Correctly format Pydantic error messages
aguest-kc Jul 13, 2026
afcee71
[DEV-15494] Ruff fixes
aguest-kc Jul 13, 2026
c253081
[DEV-15460] PR suggestion
james-at-kc Jul 14, 2026
5e7a056
[DEV-15460] unit tests
james-at-kc Jul 14, 2026
81bc697
Merge pull request #4687 from fedspendingtransparency/ftr/OPS-2989-Mi…
james-at-kc Jul 14, 2026
bc57859
Merge branch 'qat' into ftr/DEV-15167-implement-recipient-lookup-tool
james-at-kc Jul 14, 2026
1ea641d
Merge branch 'qat' into ftr/dev-15460-remove-stack-trace-from-client-…
james-at-kc Jul 14, 2026
c43f287
Merge pull request #4683 from fedspendingtransparency/ftr/DEV-15167-i…
james-at-kc Jul 14, 2026
a367aac
Merge branch 'qat' into ftr/dev-15460-remove-stack-trace-from-client-…
james-at-kc Jul 14, 2026
6cb0e93
Merge branch 'qat' into fix/dev-15494-return-422-on-pydantic-validati…
aguest-kc Jul 14, 2026
228588a
Merge branch 'qat' into fix/ops-2987-hierarchical-filter
aguest-kc Jul 14, 2026
88c9ff1
Merge branch 'qat' into bug/dev-15434-filter-empty-request-bodies
aguest-kc Jul 14, 2026
bf704d7
Merge pull request #4690 from fedspendingtransparency/ftr/dev-15460-r…
james-at-kc Jul 14, 2026
176af28
Merge branch 'qat' into fix/ops-2987-hierarchical-filter
zachflanders-frb Jul 14, 2026
f3f41d8
Merge branch 'qat' into fix/dev-15494-return-422-on-pydantic-validati…
aguest-kc Jul 14, 2026
b6b5759
Merge branch 'qat' into bug/dev-15434-filter-empty-request-bodies
aguest-kc Jul 14, 2026
b2a5180
Merge pull request #4686 from fedspendingtransparency/fix/ops-2987-hi…
zachflanders-frb Jul 14, 2026
2e62a87
Merge branch 'qat' into fix/dev-15494-return-422-on-pydantic-validati…
aguest-kc Jul 14, 2026
dadb011
[DEV-14679] - update assistant code to make more robust
zachflanders-frb Jul 14, 2026
5014cfc
Merge branch 'qat' into dev-14679-implement-search-assistant
zachflanders-frb Jul 14, 2026
65dc051
Merge pull request #4691 from fedspendingtransparency/fix/dev-15494-r…
aguest-kc Jul 14, 2026
afb22f0
Merge branch 'qat' into dev-14679-implement-search-assistant
aguest-kc Jul 14, 2026
7a182fb
Merge pull request #4684 from fedspendingtransparency/dev-14679-imple…
zachflanders-frb Jul 14, 2026
703e438
Merge branch 'qat' into bug/dev-15434-filter-empty-request-bodies
DavidMikolaKC Jul 14, 2026
90bbafe
Merge pull request #4688 from fedspendingtransparency/bug/dev-15434-f…
DavidMikolaKC Jul 14, 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
2 changes: 2 additions & 0 deletions .github/workflows/code-style-checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ jobs:
with:
files: |
**.py
files_ignore: |
**/migrations/**
separator: " "

- name: Check If `changed-python-files` Is An Empty String
Expand Down
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ dependencies = [
"django-debug-toolbar==4.3.*",
"django-extensions==3.2.*",
"django-spaghetti-and-meatballs==0.4.*",
"Django==4.2.*",
"Django==5.2.*",
"django_cte==1.3.*",
"djangorestframework==3.15.*",
"djangorestframework==3.17.*",
"docutils>=0.10,<0.17",
"drf-api-tracking==1.8.4",
"drf-extensions==0.7.*",
Expand Down Expand Up @@ -233,3 +233,6 @@ pycodestyle.max-line-length = 120
"PLR0913", # too-many-arguments; avoid conflict with too many fixtures
"PLR0915", # too-many-statements; avoid conflict with long fixtures
]
"**/disaster/management/sql/spark/**.py" = [
"E501", # Line too long
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.2.14 on 2026-05-07 12:57

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('awards', '0114_alter_ctodlinkageupdates_award_id'),
]

operations = [
migrations.RenameIndex(
model_name='financialaccountsbyawards',
new_name='financial_a_disaste_396e45_idx',
old_fields=('disaster_emergency_fund', 'submission', 'award', 'piid', 'fain', 'uri', 'parent_award_id', 'transaction_obligated_amount', 'gross_outlay_amount_by_award_cpe'),
),
]
32 changes: 16 additions & 16 deletions usaspending_api/awards/models/financial_accounts_by_awards.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.db import models
from django_cte import CTEManager
from django.db.models import Q
from django_cte import CTEManager

from usaspending_api.common.models import DataSourceTrackedModel

Expand Down Expand Up @@ -154,21 +154,6 @@ class FinancialAccountsByAwards(AbstractFinancialAccountsByAwards):
class Meta:
managed = True
db_table = "financial_accounts_by_awards"
index_together = [
# This index dramatically sped up disaster endpoint queries. VERY IMPORTANT! It needs
# to cover all of the fields being queried in order to eek out maximum performance.
[
"disaster_emergency_fund",
"submission",
"award",
"piid",
"fain",
"uri",
"parent_award_id",
"transaction_obligated_amount",
"gross_outlay_amount_by_award_cpe",
]
]
indexes = [
models.Index(
fields=["submission_id", "treasury_account_id"],
Expand All @@ -193,4 +178,19 @@ class Meta:
name="faba_subid_awardkey_sums_idx",
condition=Q(disaster_emergency_fund__in=["L", "M", "N", "O", "P", "U", "V"]),
),
# This index dramatically sped up disaster endpoint queries. VERY IMPORTANT! It needs
# to cover all of the fields being queried in order to eek out maximum performance.
models.Index(
fields=[
"disaster_emergency_fund",
"submission",
"award",
"piid",
"fain",
"uri",
"parent_award_id",
"transaction_obligated_amount",
"gross_outlay_amount_by_award_cpe",
]
),
]
4 changes: 3 additions & 1 deletion usaspending_api/awards/models/transaction_normalized.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ def __str__(self):
class Meta:
managed = False
db_table = "vw_transaction_normalized"
index_together = ["award", "action_date"]
indexes = [
models.Index(fields=["award", "action_date"])
]


NORM_ALT_COL_NAMES_IN_TRANSACTION_SEARCH = {
Expand Down
20 changes: 14 additions & 6 deletions usaspending_api/common/cache.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import hashlib
import json
from typing import Any, Callable

from rest_framework.request import Request
from rest_framework.views import APIView
from rest_framework_extensions.key_constructor import bits
from rest_framework_extensions.key_constructor.constructors import DefaultKeyConstructor

Expand All @@ -12,7 +15,9 @@ class PathKeyBit(bits.QueryParamsKeyBit):
Adds query path as a key bit
"""

def get_source_dict(self, params, view_instance, view_method, request, args, kwargs):
def get_source_dict(
self, params: dict, view_instance: APIView, view_method: Callable, request: Request, args: Any, kwargs: Any
) -> dict[str, str]:
return {"path": request.path}


Expand All @@ -22,14 +27,17 @@ class GetPostQueryParamsKeyBit(bits.QueryParamsKeyBit):
directives in a POST request (i.e., request.data) as well as GET parameters
"""

def get_source_dict(self, params, view_instance, view_method, request, args, kwargs):
def get_source_dict(
self, params: dict, view_instance: APIView, view_method: Callable, request: Request, args: Any, kwargs: Any
) -> dict[str, str]:

if hasattr(view_instance, "cache_key_whitelist"):
whitelist = view_instance.cache_key_whitelist
params = {}
for param in whitelist:
if param in request.query_params:
params[param] = request.query_params[param]
# Currently, the only view with a whitelist attr is RecipientCount
# RecipientCount only reads the request body, not query params.
# Take this into consideration when implementing whitelist attr
if param in request.data:
params[param] = request.data[param]
else:
Expand All @@ -43,14 +51,14 @@ def get_source_dict(self, params, view_instance, view_method, request, args, kwa

class USAspendingKeyConstructor(DefaultKeyConstructor):
"""
Handle cache key construction for API requests. If we never need to create more nuanced keys, see the
Handle cache key construction for API requests. If we ever need to create more nuanced keys, see the
drf-extensions documentation: http://chibisov.github.io/drf-extensions/docs/#default-key-constructor
"""

path_bit = PathKeyBit()
request_params = GetPostQueryParamsKeyBit()

def prepare_key(self, key_dict):
def prepare_key(self, key_dict: dict) -> str:
# Order the key_dict using the order_nested_object function to make sure cache keys are always exactly the same
ordered_key_dict = json.dumps(order_nested_object(key_dict))
key_hex = hashlib.md5(ordered_key_dict.encode("utf-8"), usedforsecurity=False).hexdigest()
Expand Down
53 changes: 20 additions & 33 deletions usaspending_api/common/helpers/orm_helpers.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
from datetime import date
from functools import reduce
from operator import add
from typing import List, Union

from django.contrib.postgres.aggregates import StringAgg
from django.db import DEFAULT_DB_ALIAS
from django.db import DEFAULT_DB_ALIAS, connections
from django.db.backends.postgresql.psycopg_any import mogrify
from django.db.models import Aggregate, Case, CharField, F, Func, IntegerField, QuerySet, TextField, Value, When
from django.db.models.functions import Cast, Coalesce, Concat, LPad

from usaspending_api.awards.v2.lookups.lookups import (
all_award_types_mappings,
assistance_type_mapping,
procurement_type_mapping,
all_award_types_mappings,
)


TYPES_TO_QUOTE_IN_SQL = (str, date)


class AwardGroupsException(Exception):
"""Custom Exception for a specific event"""

Expand Down Expand Up @@ -103,7 +100,7 @@ class StringAggWithDefault(StringAgg):
output_field = TextField()


def get_fyp_notation(relation_name=None):
def get_fyp_notation(relation_name: str = None) -> Concat:
"""
Generates FYyyyyPpp syntax from submission table. relation_name is the Django ORM
relation name from the foreign key table to the submission table.
Expand All @@ -117,7 +114,7 @@ def get_fyp_notation(relation_name=None):
)


def get_fyq_notation(relation_name=None):
def get_fyq_notation(relation_name: str = None) -> Concat:
"""
Generates FYyyyyPpp syntax from submission table. relation_name is the Django ORM
relation name from the foreign key table to the submission table.
Expand All @@ -131,7 +128,7 @@ def get_fyq_notation(relation_name=None):
)


def get_fyp_or_q_notation(relation_name=None):
def get_fyp_or_q_notation(relation_name: str = None) -> Case:
"""
Generates FYyyyyQq or FYyyyyPpp syntax from submission table. relation_name is the Django ORM
relation name from the foreign key table to the submission table.
Expand All @@ -144,7 +141,7 @@ def get_fyp_or_q_notation(relation_name=None):
)


def get_gtas_fyp_notation():
def get_gtas_fyp_notation() -> Concat:
"""
Generates FYyyyyPpp syntax from gtas_sf133_balances table.
"""
Expand All @@ -157,31 +154,21 @@ def get_gtas_fyp_notation():


def generate_raw_quoted_query(queryset: QuerySet) -> str:
"""Generates the raw sql from a queryset with quotable types quoted.
"""Generates the raw sql from a queryset parameters safely quoted by the DB driver.

This function provided benefit since the Django queryset.query doesn't quote
some types such as dates and strings. If Django is updated to fix this,
please use that instead.

Note: To add new python data types that should be quoted in queryset.query output,
add them to TYPES_TO_QUOTE_IN_SQL global
Compiles the queryset to parameterized SQL (%s placeholders) and uses psycopg
client-side binding to quote values.
"""
sql, params = queryset.query.get_compiler(DEFAULT_DB_ALIAS).as_sql()
str_fix_params = []
for param in params:
if isinstance(param, TYPES_TO_QUOTE_IN_SQL):
# single quotes are escaped with two '' for strings in sql
param = param.replace("'", "''") if isinstance(param, str) else param
str_fix_param = "'{}'".format(param)
elif isinstance(param, list):
str_fix_param = "ARRAY{}".format(param)
else:
str_fix_param = param
str_fix_params.append(str_fix_param)
return sql % tuple(str_fix_params)


def obtain_category_from_award_group(type_list):
if not params:
return sql
quoted_sql = mogrify(sql, params, connections[DEFAULT_DB_ALIAS])
if isinstance(quoted_sql, bytes):
quoted_sql = quoted_sql.decode()
return quoted_sql


def obtain_category_from_award_group(type_list: list) -> str:
if not type_list:
raise AwardGroupsException("Invalid award type list: No types provided.")

Expand Down Expand Up @@ -210,7 +197,7 @@ def award_types_are_valid_groups(type_list: list) -> bool:
return is_valid


def subaward_types_are_valid_groups(type_list):
def subaward_types_are_valid_groups(type_list: list) -> bool:
"""Check to ensure the award type list is a subset of one and only one award group.

Groups: are "Procurement" and "Assistance"
Expand Down
62 changes: 44 additions & 18 deletions usaspending_api/common/helpers/pydantic_error_formatter.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,52 @@
from typing import Any

from pydantic import ValidationError

# Pydantic V2 error types mapped to the type names our API has always used
API_TYPE_BY_ERROR_TYPE = {
"bool_parsing": "boolean",
"bool_type": "boolean",
"date_from_datetime_parsing": "date",
"date_parsing": "date",
"dict_type": "object",
"float_parsing": "float",
"float_type": "float",
"int_parsing": "integer",
"int_type": "integer",
"list_type": "array",
"model_attributes_type": "object",
"model_type": "object",
"string_type": "text",
}


def _key_name(loc: tuple[str | int, ...]) -> str:
"""Convert a Pydantic error location into the pipe delimited key used in our API messages.

List indexes and union member tags are dropped, so ("filters", "recipient_locations", 0, "state") becomes
"filters|recipient_locations|state" and ("filters", "naics_codes", "list[str]") becomes "filters|"naics_codes".
"""

field_names = [part for part in loc if isinstance(part, str) and "[" not in part and part.islower()]
return "|".join(field_names)


def pydantic_error_formatter(error: ValidationError) -> str:
errors: list[dict] = error.errors()
def pydantic_error_formatter(error: ValidationError) -> str: # noqa: PLR0911
errors: list[dict[str, Any]] = error.errors()
key_name = _key_name(errors[0]["loc"])

for error in errors:
# Missing required fields
if error.get('msg') == 'Field required':
key_name = error['loc'][0]
key_errors = [err for err in errors if _key_name(err["loc"]) == key_name]
rule_error = next((err for err in key_errors if err["type"] not in API_TYPE_BY_ERROR_TYPE), None)

return f"Missing value: '{key_name}' is a required field"
if rule_error is None:
expected_types = ", ".join(dict.fromkeys(API_TYPE_BY_ERROR_TYPE[err["type"]] for err in key_errors))
return f"Invalid value in '{key_name}'. '{errors[0]['input']}' is not a valid type ({expected_types})."

# Incorrect type for a filter
else:
key_name = error["loc"][0] + "|" + error["loc"][1] if len(error['loc']) > 1 else error['loc'][0]
bad_value = error['input']
if rule_error["type"] == "missing":
return f"Missing value: '{key_name}' is a required field"

if error['type'].endswith('_type'):
expected_type = error['type'].strip("_type")
elif error.get('ctx'):
expected_type = error['ctx']['expected_type']
else:
expected_type = "dictionary"
if rule_error["type"] == "literal_error":
return f"Field '{key_name}' is outside valid values {rule_error['ctx']['expected']}"

return f"Invalid value in '{key_name}'. '{bad_value}' is not a valid type ({expected_type})."
message: str = rule_error["msg"].removeprefix("Value error, ")
return f"Invalid value in '{key_name}': {message}"
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ SELECT
"transaction_fpds"."cost_accounting_standards" AS "cost_accounting_standards_clause_code",
"transaction_fpds"."cost_accounting_stand_desc" AS "cost_accounting_standards_clause",
"transaction_fpds"."government_furnished_prope" AS "government_furnished_property_code",
"transaction_fpds"."government_furnished_prope" AS "government_furnished_property",
"transaction_fpds"."government_furnished_desc" AS "government_furnished_property",
"transaction_fpds"."sea_transportation" AS "sea_transportation_code",
"transaction_fpds"."sea_transportation_desc" AS "sea_transportation",
"transaction_fpds"."consolidated_contract" AS "consolidated_contract_code",
Expand Down
9 changes: 3 additions & 6 deletions usaspending_api/common/pydantic_base_models/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ def check_at_least_one_key(self) -> Self:
if self.require is None and self.exclude is None:
raise PydanticCustomError(
"missing_required_field",
'At least one of "require" or "exclude" must be provided',
{"expected_type": "array, object"},
'At least one of "require" or "exclude" must be provided'
)
return self

Expand All @@ -27,8 +26,7 @@ def check_at_least_one_key(self) -> Self:
if self.require is None and self.exclude is None:
raise PydanticCustomError(
"missing_required_field",
'At least one of "require" or "exclude" must be provided',
{"expected_type": "array, object"},
'At least one of "require" or "exclude" must be provided'
)
return self

Expand All @@ -42,8 +40,7 @@ def check_at_least_one_key(self) -> Self:
if self.require is None and self.exclude is None:
raise PydanticCustomError(
"missing_required_field",
'At least one of "require" or "exclude" must be provided',
{"expected_type": "array, object"}
'At least one of "require" or "exclude" must be provided'
)
return self

Expand Down
Loading
Loading