pulse-code 1.0.1__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 (82) hide show
  1. pulse/__init__.py +1 -0
  2. pulse/__main__.py +4 -0
  3. pulse/catalog.py +102 -0
  4. pulse/cli.py +984 -0
  5. pulse/data/catalog.json +1599 -0
  6. pulse/data/queries_index.json +328 -0
  7. pulse/data/variable_labels.json +1338 -0
  8. pulse/llm_builder.py +732 -0
  9. pulse/matcher.py +180 -0
  10. pulse/queries/aids-cases-by-year-1981-1999-req.xml +178 -0
  11. pulse/queries/births-by-year-1995-2002-req.xml +226 -0
  12. pulse/queries/births-by-year-2003-2006-req.xml +306 -0
  13. pulse/queries/births-by-year-2007-2024-req.xml +334 -0
  14. pulse/queries/cancer-incidence-by-site-by-year-1999-2022-req.xml +174 -0
  15. pulse/queries/cancer-mortality-by-site-by-year-2018-2023-req.xml +166 -0
  16. pulse/queries/covid-deaths-by-race-2020-2023-req.xml +529 -0
  17. pulse/queries/drug-deaths-by-month-1999-2020-req.xml +436 -0
  18. pulse/queries/drug-deaths-by-month-2018-2024-req.xml +544 -0
  19. pulse/queries/drug-deaths-by-year-1999-2020-req.xml +436 -0
  20. pulse/queries/drug-deaths-by-year-2018-2024-req.xml +536 -0
  21. pulse/queries/fentanyl-deaths-by-month-1999-2020-req.xml +430 -0
  22. pulse/queries/fentanyl-deaths-by-month-2018-2024-req.xml +530 -0
  23. pulse/queries/fetal-deaths-by-cause-by-year-2014-2024-req.xml +530 -0
  24. pulse/queries/fetal-deaths-by-year-2005-2024-req.xml +322 -0
  25. pulse/queries/heart-vs-cancer-by-sex-2018-2023-req.xml +532 -0
  26. pulse/queries/heat-wave-days-by-county-req.xml +154 -0
  27. pulse/queries/infant-mortality-2018-2023-req.xml +531 -0
  28. pulse/queries/infant-mortality-by-cause-by-year-2007-2023-req.xml +290 -0
  29. pulse/queries/maternal-mortality-by-year-1999-2020-req.xml +351 -0
  30. pulse/queries/maternal-mortality-by-year-2018-2024-req.xml +413 -0
  31. pulse/queries/mortality-by-race-sex-2018-2023-req.xml +490 -0
  32. pulse/queries/mortality-by-year-cause-1979-1998-req.xml +222 -0
  33. pulse/queries/mortality-by-year-cause-1999-2020-req.xml +434 -0
  34. pulse/queries/mortality-by-year-cause-2021-2024-req.xml +529 -0
  35. pulse/queries/opioid-overdose-deaths-2018-2024-req.xml +544 -0
  36. pulse/queries/pm25-by-year-2003-2011-req.xml +194 -0
  37. pulse/queries/provisional-births-by-month-2023-req.xml +854 -0
  38. pulse/queries/racial-mortality-gap-2018-2023-req.xml +531 -0
  39. pulse/queries/std-cases-by-disease-by-year-1984-2014-req.xml +178 -0
  40. pulse/queries/suicide-by-sex-1999-2020-req.xml +411 -0
  41. pulse/queries/suicide-by-sex-2021-2024-req.xml +551 -0
  42. pulse/queries/tb-cases-by-year-1993-2023-req.xml +206 -0
  43. pulse/queries/tick-borne-diseases-by-year-2016-2023-req.xml +125 -0
  44. pulse/queries/underlying-cause-mortality-by-year-1999-2020-req.xml +350 -0
  45. pulse/queries/unintentional-injuries-by-age-2018-2023-req.xml +531 -0
  46. pulse/templates/D10-base.xml +226 -0
  47. pulse/templates/D104-base.xml +142 -0
  48. pulse/templates/D117-base.xml +110 -0
  49. pulse/templates/D128-base.xml +182 -0
  50. pulse/templates/D140-base.xml +318 -0
  51. pulse/templates/D141-base.xml +454 -0
  52. pulse/templates/D149-base.xml +878 -0
  53. pulse/templates/D157-base.xml +490 -0
  54. pulse/templates/D158-base.xml +406 -0
  55. pulse/templates/D159-base.xml +774 -0
  56. pulse/templates/D16-base.xml +266 -0
  57. pulse/templates/D176-base.xml +526 -0
  58. pulse/templates/D178-base.xml +158 -0
  59. pulse/templates/D18-base.xml +262 -0
  60. pulse/templates/D192-base.xml +854 -0
  61. pulse/templates/D204-base.xml +142 -0
  62. pulse/templates/D23-base.xml +258 -0
  63. pulse/templates/D27-base.xml +342 -0
  64. pulse/templates/D31-base.xml +262 -0
  65. pulse/templates/D60-base.xml +274 -0
  66. pulse/templates/D61-base.xml +250 -0
  67. pulse/templates/D66-base.xml +378 -0
  68. pulse/templates/D69-base.xml +278 -0
  69. pulse/templates/D73-base.xml +182 -0
  70. pulse/templates/D74-base.xml +254 -0
  71. pulse/templates/D76-base.xml +350 -0
  72. pulse/templates/D77-base.xml +434 -0
  73. pulse/templates/D8-base.xml +314 -0
  74. pulse/templates/D80-base.xml +174 -0
  75. pulse/templates/D81-base.xml +178 -0
  76. pulse/wonder_client.py +161 -0
  77. pulse_code-1.0.1.dist-info/METADATA +249 -0
  78. pulse_code-1.0.1.dist-info/RECORD +82 -0
  79. pulse_code-1.0.1.dist-info/WHEEL +5 -0
  80. pulse_code-1.0.1.dist-info/entry_points.txt +2 -0
  81. pulse_code-1.0.1.dist-info/licenses/LICENSE +121 -0
  82. pulse_code-1.0.1.dist-info/top_level.txt +1 -0
