iints-sdk-python35 0.0.18__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 (118) hide show
  1. iints/__init__.py +183 -0
  2. iints/analysis/__init__.py +12 -0
  3. iints/analysis/algorithm_xray.py +387 -0
  4. iints/analysis/baseline.py +92 -0
  5. iints/analysis/clinical_benchmark.py +198 -0
  6. iints/analysis/clinical_metrics.py +551 -0
  7. iints/analysis/clinical_tir_analyzer.py +136 -0
  8. iints/analysis/diabetes_metrics.py +43 -0
  9. iints/analysis/edge_efficiency.py +33 -0
  10. iints/analysis/edge_performance_monitor.py +315 -0
  11. iints/analysis/explainability.py +94 -0
  12. iints/analysis/explainable_ai.py +232 -0
  13. iints/analysis/hardware_benchmark.py +221 -0
  14. iints/analysis/metrics.py +117 -0
  15. iints/analysis/population_report.py +188 -0
  16. iints/analysis/reporting.py +345 -0
  17. iints/analysis/safety_index.py +311 -0
  18. iints/analysis/sensor_filtering.py +54 -0
  19. iints/analysis/validator.py +273 -0
  20. iints/api/__init__.py +0 -0
  21. iints/api/base_algorithm.py +307 -0
  22. iints/api/registry.py +103 -0
  23. iints/api/template_algorithm.py +195 -0
  24. iints/assets/iints_logo.png +0 -0
  25. iints/cli/__init__.py +0 -0
  26. iints/cli/cli.py +2598 -0
  27. iints/core/__init__.py +1 -0
  28. iints/core/algorithms/__init__.py +0 -0
  29. iints/core/algorithms/battle_runner.py +138 -0
  30. iints/core/algorithms/correction_bolus.py +95 -0
  31. iints/core/algorithms/discovery.py +92 -0
  32. iints/core/algorithms/fixed_basal_bolus.py +58 -0
  33. iints/core/algorithms/hybrid_algorithm.py +92 -0
  34. iints/core/algorithms/lstm_algorithm.py +138 -0
  35. iints/core/algorithms/mock_algorithms.py +162 -0
  36. iints/core/algorithms/pid_controller.py +88 -0
  37. iints/core/algorithms/standard_pump_algo.py +64 -0
  38. iints/core/device.py +0 -0
  39. iints/core/device_manager.py +64 -0
  40. iints/core/devices/__init__.py +3 -0
  41. iints/core/devices/models.py +160 -0
  42. iints/core/patient/__init__.py +9 -0
  43. iints/core/patient/bergman_model.py +341 -0
  44. iints/core/patient/models.py +285 -0
  45. iints/core/patient/patient_factory.py +117 -0
  46. iints/core/patient/profile.py +41 -0
  47. iints/core/safety/__init__.py +12 -0
  48. iints/core/safety/config.py +37 -0
  49. iints/core/safety/input_validator.py +95 -0
  50. iints/core/safety/supervisor.py +39 -0
  51. iints/core/simulation/__init__.py +0 -0
  52. iints/core/simulation/scenario_parser.py +61 -0
  53. iints/core/simulator.py +874 -0
  54. iints/core/supervisor.py +367 -0
  55. iints/data/__init__.py +53 -0
  56. iints/data/adapter.py +142 -0
  57. iints/data/column_mapper.py +398 -0
  58. iints/data/datasets.json +132 -0
  59. iints/data/demo/__init__.py +1 -0
  60. iints/data/demo/demo_cgm.csv +289 -0
  61. iints/data/importer.py +275 -0
  62. iints/data/ingestor.py +162 -0
  63. iints/data/nightscout.py +128 -0
  64. iints/data/quality_checker.py +550 -0
  65. iints/data/registry.py +166 -0
  66. iints/data/tidepool.py +38 -0
  67. iints/data/universal_parser.py +813 -0
  68. iints/data/virtual_patients/clinic_safe_baseline.yaml +9 -0
  69. iints/data/virtual_patients/clinic_safe_hyper_challenge.yaml +9 -0
  70. iints/data/virtual_patients/clinic_safe_hypo_prone.yaml +9 -0
  71. iints/data/virtual_patients/clinic_safe_midnight.yaml +9 -0
  72. iints/data/virtual_patients/clinic_safe_pizza.yaml +9 -0
  73. iints/data/virtual_patients/clinic_safe_stress_meal.yaml +9 -0
  74. iints/data/virtual_patients/default_patient.yaml +11 -0
  75. iints/data/virtual_patients/patient_559_config.yaml +11 -0
  76. iints/emulation/__init__.py +80 -0
  77. iints/emulation/legacy_base.py +414 -0
  78. iints/emulation/medtronic_780g.py +337 -0
  79. iints/emulation/omnipod_5.py +367 -0
  80. iints/emulation/tandem_controliq.py +393 -0
  81. iints/highlevel.py +451 -0
  82. iints/learning/__init__.py +3 -0
  83. iints/learning/autonomous_optimizer.py +194 -0
  84. iints/learning/learning_system.py +122 -0
  85. iints/metrics.py +34 -0
  86. iints/population/__init__.py +11 -0
  87. iints/population/generator.py +131 -0
  88. iints/population/runner.py +327 -0
  89. iints/presets/__init__.py +28 -0
  90. iints/presets/presets.json +114 -0
  91. iints/research/__init__.py +30 -0
  92. iints/research/config.py +68 -0
  93. iints/research/dataset.py +319 -0
  94. iints/research/losses.py +73 -0
  95. iints/research/predictor.py +329 -0
  96. iints/scenarios/__init__.py +3 -0
  97. iints/scenarios/generator.py +92 -0
  98. iints/templates/__init__.py +0 -0
  99. iints/templates/default_algorithm.py +91 -0
  100. iints/templates/scenarios/__init__.py +0 -0
  101. iints/templates/scenarios/chaos_insulin_stacking.json +29 -0
  102. iints/templates/scenarios/chaos_runaway_ai.json +25 -0
  103. iints/templates/scenarios/example_scenario.json +35 -0
  104. iints/templates/scenarios/exercise_stress.json +30 -0
  105. iints/utils/__init__.py +3 -0
  106. iints/utils/plotting.py +50 -0
  107. iints/utils/run_io.py +152 -0
  108. iints/validation/__init__.py +133 -0
  109. iints/validation/schemas.py +94 -0
  110. iints/visualization/__init__.py +34 -0
  111. iints/visualization/cockpit.py +691 -0
  112. iints/visualization/uncertainty_cloud.py +612 -0
  113. iints_sdk_python35-0.0.18.dist-info/METADATA +225 -0
  114. iints_sdk_python35-0.0.18.dist-info/RECORD +118 -0
  115. iints_sdk_python35-0.0.18.dist-info/WHEEL +5 -0
  116. iints_sdk_python35-0.0.18.dist-info/entry_points.txt +10 -0
  117. iints_sdk_python35-0.0.18.dist-info/licenses/LICENSE +28 -0
  118. iints_sdk_python35-0.0.18.dist-info/top_level.txt +1 -0
