tango-python 1.11.0__py3-none-any.whl → 1.12.0__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/__init__.py CHANGED
@@ -11,6 +11,9 @@ from .exceptions import (
11
11
  )
12
12
  from .models import (
13
13
  BudgetAccount,
14
+ BudgetAccountAnomalySource,
15
+ BudgetAccountAnomalySourceRow,
16
+ BudgetAccountSourceAnomaly,
14
17
  ContractAppeal,
15
18
  DibbsAward,
16
19
  DibbsRfp,
@@ -59,7 +62,7 @@ from .webhooks import (
59
62
  )
60
63
  from .webhooks.receiver import Delivery, WebhookReceiver
61
64
 
62
- __version__ = "1.11.0"
65
+ __version__ = "1.12.0"
63
66
  __all__ = [
64
67
  "TangoClient",
65
68
  "TangoAPIError",
@@ -72,6 +75,9 @@ __all__ = [
72
75
  "ResolveCandidate",
73
76
  "ResolveResult",
74
77
  "BudgetAccount",
78
+ "BudgetAccountAnomalySource",
79
+ "BudgetAccountAnomalySourceRow",
80
+ "BudgetAccountSourceAnomaly",
75
81
  "ContractAppeal",
76
82
  "FederalRegisterDocument",
77
83
  "EbuyAccess",
tango/client.py CHANGED
@@ -986,6 +986,7 @@ class TangoClient:
986
986
  next=data.get("next"),
987
987
  previous=data.get("previous"),
988
988
  results=results,
989
+ cursor=data.get("cursor"),
989
990
  page_metadata=data.get("page_metadata"),
990
991
  meta=data.get("meta"),
991
992
  )
@@ -1088,6 +1089,7 @@ class TangoClient:
1088
1089
  next=data.get("next"),
1089
1090
  previous=data.get("previous"),
1090
1091
  results=results,
1092
+ cursor=data.get("cursor"),
1091
1093
  page_metadata=data.get("page_metadata"),
1092
1094
  meta=data.get("meta"),
1093
1095
  )
@@ -1133,6 +1135,7 @@ class TangoClient:
1133
1135
  next=data.get("next"),
1134
1136
  previous=data.get("previous"),
1135
1137
  results=results,
1138
+ cursor=data.get("cursor"),
1136
1139
  page_metadata=data.get("page_metadata"),
1137
1140
  meta=data.get("meta"),
1138
1141
  )
@@ -1150,6 +1153,7 @@ class TangoClient:
1150
1153
  next=data.get("next"),
1151
1154
  previous=data.get("previous"),
1152
1155
  results=data.get("results") or [],
1156
+ cursor=data.get("cursor"),
1153
1157
  page_metadata=data.get("page_metadata"),
1154
1158
  meta=data.get("meta"),
1155
1159
  )
@@ -4444,6 +4448,8 @@ class TangoClient:
4444
4448
  bea_category: str | None = None,
4445
4449
  on_off_budget: str | None = None,
4446
4450
  subfunction_code: str | None = None,
4451
+ account_category: str | None = None,
4452
+ account_category_in: str | None = None,
4447
4453
  # Range-numeric filters: each field also accepts ``__gte`` / ``__lte``.
4448
4454
  requested_ba: float | None = None,
4449
4455
  requested_ba_gte: float | None = None,
@@ -4550,6 +4556,11 @@ class TangoClient:
4550
4556
  bea_category: BEA category (exact).
4551
4557
  on_off_budget: On/off budget flag (exact).
4552
4558
  subfunction_code: Subfunction code (exact).
4559
+ account_category: Account category (exact), e.g. ``budgetary`` or
4560
+ ``credit_financing``. Treat the value as an open string; new
4561
+ categories may be added.
4562
+ account_category_in: Comma-separated account categories to match
4563
+ any of, e.g. ``"budgetary,credit_financing"``.
4553
4564
  requested_ba: President's-budget requested BA (exact). Also
4554
4565
  ``requested_ba_gte`` / ``requested_ba_lte`` for range queries.
4555
4566
  enacted_ba: Enacted budget authority (exact / gte / lte).
@@ -4592,7 +4603,9 @@ class TangoClient:
4592
4603
  ordering: Sort field (prefix with '-' for descending). Any of the
4593
4604
  numeric fields above is a valid ordering target — e.g.
4594
4605
  ``ordering="-unobligated_balance"`` to rank by largest