pulse/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """pulse — CDC WONDER query CLI for exploring and refining public health data."""
pulse/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ from pulse.cli import app
2
+
3
+ if __name__ == "__main__":
4
+ app()
pulse/catalog.py ADDED
@@ -0,0 +1,102 @@
1
+ """Dataset and query catalog loader."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import Optional
9
+
10
+ _DATA_DIR = Path(__file__).parent / "data"
11
+
12
+
13
+ @dataclass
14
+ class Measure:
15
+ code: str
16
+ label: str
17
+
18
+
19
+ @dataclass
20
+ class Dataset:
21
+ id: str
22
+ title: str
23
+ topic: str
24
+ subject: str
25
+ year_start: int
26
+ year_end: Optional[int]
27
+ year_range_label: str
28
+ tags: list[str]
29
+ measures: list[Measure]
30
+ key_groupings: list[str]
31
+ has_template: bool
32
+ has_aar: bool
33
+ notes: str = ""
34
+
35
+ @property
36
+ def year_end_label(self) -> str:
37
+ return str(self.year_end) if self.year_end else "present"
38
+
39
+
40
+ @dataclass
41
+ class BundledQuery:
42
+ filename: str
43
+ dataset_id: str
44
+ description: str
45
+ topic: str
46
+ tags: list[str]
47
+ groupings: list[str]
48
+ year_range: str
49
+
50
+ @property
51
+ def stem(self) -> str:
52
+ return self.filename.removesuffix("-req.xml")
53
+
54
+
55
+ class Catalog:
56
+ def __init__(self) -> None:
57
+ raw = json.loads((_DATA_DIR / "catalog.json").read_text())
58
+ self._datasets: dict[str, Dataset] = {}
59
+ for d in raw["datasets"]:
60
+ measures = [Measure(**m) for m in d.get("measures", [])]
61
+ ds = Dataset(
62
+ id=d["id"],
63
+ title=d["title"],
64
+ topic=d["topic"],
65
+ subject=d["subject"],
66
+ year_start=d["year_start"],
67
+ year_end=d.get("year_end"),
68
+ year_range_label=d["year_range_label"],
69
+ tags=d.get("tags", []),
70
+ measures=measures,
71
+ key_groupings=d.get("key_groupings", []),
72
+ has_template=d.get("has_template", False),
73
+ has_aar=d.get("has_aar", False),
74
+ notes=d.get("notes", ""),
75
+ )
76
+ self._datasets[ds.id] = ds
77
+
78
+ raw_q = json.loads((_DATA_DIR / "queries_index.json").read_text())
79
+ self._queries: list[BundledQuery] = [
80
+ BundledQuery(**q) for q in raw_q["queries"]
81
+ ]
82
+
83
+ def datasets(self) -> list[Dataset]:
84
+ return list(self._datasets.values())
85
+
86
+ def dataset(self, dataset_id: str) -> Optional[Dataset]:
87
+ return self._datasets.get(dataset_id.upper())
88
+
89
+ def queries(self) -> list[BundledQuery]:
90
+ return self._queries
91
+
92
+ def queries_for_dataset(self, dataset_id: str) -> list[BundledQuery]:
93
+ return [q for q in self._queries if q.dataset_id == dataset_id.upper()]
94
+
95
+ def topics(self) -> list[str]:
96
+ seen: set[str] = set()
97
+ result: list[str] = []
98
+ for ds in self._datasets.values():
99
+ if ds.topic not in seen:
100
+ seen.add(ds.topic)
101
+ result.append(ds.topic)
102
+ return result