tango-python 0.4.1__py3-none-any.whl → 0.4.2__py3-none-any.whl
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.
- tango/client.py +124 -67
- tango/models.py +31 -1
- tango/shapes/explicit_schemas.py +53 -0
- {tango_python-0.4.1.dist-info → tango_python-0.4.2.dist-info}/METADATA +57 -29
- {tango_python-0.4.1.dist-info → tango_python-0.4.2.dist-info}/RECORD +7 -7
- {tango_python-0.4.1.dist-info → tango_python-0.4.2.dist-info}/WHEEL +0 -0
- {tango_python-0.4.1.dist-info → tango_python-0.4.2.dist-info}/licenses/LICENSE +0 -0
tango/client.py
CHANGED
|
@@ -31,6 +31,7 @@ from tango.models import (
|
|
|
31
31
|
Opportunity,
|
|
32
32
|
Organization,
|
|
33
33
|
PaginatedResponse,
|
|
34
|
+
Protest,
|
|
34
35
|
SearchFilters,
|
|
35
36
|
ShapeConfig,
|
|
36
37
|
Subaward,
|
|
@@ -943,32 +944,6 @@ class TangoClient:
|
|
|
943
944
|
page_metadata=data.get("page_metadata"),
|
|
944
945
|
)
|
|
945
946
|
|
|
946
|
-
def get_idv_summary(self, identifier: str) -> dict[str, Any]:
|
|
947
|
-
"""Get a summary for an IDV solicitation identifier (`/api/idvs/{identifier}/summary/`)."""
|
|
948
|
-
return self._get(f"/api/idvs/{identifier}/summary/")
|
|
949
|
-
|
|
950
|
-
def list_idv_summary_awards(
|
|
951
|
-
self,
|
|
952
|
-
identifier: str,
|
|
953
|
-
limit: int = 25,
|
|
954
|
-
cursor: str | None = None,
|
|
955
|
-
ordering: str | None = None,
|
|
956
|
-
) -> PaginatedResponse:
|
|
957
|
-
"""List awards under an IDV summary (`/api/idvs/{identifier}/summary/awards/`)."""
|
|
958
|
-
params: dict[str, Any] = {"limit": min(limit, 100)}
|
|
959
|
-
if cursor:
|
|
960
|
-
params["cursor"] = cursor
|
|
961
|
-
if ordering:
|
|
962
|
-
params["ordering"] = ordering
|
|
963
|
-
data = self._get(f"/api/idvs/{identifier}/summary/awards/", params)
|
|
964
|
-
return PaginatedResponse(
|
|
965
|
-
count=int(data.get("count") or len(data.get("results") or [])),
|
|
966
|
-
next=data.get("next"),
|
|
967
|
-
previous=data.get("previous"),
|
|
968
|
-
results=data.get("results") or [],
|
|
969
|
-
page_metadata=data.get("page_metadata"),
|
|
970
|
-
)
|
|
971
|
-
|
|
972
947
|
def list_otas(
|
|
973
948
|
self,
|
|
974
949
|
limit: int = 25,
|
|
@@ -1859,6 +1834,129 @@ class TangoClient:
|
|
|
1859
1834
|
results=results,
|
|
1860
1835
|
)
|
|
1861
1836
|
|
|
1837
|
+
# Protest endpoints
|
|
1838
|
+
# See https://tango.makegov.com/docs/api-reference/protests.md
|
|
1839
|
+
# Note: Protests API does not support ordering (returns 400 if provided).
|
|
1840
|
+
# Use shape=...,dockets(...) to request nested dockets.
|
|
1841
|
+
def list_protests(
|
|
1842
|
+
self,
|
|
1843
|
+
page: int = 1,
|
|
1844
|
+
limit: int = 25,
|
|
1845
|
+
shape: str | None = None,
|
|
1846
|
+
flat: bool = False,
|
|
1847
|
+
flat_lists: bool = False,
|
|
1848
|
+
source_system: str | None = None,
|
|
1849
|
+
outcome: str | None = None,
|
|
1850
|
+
case_type: str | None = None,
|
|
1851
|
+
agency: str | None = None,
|
|
1852
|
+
case_number: str | None = None,
|
|
1853
|
+
solicitation_number: str | None = None,
|
|
1854
|
+
protester: str | None = None,
|
|
1855
|
+
filed_date_after: str | None = None,
|
|
1856
|
+
filed_date_before: str | None = None,
|
|
1857
|
+
decision_date_after: str | None = None,
|
|
1858
|
+
decision_date_before: str | None = None,
|
|
1859
|
+
search: str | None = None,
|
|
1860
|
+
) -> PaginatedResponse:
|
|
1861
|
+
"""
|
|
1862
|
+
List bid protests.
|
|
1863
|
+
|
|
1864
|
+
Returns case-level protest records. Use shape=...,dockets(...) to include
|
|
1865
|
+
nested dockets. API reference: https://tango.makegov.com/docs/api-reference/protests.md
|
|
1866
|
+
|
|
1867
|
+
Args:
|
|
1868
|
+
page: Page number
|
|
1869
|
+
limit: Results per page (max 100)
|
|
1870
|
+
shape: Response shape string (defaults to minimal shape)
|
|
1871
|
+
flat: If True, flatten nested objects in shaped response
|
|
1872
|
+
flat_lists: If True, flatten arrays using indexed keys
|
|
1873
|
+
source_system: Filter by source system (e.g. gao)
|
|
1874
|
+
outcome: Filter by outcome (e.g. Denied, Dismissed, Withdrawn, Sustained)
|
|
1875
|
+
case_type: Filter by case type
|
|
1876
|
+
agency: Filter by protested agency text
|
|
1877
|
+
case_number: Filter by case number (e.g. b-423274)
|
|
1878
|
+
solicitation_number: Filter by exact solicitation number
|
|
1879
|
+
protester: Filter by protester name text
|
|
1880
|
+
filed_date_after: Filed date on or after
|
|
1881
|
+
filed_date_before: Filed date on or before
|
|
1882
|
+
decision_date_after: Decision date on or after
|
|
1883
|
+
decision_date_before: Decision date on or before
|
|
1884
|
+
search: Full-text search over protest searchable fields
|
|
1885
|
+
"""
|
|
1886
|
+
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
|
|
1887
|
+
|
|
1888
|
+
if shape is None:
|
|
1889
|
+
shape = ShapeConfig.PROTESTS_MINIMAL
|
|
1890
|
+
if shape:
|
|
1891
|
+
params["shape"] = shape
|
|
1892
|
+
if flat:
|
|
1893
|
+
params["flat"] = "true"
|
|
1894
|
+
if flat_lists:
|
|
1895
|
+
params["flat_lists"] = "true"
|
|
1896
|
+
|
|
1897
|
+
for key, val in (
|
|
1898
|
+
("source_system", source_system),
|
|
1899
|
+
("outcome", outcome),
|
|
1900
|
+
("case_type", case_type),
|
|
1901
|
+
("agency", agency),
|
|
1902
|
+
("case_number", case_number),
|
|
1903
|
+
("solicitation_number", solicitation_number),
|
|
1904
|
+
("protester", protester),
|
|
1905
|
+
("filed_date_after", filed_date_after),
|
|
1906
|
+
("filed_date_before", filed_date_before),
|
|
1907
|
+
("decision_date_after", decision_date_after),
|
|
1908
|
+
("decision_date_before", decision_date_before),
|
|
1909
|
+
("search", search),
|
|
1910
|
+
):
|
|
1911
|
+
if val is not None:
|
|
1912
|
+
params[key] = val
|
|
1913
|
+
|
|
1914
|
+
data = self._get("/api/protests/", params)
|
|
1915
|
+
|
|
1916
|
+
results = [
|
|
1917
|
+
self._parse_response_with_shape(item, shape, Protest, flat, flat_lists)
|
|
1918
|
+
for item in data["results"]
|
|
1919
|
+
]
|
|
1920
|
+
|
|
1921
|
+
return PaginatedResponse(
|
|
1922
|
+
count=data["count"],
|
|
1923
|
+
next=data.get("next"),
|
|
1924
|
+
previous=data.get("previous"),
|
|
1925
|
+
results=results,
|
|
1926
|
+
)
|
|
1927
|
+
|
|
1928
|
+
def get_protest(
|
|
1929
|
+
self,
|
|
1930
|
+
case_id: str,
|
|
1931
|
+
shape: str | None = None,
|
|
1932
|
+
flat: bool = False,
|
|
1933
|
+
flat_lists: bool = False,
|
|
1934
|
+
) -> Any:
|
|
1935
|
+
"""
|
|
1936
|
+
Get a single protest by case_id (RFC 4122 UUID).
|
|
1937
|
+
|
|
1938
|
+
Use shape=...,dockets(...) to include nested dockets.
|
|
1939
|
+
API reference: https://tango.makegov.com/docs/api-reference/protests.md
|
|
1940
|
+
|
|
1941
|
+
Args:
|
|
1942
|
+
case_id: Deterministic case UUID (from source_system + base_case_number)
|
|
1943
|
+
shape: Response shape string (defaults to minimal shape)
|
|
1944
|
+
flat: If True, flatten nested objects in shaped response
|
|
1945
|
+
flat_lists: If True, flatten arrays using indexed keys
|
|
1946
|
+
"""
|
|
1947
|
+
params: dict[str, Any] = {}
|
|
1948
|
+
if shape is None:
|
|
1949
|
+
shape = ShapeConfig.PROTESTS_MINIMAL
|
|
1950
|
+
if shape:
|
|
1951
|
+
params["shape"] = shape
|
|
1952
|
+
if flat:
|
|
1953
|
+
params["flat"] = "true"
|
|
1954
|
+
if flat_lists:
|
|
1955
|
+
params["flat_lists"] = "true"
|
|
1956
|
+
|
|
1957
|
+
data = self._get(f"/api/protests/{case_id}/", params)
|
|
1958
|
+
return self._parse_response_with_shape(data, shape, Protest, flat, flat_lists)
|
|
1959
|
+
|
|
1862
1960
|
# Grant endpoints
|
|
1863
1961
|
def list_grants(
|
|
1864
1962
|
self,
|
|
@@ -1945,47 +2043,6 @@ class TangoClient:
|
|
|
1945
2043
|
results=results,
|
|
1946
2044
|
)
|
|
1947
2045
|
|
|
1948
|
-
def list_assistance(
|
|
1949
|
-
self,
|
|
1950
|
-
limit: int = 25,
|
|
1951
|
-
cursor: str | None = None,
|
|
1952
|
-
assistance_type: str | None = None,
|
|
1953
|
-
award_key: str | None = None,
|
|
1954
|
-
fiscal_year: int | None = None,
|
|
1955
|
-
fiscal_year_gte: int | None = None,
|
|
1956
|
-
fiscal_year_lte: int | None = None,
|
|
1957
|
-
highly_compensated_officers: str | None = None,
|
|
1958
|
-
recipient: str | None = None,
|
|
1959
|
-
recipient_address: str | None = None,
|
|
1960
|
-
search: str | None = None,
|
|
1961
|
-
) -> PaginatedResponse:
|
|
1962
|
-
"""List assistance (financial assistance) transactions (`/api/assistance/`). Keyset pagination."""
|
|
1963
|
-
params: dict[str, Any] = {"limit": min(limit, 100)}
|
|
1964
|
-
if cursor:
|
|
1965
|
-
params["cursor"] = cursor
|
|
1966
|
-
for key, val in (
|
|
1967
|
-
("assistance_type", assistance_type),
|
|
1968
|
-
("award_key", award_key),
|
|
1969
|
-
("fiscal_year", fiscal_year),
|
|
1970
|
-
("fiscal_year_gte", fiscal_year_gte),
|
|
1971
|
-
("fiscal_year_lte", fiscal_year_lte),
|
|
1972
|
-
("highly_compensated_officers", highly_compensated_officers),
|
|
1973
|
-
("recipient", recipient),
|
|
1974
|
-
("recipient_address", recipient_address),
|
|
1975
|
-
("search", search),
|
|
1976
|
-
):
|
|
1977
|
-
if val is not None:
|
|
1978
|
-
params[key] = val
|
|
1979
|
-
data = self._get("/api/assistance/", params)
|
|
1980
|
-
return PaginatedResponse(
|
|
1981
|
-
count=int(data.get("count") or len(data.get("results") or [])),
|
|
1982
|
-
next=data.get("next"),
|
|
1983
|
-
previous=data.get("previous"),
|
|
1984
|
-
results=data.get("results", []),
|
|
1985
|
-
cursor=data.get("cursor"),
|
|
1986
|
-
page_metadata=data.get("page_metadata"),
|
|
1987
|
-
)
|
|
1988
|
-
|
|
1989
2046
|
# ============================================================================
|
|
1990
2047
|
# Webhooks (v2)
|
|
1991
2048
|
# ============================================================================
|
tango/models.py
CHANGED
|
@@ -433,6 +433,33 @@ class Notice:
|
|
|
433
433
|
naics_code: str | None = None
|
|
434
434
|
|
|
435
435
|
|
|
436
|
+
@dataclass
|
|
437
|
+
class Protest:
|
|
438
|
+
"""Schema definition for Protest (not used for instances)
|
|
439
|
+
|
|
440
|
+
Bid protest records at /api/protests/. Case-level object identified by case_id (UUID).
|
|
441
|
+
See https://tango.makegov.com/docs/api-reference/protests.md.
|
|
442
|
+
"""
|
|
443
|
+
|
|
444
|
+
case_id: str
|
|
445
|
+
case_number: str | None = None
|
|
446
|
+
title: str | None = None
|
|
447
|
+
source_system: str | None = None
|
|
448
|
+
outcome: str | None = None
|
|
449
|
+
agency: str | None = None
|
|
450
|
+
protester: str | None = None
|
|
451
|
+
solicitation_number: str | None = None
|
|
452
|
+
case_type: str | None = None
|
|
453
|
+
filed_date: datetime | None = None
|
|
454
|
+
posted_date: datetime | None = None
|
|
455
|
+
decision_date: datetime | None = None
|
|
456
|
+
due_date: datetime | None = None
|
|
457
|
+
docket_url: str | None = None
|
|
458
|
+
decision_url: str | None = None
|
|
459
|
+
digest: str | None = None
|
|
460
|
+
dockets: list[dict[str, Any]] | None = None
|
|
461
|
+
|
|
462
|
+
|
|
436
463
|
@dataclass
|
|
437
464
|
class AssistanceListing:
|
|
438
465
|
"""Schema definition for Assistance Listing (not used for instances)"""
|
|
@@ -575,7 +602,7 @@ class ShapeConfig:
|
|
|
575
602
|
"business_types,primary_naics,naics_codes,psc_codes,"
|
|
576
603
|
"email_address,entity_url,description,capabilities,keywords,"
|
|
577
604
|
"physical_address,mailing_address,"
|
|
578
|
-
"federal_obligations,congressional_district"
|
|
605
|
+
"federal_obligations(*),congressional_district"
|
|
579
606
|
)
|
|
580
607
|
|
|
581
608
|
# Default for list_forecasts()
|
|
@@ -589,6 +616,9 @@ class ShapeConfig:
|
|
|
589
616
|
# Default for list_notices()
|
|
590
617
|
NOTICES_MINIMAL: Final = "notice_id,title,solicitation_number,posted_date"
|
|
591
618
|
|
|
619
|
+
# Default for list_protests()
|
|
620
|
+
PROTESTS_MINIMAL: Final = "case_id,case_number,title,source_system,outcome,filed_date"
|
|
621
|
+
|
|
592
622
|
# Default for list_grants()
|
|
593
623
|
GRANTS_MINIMAL: Final = "grant_id,opportunity_number,title,status(*),agency_code"
|
|
594
624
|
|
tango/shapes/explicit_schemas.py
CHANGED
|
@@ -637,6 +637,57 @@ NOTICE_SCHEMA: dict[str, FieldSchema] = {
|
|
|
637
637
|
}
|
|
638
638
|
|
|
639
639
|
|
|
640
|
+
# Docket-level fields for Protest dockets expansion: dockets(docket_number, filed_date, ...)
|
|
641
|
+
PROTEST_DOCKET_SCHEMA: dict[str, FieldSchema] = {
|
|
642
|
+
"source_system": FieldSchema(name="source_system", type=str, is_optional=True, is_list=False),
|
|
643
|
+
"case_number": FieldSchema(name="case_number", type=str, is_optional=True, is_list=False),
|
|
644
|
+
"docket_number": FieldSchema(name="docket_number", type=str, is_optional=True, is_list=False),
|
|
645
|
+
"title": FieldSchema(name="title", type=str, is_optional=True, is_list=False),
|
|
646
|
+
"protester": FieldSchema(name="protester", type=str, is_optional=True, is_list=False),
|
|
647
|
+
"agency": FieldSchema(name="agency", type=str, is_optional=True, is_list=False),
|
|
648
|
+
"solicitation_number": FieldSchema(
|
|
649
|
+
name="solicitation_number", type=str, is_optional=True, is_list=False
|
|
650
|
+
),
|
|
651
|
+
"case_type": FieldSchema(name="case_type", type=str, is_optional=True, is_list=False),
|
|
652
|
+
"outcome": FieldSchema(name="outcome", type=str, is_optional=True, is_list=False),
|
|
653
|
+
"filed_date": FieldSchema(name="filed_date", type=datetime, is_optional=True, is_list=False),
|
|
654
|
+
"posted_date": FieldSchema(name="posted_date", type=datetime, is_optional=True, is_list=False),
|
|
655
|
+
"decision_date": FieldSchema(
|
|
656
|
+
name="decision_date", type=datetime, is_optional=True, is_list=False
|
|
657
|
+
),
|
|
658
|
+
"due_date": FieldSchema(name="due_date", type=datetime, is_optional=True, is_list=False),
|
|
659
|
+
"docket_url": FieldSchema(name="docket_url", type=str, is_optional=True, is_list=False),
|
|
660
|
+
"decision_url": FieldSchema(name="decision_url", type=str, is_optional=True, is_list=False),
|
|
661
|
+
"digest": FieldSchema(name="digest", type=str, is_optional=True, is_list=False),
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
PROTEST_SCHEMA: dict[str, FieldSchema] = {
|
|
665
|
+
"case_id": FieldSchema(name="case_id", type=str, is_optional=False, is_list=False),
|
|
666
|
+
"case_number": FieldSchema(name="case_number", type=str, is_optional=True, is_list=False),
|
|
667
|
+
"title": FieldSchema(name="title", type=str, is_optional=True, is_list=False),
|
|
668
|
+
"source_system": FieldSchema(name="source_system", type=str, is_optional=True, is_list=False),
|
|
669
|
+
"outcome": FieldSchema(name="outcome", type=str, is_optional=True, is_list=False),
|
|
670
|
+
"agency": FieldSchema(name="agency", type=str, is_optional=True, is_list=False),
|
|
671
|
+
"protester": FieldSchema(name="protester", type=str, is_optional=True, is_list=False),
|
|
672
|
+
"solicitation_number": FieldSchema(
|
|
673
|
+
name="solicitation_number", type=str, is_optional=True, is_list=False
|
|
674
|
+
),
|
|
675
|
+
"case_type": FieldSchema(name="case_type", type=str, is_optional=True, is_list=False),
|
|
676
|
+
"filed_date": FieldSchema(name="filed_date", type=datetime, is_optional=True, is_list=False),
|
|
677
|
+
"posted_date": FieldSchema(name="posted_date", type=datetime, is_optional=True, is_list=False),
|
|
678
|
+
"decision_date": FieldSchema(
|
|
679
|
+
name="decision_date", type=datetime, is_optional=True, is_list=False
|
|
680
|
+
),
|
|
681
|
+
"due_date": FieldSchema(name="due_date", type=datetime, is_optional=True, is_list=False),
|
|
682
|
+
"docket_url": FieldSchema(name="docket_url", type=str, is_optional=True, is_list=False),
|
|
683
|
+
"decision_url": FieldSchema(name="decision_url", type=str, is_optional=True, is_list=False),
|
|
684
|
+
"digest": FieldSchema(name="digest", type=str, is_optional=True, is_list=False),
|
|
685
|
+
"dockets": FieldSchema(
|
|
686
|
+
name="dockets", type=dict, is_optional=True, is_list=True, nested_model="ProtestDocket"
|
|
687
|
+
),
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
|
|
640
691
|
AGENCY_SCHEMA: dict[str, FieldSchema] = {
|
|
641
692
|
"abbreviation": FieldSchema(name="abbreviation", type=str, is_optional=True, is_list=False),
|
|
642
693
|
"code": FieldSchema(name="code", type=str, is_optional=False, is_list=False),
|
|
@@ -1105,6 +1156,8 @@ EXPLICIT_SCHEMAS: dict[str, dict[str, FieldSchema]] = {
|
|
|
1105
1156
|
"Forecast": FORECAST_SCHEMA,
|
|
1106
1157
|
"Opportunity": OPPORTUNITY_SCHEMA,
|
|
1107
1158
|
"Notice": NOTICE_SCHEMA,
|
|
1159
|
+
"Protest": PROTEST_SCHEMA,
|
|
1160
|
+
"ProtestDocket": PROTEST_DOCKET_SCHEMA,
|
|
1108
1161
|
"Agency": AGENCY_SCHEMA,
|
|
1109
1162
|
"Grant": GRANT_SCHEMA,
|
|
1110
1163
|
# Vehicles (Awards)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tango-python
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Python SDK for the Tango API
|
|
5
5
|
Project-URL: Homepage, https://github.com/makegov/tango-python
|
|
6
6
|
Project-URL: Documentation, https://docs.makegov.com/tango-python
|
|
@@ -61,7 +61,7 @@ A modern Python SDK for the [Tango API](https://tango.makegov.com) by MakeGov, f
|
|
|
61
61
|
|
|
62
62
|
- **Dynamic Response Shaping** - Request only the fields you need, reducing payload sizes by 60-80%
|
|
63
63
|
- **Full Type Safety** - Runtime-generated TypedDict types with accurate type hints for IDE autocomplete
|
|
64
|
-
- **Comprehensive API Coverage** - All major Tango API endpoints (contracts, entities, forecasts, opportunities, notices, grants, webhooks
|
|
64
|
+
- **Comprehensive API Coverage** - All major Tango API endpoints (contracts, IDVs, OTAs, entities, forecasts, opportunities, notices, grants, protests, webhooks, and more)
|
|
65
65
|
- **Flexible Data Access** - Dictionary-based response objects with validation
|
|
66
66
|
- **Modern Python** - Built for Python 3.12+ using modern async-ready patterns
|
|
67
67
|
- **Production-Ready** - Comprehensive test suite with VCR.py-based integration tests
|
|
@@ -207,14 +207,33 @@ contracts = client.list_contracts(
|
|
|
207
207
|
**Response Options:**
|
|
208
208
|
- `shape`, `flat`, `flat_lists` - Response shaping options
|
|
209
209
|
|
|
210
|
+
### IDVs, OTAs, OTIDVs
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
# List IDVs (keyset pagination)
|
|
214
|
+
idvs = client.list_idvs(limit=25, awarding_agency="4700")
|
|
215
|
+
|
|
216
|
+
# Get single IDV with shaping
|
|
217
|
+
idv = client.get_idv("IDV_KEY", shape=ShapeConfig.IDVS_COMPREHENSIVE)
|
|
218
|
+
|
|
219
|
+
# OTAs and OTIDVs follow the same pattern
|
|
220
|
+
otas = client.list_otas(limit=25)
|
|
221
|
+
otidvs = client.list_otidvs(limit=25)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Vehicles
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
vehicles = client.list_vehicles(search="GSA schedule", shape=ShapeConfig.VEHICLES_MINIMAL)
|
|
228
|
+
vehicle = client.get_vehicle("UUID", shape=ShapeConfig.VEHICLES_COMPREHENSIVE)
|
|
229
|
+
awardees = client.list_vehicle_awardees("UUID")
|
|
230
|
+
```
|
|
231
|
+
|
|
210
232
|
### Entities (Vendors/Recipients)
|
|
211
233
|
|
|
212
234
|
```python
|
|
213
|
-
# List entities
|
|
214
|
-
entities = client.list_entities(
|
|
215
|
-
page=1,
|
|
216
|
-
limit=25
|
|
217
|
-
)
|
|
235
|
+
# List entities with filters
|
|
236
|
+
entities = client.list_entities(search="Booz Allen", state="VA", limit=25)
|
|
218
237
|
|
|
219
238
|
# Get specific entity by UEI or CAGE code
|
|
220
239
|
entity = client.get_entity("ZQGGHJH74DW7")
|
|
@@ -223,47 +242,49 @@ entity = client.get_entity("ZQGGHJH74DW7")
|
|
|
223
242
|
### Forecasts
|
|
224
243
|
|
|
225
244
|
```python
|
|
226
|
-
|
|
227
|
-
forecasts = client.list_forecasts(
|
|
228
|
-
agency="GSA",
|
|
229
|
-
limit=25
|
|
230
|
-
)
|
|
245
|
+
forecasts = client.list_forecasts(agency="GSA", fiscal_year=2025, limit=25)
|
|
231
246
|
```
|
|
232
247
|
|
|
233
248
|
### Opportunities
|
|
234
249
|
|
|
235
250
|
```python
|
|
236
|
-
|
|
237
|
-
opportunities = client.list_opportunities(
|
|
238
|
-
agency="DOD",
|
|
239
|
-
limit=25
|
|
240
|
-
)
|
|
251
|
+
opportunities = client.list_opportunities(agency="DOD", active=True, limit=25)
|
|
241
252
|
```
|
|
242
253
|
|
|
243
254
|
### Notices
|
|
244
255
|
|
|
245
256
|
```python
|
|
246
|
-
|
|
247
|
-
notices = client.list_notices(
|
|
248
|
-
agency="DOD",
|
|
249
|
-
limit=25
|
|
250
|
-
)
|
|
257
|
+
notices = client.list_notices(agency="DOD", notice_type="award", limit=25)
|
|
251
258
|
```
|
|
252
259
|
|
|
253
260
|
### Grants
|
|
254
261
|
|
|
255
262
|
```python
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
263
|
+
grants = client.list_grants(agency="HHS", status="forecasted", limit=25)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Protests
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
protests = client.list_protests(source_system="gao", outcome="Sustained", limit=25)
|
|
270
|
+
protest = client.get_protest("CASE_UUID")
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### GSA eLibrary Contracts
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
contracts = client.list_gsa_elibrary_contracts(schedule="MAS", limit=25)
|
|
277
|
+
contract = client.get_gsa_elibrary_contract("UUID")
|
|
261
278
|
```
|
|
262
279
|
|
|
263
|
-
###
|
|
280
|
+
### Reference Data
|
|
264
281
|
|
|
265
282
|
```python
|
|
266
|
-
#
|
|
283
|
+
# Offices, organizations, NAICS, subawards, business types
|
|
284
|
+
offices = client.list_offices(search="acquisitions")
|
|
285
|
+
organizations = client.list_organizations(level=1)
|
|
286
|
+
naics = client.list_naics(search="software")
|
|
287
|
+
subawards = client.list_subawards(prime_uei="UEI123")
|
|
267
288
|
business_types = client.list_business_types()
|
|
268
289
|
```
|
|
269
290
|
|
|
@@ -476,9 +497,16 @@ tango-python/
|
|
|
476
497
|
│ ├── test_entities_integration.py
|
|
477
498
|
│ ├── test_forecasts_integration.py
|
|
478
499
|
│ ├── test_grants_integration.py
|
|
500
|
+
│ ├── test_naics_integration.py
|
|
479
501
|
│ ├── test_notices_integration.py
|
|
502
|
+
│ ├── test_offices_integration.py
|
|
480
503
|
│ ├── test_opportunities_integration.py
|
|
504
|
+
│ ├── test_organizations_integration.py
|
|
505
|
+
│ ├── test_otas_otidvs_integration.py
|
|
506
|
+
│ ├── test_protests_integration.py
|
|
481
507
|
│ ├── test_reference_data_integration.py
|
|
508
|
+
│ ├── test_subawards_integration.py
|
|
509
|
+
│ ├── test_vehicles_idvs_integration.py
|
|
482
510
|
│ └── test_edge_cases_integration.py
|
|
483
511
|
├── docs/ # Documentation
|
|
484
512
|
│ ├── API_REFERENCE.md # Complete API reference
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
tango/__init__.py,sha256=7EdEUgCcK0lDNJWWDgdSWxx8xxryO-fHL-iml9PaYLw,1102
|
|
2
|
-
tango/client.py,sha256=
|
|
2
|
+
tango/client.py,sha256=HvS-ss9QOeajLOkP2IsX9gTF_KvOb9_NOlLUphd8gSc,86111
|
|
3
3
|
tango/exceptions.py,sha256=JmtbOY0ofBnX24pUErh2XFlTj9dim2ngyboserEGRFw,2226
|
|
4
|
-
tango/models.py,sha256=
|
|
4
|
+
tango/models.py,sha256=4sLmWjyqsCU7-b8lr9ZRRG_ElBKz-5txibcOFcScEDY,20555
|
|
5
5
|
tango/shapes/__init__.py,sha256=7ea1WU74jp4znhNw-gXruag6m6eyPZtbVgbDFmFUWro,1072
|
|
6
|
-
tango/shapes/explicit_schemas.py,sha256=
|
|
6
|
+
tango/shapes/explicit_schemas.py,sha256=H4pYs0LCTSV5msRCxftmgiM_-3sc4LsqpDPgj36DkPY,55202
|
|
7
7
|
tango/shapes/factory.py,sha256=ytpMi5Uw72XZ8MimhuSsLDVXF3zO_Zt3_tAL6NF7LnU,34318
|
|
8
8
|
tango/shapes/generator.py,sha256=61V1T3lm8Ps_KSMJAezQJLQVFbNKt1jtoLyhiqNtFTs,23380
|
|
9
9
|
tango/shapes/models.py,sha256=h3pIhOqrrdlN953Y6r0oney5HFbKPOD-frRndRWimJ0,3018
|
|
10
10
|
tango/shapes/parser.py,sha256=k6OsI2w3GH6-IBbc-XTLgL1mWH7bMf7A_dA6pr1xKfw,24619
|
|
11
11
|
tango/shapes/schema.py,sha256=VRPOB1sBdjFyimNchrZKIpTHn83CyX4RfU9077aQtIU,14136
|
|
12
12
|
tango/shapes/types.py,sha256=27jrAE0VIdrKaLjR_FK71hfIIGX2Tg3ex7REEBV1TFE,1301
|
|
13
|
-
tango_python-0.4.
|
|
14
|
-
tango_python-0.4.
|
|
15
|
-
tango_python-0.4.
|
|
16
|
-
tango_python-0.4.
|
|
13
|
+
tango_python-0.4.2.dist-info/METADATA,sha256=h3QpwadNjsoHnMuXXpFj6BScFCvx61NGGOM43gG6GLQ,17595
|
|
14
|
+
tango_python-0.4.2.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
15
|
+
tango_python-0.4.2.dist-info/licenses/LICENSE,sha256=j2kYVHMwTkoGn3ZNScnrdIueG0k2XzB_LCPFoyBc2wk,1064
|
|
16
|
+
tango_python-0.4.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|