agentdata 0.3.26__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.
Files changed (120) hide show
  1. agentdata/__init__.py +33 -0
  2. agentdata/__main__.py +4 -0
  3. agentdata/cache.py +115 -0
  4. agentdata/cli.py +173 -0
  5. agentdata/client.py +158 -0
  6. agentdata/company/__init__.py +3 -0
  7. agentdata/company/cf.py +145 -0
  8. agentdata/company/ch_zefix.py +100 -0
  9. agentdata/company/cli.py +243 -0
  10. agentdata/company/co_rues.py +72 -0
  11. agentdata/company/edgar_cik.py +84 -0
  12. agentdata/company/edgar_fts.py +101 -0
  13. agentdata/company/faces.py +746 -0
  14. agentdata/company/fdic_bankfind.py +107 -0
  15. agentdata/company/fi_ytj.py +89 -0
  16. agentdata/company/fr_recherche.py +124 -0
  17. agentdata/company/fts.py +121 -0
  18. agentdata/company/gleif.py +178 -0
  19. agentdata/company/kr_hometax.py +112 -0
  20. agentdata/company/no_brreg.py +124 -0
  21. agentdata/company/ror.py +105 -0
  22. agentdata/company/ted.py +117 -0
  23. agentdata/company/usaspending.py +124 -0
  24. agentdata/company/vies.py +66 -0
  25. agentdata/daterange.py +35 -0
  26. agentdata/economy/__init__.py +10 -0
  27. agentdata/economy/bis.py +132 -0
  28. agentdata/economy/cli.py +199 -0
  29. agentdata/economy/ecb.py +117 -0
  30. agentdata/economy/eurostat.py +163 -0
  31. agentdata/economy/faces.py +573 -0
  32. agentdata/economy/fred.py +92 -0
  33. agentdata/economy/ilo_stat.py +99 -0
  34. agentdata/economy/imf_sdmx.py +133 -0
  35. agentdata/economy/un_comtrade.py +199 -0
  36. agentdata/economy/unsd_sdg.py +154 -0
  37. agentdata/economy/wb.py +208 -0
  38. agentdata/economy/who_xmart.py +177 -0
  39. agentdata/entries.py +30 -0
  40. agentdata/errors.py +38 -0
  41. agentdata/esg/__init__.py +5 -0
  42. agentdata/esg/cli.py +180 -0
  43. agentdata/esg/climatetrace.py +260 -0
  44. agentdata/esg/eiti.py +187 -0
  45. agentdata/esg/epa_frs.py +138 -0
  46. agentdata/esg/euasl.py +75 -0
  47. agentdata/esg/eutl.py +66 -0
  48. agentdata/esg/faces.py +498 -0
  49. agentdata/esg/paris_mou.py +240 -0
  50. agentdata/esg/thetis_mrv.py +67 -0
  51. agentdata/healthcare/__init__.py +7 -0
  52. agentdata/healthcare/au_tga.py +142 -0
  53. agentdata/healthcare/ca_dpd.py +123 -0
  54. agentdata/healthcare/ca_mdall.py +155 -0
  55. agentdata/healthcare/cli.py +375 -0
  56. agentdata/healthcare/ctgov.py +101 -0
  57. agentdata/healthcare/dailymed.py +102 -0
  58. agentdata/healthcare/epmc.py +108 -0
  59. agentdata/healthcare/eudamed.py +124 -0
  60. agentdata/healthcare/faces.py +811 -0
  61. agentdata/healthcare/fda_crl.py +86 -0
  62. agentdata/healthcare/fda_devices.py +199 -0
  63. agentdata/healthcare/fda_drugs.py +156 -0
  64. agentdata/healthcare/fda_recalls.py +137 -0
  65. agentdata/healthcare/gb_mhra.py +137 -0
  66. agentdata/healthcare/gudid.py +84 -0
  67. agentdata/healthcare/mesh.py +89 -0
  68. agentdata/healthcare/rasff.py +164 -0
  69. agentdata/healthcare/rxnav.py +67 -0
  70. agentdata/healthcare/safety_gate.py +175 -0
  71. agentdata/healthcare/shortages.py +107 -0
  72. agentdata/legal/__init__.py +4 -0
  73. agentdata/legal/afdb.py +93 -0
  74. agentdata/legal/ca_sema.py +143 -0
  75. agentdata/legal/cli.py +312 -0
  76. agentdata/legal/co_sic.py +70 -0
  77. agentdata/legal/courtlistener.py +77 -0
  78. agentdata/legal/csl.py +139 -0
  79. agentdata/legal/dgcomp.py +125 -0
  80. agentdata/legal/ecfr.py +129 -0
  81. agentdata/legal/faces.py +700 -0
  82. agentdata/legal/federalregister.py +188 -0
  83. agentdata/legal/gb_cma.py +117 -0
  84. agentdata/legal/gb_tna_caselaw.py +245 -0
  85. agentdata/legal/idb.py +85 -0
  86. agentdata/legal/lda.py +147 -0
  87. agentdata/legal/sipri.py +178 -0
  88. agentdata/legal/ukec.py +148 -0
  89. agentdata/legal/wb.py +92 -0
  90. agentdata/procurement/__init__.py +5 -0
  91. agentdata/procurement/br_pncp.py +126 -0
  92. agentdata/procurement/cli.py +155 -0
  93. agentdata/procurement/co_secop.py +88 -0
  94. agentdata/procurement/faces.py +239 -0
  95. agentdata/procurement/ny_open_data.py +82 -0
  96. agentdata/procurement/ungm.py +137 -0
  97. agentdata/procurement/wb_proc.py +84 -0
  98. agentdata/research/__init__.py +4 -0
  99. agentdata/research/biorxiv.py +66 -0
  100. agentdata/research/cli.py +129 -0
  101. agentdata/research/crossref.py +121 -0
  102. agentdata/research/faces.py +349 -0
  103. agentdata/research/gb_gtr.py +58 -0
  104. agentdata/research/icite.py +52 -0
  105. agentdata/research/nih_reporter.py +143 -0
  106. agentdata/research/nsf.py +68 -0
  107. agentdata/research/openalex.py +145 -0
  108. agentdata/research/opencitations.py +50 -0
  109. agentdata/security/__init__.py +3 -0
  110. agentdata/security/cisa_kev.py +42 -0
  111. agentdata/security/cli.py +37 -0
  112. agentdata/security/faces.py +91 -0
  113. agentdata/security/osv.py +72 -0
  114. agentdata/transport.py +541 -0
  115. agentdata-0.3.26.dist-info/METADATA +266 -0
  116. agentdata-0.3.26.dist-info/RECORD +120 -0
  117. agentdata-0.3.26.dist-info/WHEEL +5 -0
  118. agentdata-0.3.26.dist-info/entry_points.txt +10 -0
  119. agentdata-0.3.26.dist-info/licenses/LICENSE +201 -0
  120. agentdata-0.3.26.dist-info/top_level.txt +1 -0