iints/data/registry.py ADDED
@@ -0,0 +1,166 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import urllib.request
5
+ import zipfile
6
+ import hashlib
7
+ import shutil
8
+ from pathlib import Path
9
+ from typing import Any, Dict, List, Optional, IO, cast
10
+
11
+ try: # Python 3.9+
12
+ from importlib.resources import files
13
+ except Exception: # pragma: no cover
14
+ files = None # type: ignore
15
+ from importlib import resources
16
+ else:
17
+ from importlib import resources
18
+
19
+
20
+ class DatasetRegistryError(RuntimeError):
21
+ pass
22
+
23
+
24
+ class DatasetFetchError(RuntimeError):
25
+ pass
26
+
27
+
28
+ def _read_registry_text() -> str:
29
+ try:
30
+ if files is not None:
31
+ return files("iints.data").joinpath("datasets.json").read_text() # type: ignore[call-arg]
32
+ return resources.read_text("iints.data", "datasets.json")
33
+ except Exception as exc:
34
+ raise DatasetRegistryError(f"Unable to locate datasets.json: {exc}") from exc
35
+
36
+
37
+ def load_dataset_registry() -> List[Dict[str, Any]]:
38
+ return json.loads(_read_registry_text())
39
+
40
+
41
+ def get_dataset(dataset_id: str) -> Dict[str, Any]:
42
+ for entry in load_dataset_registry():
43
+ if entry.get("id") == dataset_id:
44
+ return entry
45
+ raise DatasetRegistryError(f"Unknown dataset '{dataset_id}'. Run 'iints data list' to see options.")
46
+
47
+
48
+ def list_dataset_ids() -> List[str]:
49
+ ids: List[str] = []
50
+ for entry in load_dataset_registry():
51
+ dataset_id = entry.get("id")
52
+ if isinstance(dataset_id, str) and dataset_id:
53
+ ids.append(dataset_id)
54
+ return ids
55
+
56
+
57
+ def _download_file(url: str, output_path: Path) -> Path:
58
+ output_path.parent.mkdir(parents=True, exist_ok=True)
59
+ try:
60
+ urllib.request.urlretrieve(url, output_path)
61
+ except Exception as exc:
62
+ raise DatasetFetchError(f"Failed to download {url}: {exc}") from exc
63
+ return output_path
64
+
65
+
66
+ def _sha256(path: Path) -> str:
67
+ digest = hashlib.sha256()
68
+ with path.open("rb") as handle:
69
+ for chunk in iter(lambda: handle.read(8192), b""):
70
+ digest.update(chunk)
71
+ return digest.hexdigest()
72
+
73
+
74
+ def _append_checksum(output_dir: Path, filename: str, digest: str) -> None:
75
+ checksum_path = output_dir / "SHA256SUMS.txt"
76
+ with checksum_path.open("a") as handle:
77
+ handle.write(f"{digest} {filename}\n")
78
+
79
+
80
+ def _get_expected_hash(dataset: Dict[str, Any], index: int = 0) -> Optional[str]:
81
+ expected = dataset.get("sha256")
82
+ if isinstance(expected, list):
83
+ if index < len(expected):
84
+ return expected[index] or None
85
+ return None
86
+ if isinstance(expected, str):
87
+ return expected or None
88
+ return None
89
+
90
+
91
+ def _maybe_extract_zip(path: Path, output_dir: Path) -> None:
92
+ if path.suffix.lower() != ".zip":
93
+ return
94
+ try:
95
+ with zipfile.ZipFile(path, "r") as zip_ref:
96
+ zip_ref.extractall(output_dir)
97
+ except Exception as exc:
98
+ raise DatasetFetchError(f"Failed to extract {path.name}: {exc}") from exc
99
+
100
+
101
+ def _open_bundled_binary(bundled_path: str) -> IO[bytes]:
102
+ if files is not None:
103
+ return cast(IO[bytes], files("iints.data").joinpath(bundled_path).open("rb")) # type: ignore[call-arg]
104
+ parts = bundled_path.split("/")
105
+ if len(parts) > 1:
106
+ package = ".".join(["iints", "data", *parts[:-1]])
107
+ resource = parts[-1]
108
+ return cast(IO[bytes], resources.open_binary(package, resource))
109
+ return cast(IO[bytes], resources.open_binary("iints.data", bundled_path))
110
+
111
+
112
+ def fetch_dataset(
113
+ dataset_id: str,
114
+ output_dir: Path,
115
+ extract: bool = True,
116
+ verify: bool = True,
117
+ ) -> List[Path]:
118
+ dataset = get_dataset(dataset_id)
119
+ urls = dataset.get("download_urls") or []
120
+ access = dataset.get("access", "manual")
121
+
122
+ if access == "bundled":
123
+ bundled_path = dataset.get("bundled_path")
124
+ if not bundled_path:
125
+ raise DatasetFetchError("Bundled dataset missing bundled_path entry.")
126
+ output_dir.mkdir(parents=True, exist_ok=True)
127
+ target = output_dir / Path(bundled_path).name
128
+ # Traversable may not be a real filesystem path; stream bytes instead.
129
+ try:
130
+ with _open_bundled_binary(bundled_path) as src, target.open("wb") as dst:
131
+ shutil.copyfileobj(src, dst)
132
+ except Exception as exc:
133
+ raise DatasetFetchError(f"Unable to locate bundled dataset: {exc}") from exc
134
+ expected = _get_expected_hash(dataset, 0)
135
+ if verify and expected:
136
+ actual = _sha256(target)
137
+ if actual != expected:
138
+ raise DatasetFetchError(f"SHA-256 mismatch for {target.name}. Expected {expected}, got {actual}.")
139
+ _append_checksum(output_dir, target.name, actual)
140
+ elif verify and expected is None:
141
+ actual = _sha256(target)
142
+ _append_checksum(output_dir, target.name, actual)
143
+ return [target]
144
+
145
+ if not urls:
146
+ raise DatasetFetchError(
147
+ "This dataset requires manual download or approval. Use 'iints data info' for instructions."
148
+ )
149
+ output_dir.mkdir(parents=True, exist_ok=True)
150
+ downloaded: List[Path] = []
151
+ for idx, url in enumerate(urls):
152
+ filename = url.split("/")[-1]
153
+ target = output_dir / filename
154
+ downloaded.append(_download_file(url, target))
155
+ expected = _get_expected_hash(dataset, idx)
156
+ if verify and expected:
157
+ actual = _sha256(target)
158
+ if actual != expected:
159
+ raise DatasetFetchError(f"SHA-256 mismatch for {target.name}. Expected {expected}, got {actual}.")
160
+ _append_checksum(output_dir, target.name, actual)
161
+ elif verify and expected is None:
162
+ actual = _sha256(target)
163
+ _append_checksum(output_dir, target.name, actual)
164
+ if extract:
165
+ _maybe_extract_zip(target, output_dir)
166
+ return downloaded
iints/data/tidepool.py ADDED
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any, Dict, Optional
5
+ import json
6
+ import urllib.request
7
+
8
+
9
+ @dataclass
10
+ class TidepoolClient:
11
+ """
12
+ Lightweight client skeleton based on the Tidepool OpenAPI spec.
13
+ Authentication and full endpoint coverage are intentionally left open
14
+ so teams can wire in their preferred auth flow.
15
+ """
16
+ base_url: str = "https://api.tidepool.org"
17
+ token: Optional[str] = None
18
+
19
+ def _headers(self) -> Dict[str, str]:
20
+ headers = {"Accept": "application/json"}
21
+ if self.token:
22
+ headers["Authorization"] = f"Bearer {self.token}"
23
+ return headers
24
+
25
+ def get_json(self, path: str) -> Dict[str, Any]:
26
+ if not self.token:
27
+ raise RuntimeError("TidepoolClient requires an auth token. Provide one before calling.")
28
+ url = self.base_url.rstrip("/") + "/" + path.lstrip("/")
29
+ req = urllib.request.Request(url, headers=self._headers(), method="GET")
30
+ with urllib.request.urlopen(req) as response: # nosec - thin skeleton
31
+ payload = response.read().decode("utf-8")
32
+ return json.loads(payload)
33
+
34
+
35
+ def load_openapi_spec(path: str) -> Dict[str, Any]:
36
+ """Load a local Tidepool OpenAPI JSON spec for reference tooling."""
37
+ with open(path, "r", encoding="utf-8") as handle:
38
+ return json.load(handle)