Skip to content

Commit c44ab9a

Browse files
authored
fix: conformance – explicit filter params and gsa_elibrary_contracts (#13)
1 parent 5492afa commit c44ab9a

File tree

8 files changed

+552
-173
lines changed

8 files changed

+552
-173
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.4.1] - 2026-03-03
11+
12+
### Added
13+
- GSA eLibrary contracts: `list_gsa_elibrary_contracts`, `get_gsa_elibrary_contract` with shaping and filter params (`contract_number`, `key`, `piid`, `schedule`, `search`, `sin`, `uei`).
14+
15+
### Changed
16+
- Conformance: replaced `**kwargs`/`**filters` with explicit filter parameters on `list_contracts`, `list_idvs`, `list_entities`, `list_forecasts`, `list_grants`, `list_notices`, `list_opportunities` for full filter/shape conformance. Backward compatibility preserved for `list_contracts(filters=SearchFilters(...))`.
17+
1018
## [0.4.0] - 2026-02-24
1119

1220
### Added

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "tango-python"
7-
version = "0.4.0"
7+
version = "0.4.1"
88
description = "Python SDK for the Tango API"
99
readme = "README.md"
1010
requires-python = ">=3.12"

scripts/check_filter_shape_conformance.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import ast
2222
import json
2323
from pathlib import Path
24-
from typing import Any, Type
24+
from typing import Any
2525

2626
REPO_ROOT = Path(__file__).resolve().parents[1]
2727
CLIENT_PATH = REPO_ROOT / "tango" / "client.py"
@@ -49,32 +49,34 @@
4949
"entities": "list_entities",
5050
"agencies": "list_agencies",
5151
"naics": "list_naics",
52+
"gsa_elibrary_contracts": "list_gsa_elibrary_contracts",
5253
# Resources not yet implemented in SDK
5354
"assistance": None,
5455
"offices": None,
5556
}
5657

5758

58-
def get_shape_config_entries() -> list[tuple[str, str, Type[Any]]]:
59+
def get_shape_config_entries() -> list[tuple[str, str, type[Any]]]:
5960
"""Return (shape_name, shape_string, model_class) for every ShapeConfig constant."""
6061
from tango.models import (
62+
IDV,
63+
OTA,
64+
OTIDV,
6165
Contract,
6266
Entity,
6367
Forecast,
6468
Grant,
65-
IDV,
69+
GsaElibraryContract,
6670
Notice,
67-
OTA,
68-
Organization,
6971
Opportunity,
70-
OTIDV,
72+
Organization,
7173
ShapeConfig,
7274
Subaward,
7375
Vehicle,
7476
)
7577

7678
# ShapeConfig constant name -> (shape string, model class for validation)
77-
entries: list[tuple[str, str, Type[Any]]] = []
79+
entries: list[tuple[str, str, type[Any]]] = []
7880
configs = [
7981
("CONTRACTS_MINIMAL", ShapeConfig.CONTRACTS_MINIMAL, Contract),
8082
("ENTITIES_MINIMAL", ShapeConfig.ENTITIES_MINIMAL, Entity),
@@ -92,6 +94,11 @@ def get_shape_config_entries() -> list[tuple[str, str, Type[Any]]]:
9294
("OTAS_MINIMAL", ShapeConfig.OTAS_MINIMAL, OTA),
9395
("OTIDVS_MINIMAL", ShapeConfig.OTIDVS_MINIMAL, OTIDV),
9496
("SUBAWARDS_MINIMAL", ShapeConfig.SUBAWARDS_MINIMAL, Subaward),
97+
(
98+
"GSA_ELIBRARY_CONTRACTS_MINIMAL",
99+
ShapeConfig.GSA_ELIBRARY_CONTRACTS_MINIMAL,
100+
GsaElibraryContract,
101+
),
95102
]
96103
for name, shape_str, model_cls in configs:
97104
entries.append((name, shape_str, model_cls))
@@ -166,16 +173,12 @@ def run_check(manifest_path: Path) -> tuple[list[str], list[str]]:
166173
# Explicitly marked as not implemented
167174
runtime_filters = payload.get("runtime", {}).get("filter_params", [])
168175
if runtime_filters:
169-
warnings.append(
170-
f"{resource_name}: no SDK method implemented for this resource"
171-
)
176+
warnings.append(f"{resource_name}: no SDK method implemented for this resource")
172177
continue
173178

174179
if sdk_method not in methods:
175180
# Method mapped but not found in client.py
176-
errors.append(
177-
f"{resource_name}: mapped method `{sdk_method}` not found in SDK client"
178-
)
181+
errors.append(f"{resource_name}: mapped method `{sdk_method}` not found in SDK client")
179182
continue
180183

181184
runtime_filters = set(payload.get("runtime", {}).get("filter_params", []))
@@ -212,12 +215,14 @@ def get_unmapped_resources(manifest_path: Path) -> list[dict[str, Any]]:
212215
# Check if unmapped or method doesn't exist
213216
if sdk_method is None or sdk_method not in methods:
214217
runtime = payload.get("runtime", {}) or {}
215-
unmapped.append({
216-
"resource": resource_name,
217-
"expected_method": sdk_method,
218-
"filter_params": runtime.get("filter_params", []),
219-
"pagination_class": (runtime.get("pagination") or {}).get("class", ""),
220-
})
218+
unmapped.append(
219+
{
220+
"resource": resource_name,
221+
"expected_method": sdk_method,
222+
"filter_params": runtime.get("filter_params", []),
223+
"pagination_class": (runtime.get("pagination") or {}).get("class", ""),
224+
}
225+
)
221226
return unmapped
222227

223228

tango/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
TangoValidationError,
1010
)
1111
from .models import (
12+
GsaElibraryContract,
1213
PaginatedResponse,
1314
SearchFilters,
1415
ShapeConfig,
@@ -26,14 +27,15 @@
2627
TypeGenerator,
2728
)
2829

29-
__version__ = "0.4.0"
30+
__version__ = "0.4.1"
3031
__all__ = [
3132
"TangoClient",
3233
"TangoAPIError",
3334
"TangoAuthError",
3435
"TangoNotFoundError",
3536
"TangoValidationError",
3637
"TangoRateLimitError",
38+
"GsaElibraryContract",
3739
"PaginatedResponse",
3840
"SearchFilters",
3941
"ShapeConfig",

0 commit comments

Comments
 (0)