@@ -0,0 +1,163 @@
1
+ """eurostat — Eurostat dissemination API provider (ec.europa.eu; keyless, no registration).
2
+
3
+ One face: table (one Eurostat table x the filters you give). The upstream speaks JSON-stat 2.0:
4
+ values live in a flat index map and the dimensions carry the code -> position map that rebuilds
5
+ the grid.
6
+
7
+ Shapes verified by first-hand live probing 2026-11-02 (tmp/probe-economy/):
8
+ GET /data/{table}?format=JSON&lang=EN&geo=DE&sinceTimePeriod=2022&untilTimePeriod=2023
9
+ -> {version, class, label, source, updated, value:{flatIdx:num}, status:{flatIdx:code},
10
+ id:[dim...], size:[...], dimension:{dim:{label, category:{index:{code:pos}, label:{...}}}}}
11
+ * several values for one dimension = REPEATED parameters (geo=DE&geo=FR -> 2 cells; the "+"
12
+ form is a 400 and the comma form silently yields 0 cells — the upstream "empty, no error"
13
+ trap);
14
+ * sinceTimePeriod / untilTimePeriod bound the time axis (verified: DE 2022-2023 -> 2 cells);
15
+ * a geo that is not in the table yields size 0 / zero cells and NO error (the upstream
16
+ "silent empty" family — a zero-cell answer is reported as zero cells, never as data);
17
+ * the grid is row-major with the LAST dimension fastest (verified: flat 157 -> time 1985, sex F);
18
+ * `status` carries the cell flags (b = break in time series, e = estimated, p = provisional).
19
+ Rate: no official limit published -> polite tier 1 rps / burst 2. TTL: 12h (Eurostat refreshes
20
+ daily and stamps `updated`).
21
+ """
22
+ from ..errors import SdkError
23
+
24
+ provider = {
25
+ "id": "eurostat",
26
+ "baseUrl": "https://ec.europa.eu/eurostat/api/dissemination/statistics/1.0",
27
+ "rate": {"rps": 1, "burst": 2},
28
+ "ops": {
29
+ "table": {"path": "/data/{table}", "notFound": [404]},
30
+ },
31
+ "ttl": {"table": 12 * 3600},
32
+ }
33
+
34
+ _CELL_CAP = 500_000 # a bare table (no filter) can be tens of millions of cells
35
+ _LABEL_CAP = 500 # per-dimension code->label map: skipped above this size
36
+
37
+
38
+ def _split_values(v):
39
+ """A CLI value may be a list (repeated flags) or one string; Eurostat takes repeated params."""
40
+ if v is None:
41
+ return []
42
+ if isinstance(v, (list, tuple)):
43
+ items = [str(x).strip() for x in v]
44
+ else:
45
+ items = [x.strip() for x in str(v).split(",")]
46
+ return [x for x in items if x]
47
+
48
+
49
+ def _ordered_codes(dim_payload):
50
+ """category.index is code -> position; the position defines the order."""
51
+ idx = (dim_payload.get("category") or {}).get("index") or {}
52
+ if not idx:
53
+ return []
54
+ ordered = [None] * (max(int(p) for p in idx.values()) + 1)
55
+ for code, pos in idx.items():
56
+ ordered[int(pos)] = code
57
+ return ordered
58
+
59
+
60
+ def _decode(payload):
61
+ """JSON-stat 2.0 -> (rows, dimension summary). The flat index is row-major, last dim fastest."""
62
+ dims = payload.get("id") or []
63
+ sizes = [int(x) for x in (payload.get("size") or [])]
64
+ dim_payloads = payload.get("dimension") or {}
65
+ codes = [_ordered_codes(dim_payloads.get(d) or {}) for d in dims]
66
+ values = payload.get("value") or {}
67
+ statuses = payload.get("status") or {}
68
+ rows = []
69
+ for flat_s, val in sorted(values.items(), key=lambda kv: int(kv[0])):
70
+ flat = int(flat_s)
71
+ coords = []
72
+ rem = flat
73
+ for i in range(len(dims) - 1, -1, -1):
74
+ sz = sizes[i] if i < len(sizes) else 1
75
+ sz = sz or 1
76
+ coords.insert(0, rem % sz)
77
+ rem //= sz
78
+ row = {}
79
+ for i, d in enumerate(dims):
80
+ pos = coords[i]
81
+ row[d] = codes[i][pos] if pos < len(codes[i]) else None
82
+ row["value"] = val
83
+ st = statuses.get(flat_s)
84
+ if st:
85
+ row["status"] = st
86
+ rows.append(row)
87
+ summary = {}
88
+ for i, d in enumerate(dims):
89
+ dp = dim_payloads.get(d) or {}
90
+ entry = {"label": dp.get("label"), "codes": codes[i]}
91
+ labels = (dp.get("category") or {}).get("label") or {}
92
+ if labels and len(labels) <= _LABEL_CAP:
93
+ entry["labels"] = labels
94
+ summary[d] = entry
95
+ return rows, summary
96
+
97
+
98
+ def table_raw(table, *, geo=None, time=None, dims=None, since=None, until=None, lang="EN",
99
+ cache=None, no_cache=False):
100
+ """-> {total, count, rows, params, updated, label, dimensions, _meta}; /data/{table}.
101
+ table = the Eurostat table code (e.g. tec00001, demo_pjan, nama_10_a64); geo / time /
102
+ dims are the upstream dimension filters (several values = repeated parameters); dims is the
103
+ generic carrier for the table-specific dimension ids (age, sex, unit, nace_r2 …) as
104
+ k=v pairs; since / until bound the time axis (upstream sinceTimePeriod / untilTimePeriod);
105
+ lang = the upstream language (EN default).
106
+ Local wall: at least one filter (a bare table is a bulk download), and the cell count must
107
+ stay under the local cap."""
108
+ from ..transport import call_provider
109
+
110
+ tbl = str(table or "").strip()
111
+ if not tbl:
112
+ raise SdkError("usage_error", provider="eurostat",
113
+ detail="eurostat_table requires --table (the Eurostat table code, e.g. tec00001)")
114
+ params = {"format": "JSON", "lang": str(lang or "EN").strip() or "EN", "table": tbl}
115
+ geo_v = _split_values(geo)
116
+ time_v = _split_values(time)
117
+ if geo_v:
118
+ params["geo"] = geo_v
119
+ if time_v:
120
+ params["time"] = time_v
121
+ if since:
122
+ params["sinceTimePeriod"] = str(since).strip()
123
+ if until:
124
+ params["untilTimePeriod"] = str(until).strip()
125
+ dim_items = []
126
+ for raw in (dims or []):
127
+ if isinstance(raw, dict):
128
+ items = list(raw.items())
129
+ else:
130
+ items = [tuple(str(raw).split("=", 1))]
131
+ for k, v in items:
132
+ k = str(k).strip()
133
+ if not k:
134
+ continue
135
+ dim_items.append((k, _split_values(v)))
136
+ if not (geo_v or time_v or dim_items or since or until):
137
+ raise SdkError("usage_error", provider="eurostat",
138
+ detail="eurostat_table requires at least one filter (--geo / --time / --dim / "
139
+ "--since / --until) — a bare table is a bulk download, not a query")
140
+ for k, vals in dim_items:
141
+ if len(vals) == 1:
142
+ params[k] = vals[0]
143
+ else:
144
+ params[k] = vals
145
+ r = call_provider(provider, "table", params, cache=cache, no_cache=no_cache)
146
+ payload = r["data"]
147
+ if not isinstance(payload, dict):
148
+ raise SdkError("upstream_unavailable", provider="eurostat",
149
+ detail=f"Unexpected Eurostat payload shape: {str(payload)[:160]!r}")
150
+ sizes = [int(x) for x in (payload.get("size") or [])]
151
+ cells = 1
152
+ for s in sizes:
153
+ cells *= (s or 0)
154
+ if cells > _CELL_CAP:
155
+ raise SdkError("usage_error", provider="eurostat",
156
+ detail=f"The filtered table still holds {cells:,} cells (local cap "
157
+ f"{_CELL_CAP:,}) — narrow the filters (geo / time / dim)")
158
+ rows, summary = _decode(payload)
159
+ return {"total": cells, "count": len(rows), "rows": rows,
160
+ "label": payload.get("label"), "updated": payload.get("updated"),
161
+ "source": payload.get("source"), "dimensions": summary,
162
+ "params": {k: v for k, v in params.items() if k != "table"},
163
+ "_meta": r}