4595
- headroom first.
4606
+ headroom first. The default ordering is the latest fiscal year
4607
+ first, then largest ``enacted_ba`` first, with accounts that
4608
+ have no ``enacted_ba`` sorted last.
4596
4609
  """
4597
4610
  params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
4598
4611
  if shape is None:
@@ -4615,6 +4628,8 @@ class TangoClient:
4615
4628
  ("bea_category", bea_category),
4616
4629
  ("on_off_budget", on_off_budget),
4617
4630
  ("subfunction_code", subfunction_code),
4631
+ ("account_category", account_category),
4632
+ ("account_category__in", account_category_in),
4618
4633
  ("search", search),
4619
4634
  ("ordering", ordering),
4620
4635
  )
tango/models.py CHANGED
@@ -786,6 +786,55 @@ class ValidateResult:
786
786
  errors: list[str] | None = None
787
787
 
788
788
 
789
+ class BudgetAccountAnomalySourceRow(TypedDict, total=False):
790
+ """One source record behind a budget-account source anomaly.
791
+
792
+ Every key is optional and any value may be ``None``.
793
+ """
794
+
795
+ fiscal_period: int | None
796
+ piid: str | None
797
+ parent_piid: str | None
798
+ tas: str | None
799
+ reporting_agency_id: str | None
800
+ transaction_obligated_amount: float | str | None
801
+ file_c_source: str | None
802
+
803
+
804
+ class BudgetAccountAnomalySource(TypedDict, total=False):
805
+ """Where a budget-account source anomaly was found.
806
+
807
+ Every key is optional and any value may be ``None``.
808
+ """
809
+
810
+ dataset: str | None
811
+ fiscal_year: int | None
812
+ rows: list[BudgetAccountAnomalySourceRow] | None
813
+
814
+
815
+ class BudgetAccountSourceAnomaly(TypedDict, total=False):
816
+ """One problem found in the source data behind a budget account.
817
+
818
+ An element of ``BudgetAccount.source_anomalies``. Every key is optional and
819
+ any value may be ``None``, so read keys with ``.get()``. ``code`` and
820
+ ``action`` are open strings: today ``code`` is one of
821
+ ``contract_exceeds_obligations``, ``assistance_exceeds_obligations`` or
822
+ ``contract_without_obligations``, and ``action`` is ``capped`` or
823
+ ``flagged``, but new values may appear.
824
+ """
825
+
826
+ code: str | None
827
+ field: str | None
828
+ bound_field: str | None
829
+ action: str | None
830
+ reported_value: float | str | None
831
+ served_value: float | str | None
832
+ likely_cause: str | None
833
+ affected_fields: list[str] | None
834
+ message: str | None
835
+ source: BudgetAccountAnomalySource | None
836
+
837
+
789
838
  @dataclass
790
839
  class BudgetAccount:
791
840
  """Schema definition for BudgetAccount (not used for instances).
@@ -805,6 +854,8 @@ class BudgetAccount:
805
854
  bea_category: str | None = None
806
855
  on_off_budget: str | None = None
807
856
  subfunction_code: str | None = None
857
+ # ``budgetary`` or ``credit_financing`` today; treat as an open string.
858
+ account_category: str | None = None
808
859
  # Lifecycle
809
860
  requested_ba: Decimal | None = None
810
861
  enacted_ba: Decimal | None = None
@@ -828,6 +879,8 @@ class BudgetAccount:
828
879
  assistance_share_of_obligated: Decimal | None = None
829
880
  assistance_share_of_obligated_capped: Decimal | None = None
830
881
  assistance_share_capped_flag: bool | None = None
882
+ # Problems found in the source data; ``[]`` when there are none.
883
+ source_anomalies: list[BudgetAccountSourceAnomaly] | None = None
831
884
  # Forward-look
832
885
  next_year_requested_ba: Decimal | None = None
833
886
  ba_growth_next_year: Decimal | None = None
@@ -1728,12 +1781,12 @@ class ShapeConfig:
1728
1781
  # Mirrors the API's BUDGET_ACCOUNT_DEFAULT_SHAPE.
1729
1782
  BUDGET_ACCOUNTS_MINIMAL: Final = (
1730
1783
  "id,federal_account_symbol,fiscal_year,agency_code,agency_name,bureau_name,"
1731
- "account_title,bea_category,on_off_budget,subfunction_code,"
1784
+ "account_title,bea_category,on_off_budget,subfunction_code,account_category,"
1732
1785
  "requested_ba,enacted_ba,apportioned,obligated_total,outlayed_total,"
1733
1786
  "unobligated_balance,contract_obligated,contract_share_of_obligated_capped,"
1734
1787
  "assistance_obligated,obligated_to_apportioned_pct_capped,"
1735
1788
  "obligated_to_enacted_pct_capped,outlayed_to_obligated_pct_capped,"
1736
- "ba_growth_next_year_pct"
1789
+ "ba_growth_next_year_pct,source_anomalies"
1737
1790
  )
1738
1791
 
1739
1792
  # Default for list_organizations()
@@ -1225,6 +1225,9 @@ GENERATED_OVERLAY: dict[str, dict[str, FieldSchema]] = {
1225
1225
  ),
1226
1226
  },
1227
1227
  "BudgetAccount": {
1228
+ "account_category": FieldSchema(
1229
+ name="account_category", type=str, is_optional=True, is_list=False
1230
+ ),
1228
1231
  "account_narrative_excerpt": FieldSchema(
1229
1232
  name="account_narrative_excerpt", type=str, is_optional=True, is_list=False
1230
1233
  ),
@@ -1410,6 +1413,9 @@ GENERATED_OVERLAY: dict[str, dict[str, FieldSchema]] = {
1410
1413
  "requested_personnel_share": FieldSchema(
1411
1414
  name="requested_personnel_share", type=str, is_optional=True, is_list=False
1412
1415
  ),
1416
+ "source_anomalies": FieldSchema(
1417
+ name="source_anomalies", type=dict, is_optional=True, is_list=True
1418
+ ),
1413
1419
  "subfunction_code": FieldSchema(
1414
1420
  name="subfunction_code", type=str, is_optional=True, is_list=False
1415
1421
  ),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tango-python
3
- Version: 1.11.0
3
+ Version: 1.12.0
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
@@ -1,11 +1,11 @@
1
- tango/__init__.py,sha256=nM2IFpjrIua3MzTAR1bedo7DRmTgJ0DU9YeRQOlDXQA,2535
2
- tango/client.py,sha256=3jxYp3Dcgy8cVUpy0uK0H_qQbfKrgWMq3k65bm0uadg,238519
1
+ tango/__init__.py,sha256=XRADxf8CwMbNTUr999g7MgiFKFuzoSQ0L2szhIIDWtU,2739
2
+ tango/client.py,sha256=YkbWxdNE91229sDWwPCizAYfTl1LZK517wuD2I5hPhQ,239391
3
3
  tango/exceptions.py,sha256=oPiLCccBoWLK5SjHkzP-oI6mUD9twEeKSvEuLV5h01I,4224
4
- tango/models.py,sha256=WkIK_Ym36afRych_EtlGk5Ki3aevL14klk0SCiCDxgU,67741
4
+ tango/models.py,sha256=vviVPF0gJQTpqMJE7oGhZrJuavGgwhU5NazlVJBzpYw,69578
5
5
  tango/shapes/__init__.py,sha256=7ea1WU74jp4znhNw-gXruag6m6eyPZtbVgbDFmFUWro,1072
6
6
  tango/shapes/explicit_schemas.py,sha256=spYyMmWKOiMJygz9yViBQrjIxUPFfv7HpVkJcWy13x8,84021
7
7
  tango/shapes/factory.py,sha256=uDPhnp6VVzrLBKodxteZy5AcU43juEv-qKVRWth51j0,31550
8
- tango/shapes/generated_overlay.py,sha256=RrCqR-iwBnUbr5dtPQ_f78fnrWcfLf_fP9EtfHKIdw4,140461
8
+ tango/shapes/generated_overlay.py,sha256=9SNrqVFBz59Xo8-u24-x-74g42juhCKjAArQr9_MM8o,140723
9
9
  tango/shapes/generator.py,sha256=xzakpwTwqTMUr89I06hp54-FIYZziviWHk2Glscg-LM,22775
10
10
  tango/shapes/models.py,sha256=h3pIhOqrrdlN953Y6r0oney5HFbKPOD-frRndRWimJ0,3018
11
11
  tango/shapes/parser.py,sha256=AecNx5oT_hV_pf2AWZnsR8Y2aLmCtjfgS9-znA2Pesc,27429
@@ -16,8 +16,8 @@ tango/webhooks/cli.py,sha256=f_vQbJ2AeSQjKnQo7MxHFyUB2SAKcgHYmGQULS0isqQ,13858
16
16
  tango/webhooks/receiver.py,sha256=5yhsVhlLyoxmOCGvmbynWAIlDB2OaCPVf1H4GA1SxmU,9279
17
17
  tango/webhooks/signing.py,sha256=92Ee-0B6PR7ZkvY3Np3gzl88-mtfKkh-I7lxqCe2lGw,2374
18
18
  tango/webhooks/simulate.py,sha256=g2Osa0FYU5mJuon07T2aUCtmkUoTEzsY261tlp76fF0,3165
19
- tango_python-1.11.0.dist-info/METADATA,sha256=l9-XAukNLKq3XM_V8zjXOzALwqo6MeGBIFtdEsW9kuY,22118
20
- tango_python-1.11.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
21
- tango_python-1.11.0.dist-info/entry_points.txt,sha256=kGLUbglUjuaAqEFvOZ1QuSW0vWb6VeSpCIFKaOFkKoQ,50
22
- tango_python-1.11.0.dist-info/licenses/LICENSE,sha256=j2kYVHMwTkoGn3ZNScnrdIueG0k2XzB_LCPFoyBc2wk,1064
23
- tango_python-1.11.0.dist-info/RECORD,,
19
+ tango_python-1.12.0.dist-info/METADATA,sha256=JsVs05maoR9Q7YGHhn4RQLpqyPG_ptX6BgpGnakcaeI,22118
20
+ tango_python-1.12.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
21
+ tango_python-1.12.0.dist-info/entry_points.txt,sha256=kGLUbglUjuaAqEFvOZ1QuSW0vWb6VeSpCIFKaOFkKoQ,50
22
+ tango_python-1.12.0.dist-info/licenses/LICENSE,sha256=j2kYVHMwTkoGn3ZNScnrdIueG0k2XzB_LCPFoyBc2wk,1064
23
+ tango_python-1.12.0.dist-info/RECORD,,