geniekit 0.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.
geniekit/__init__.py ADDED
@@ -0,0 +1,30 @@
1
+ """geniekit: tools for the AACR Project GENIE BPC clinicogenomic cohorts.
2
+
3
+ Three capabilities, one package:
4
+
5
+ * ``geniekit.harmonize``: normalise the six public BPC cohorts (NSCLC, CRC,
6
+ BrCa, PANC, Prostate, BLADDER) to one schema for cross-cohort analysis.
7
+ * ``geniekit.lot``: derive lines of therapy from the regimen data relative to a
8
+ user-chosen index event.
9
+ * ``geniekit.aggregate``: an aggregate-only analytic layer with disclosure
10
+ control for users who may not see patient-level records.
11
+
12
+ Supporting modules: ``geniekit.releases`` (registry of public releases and
13
+ Synapse ids), ``geniekit.dictionary`` (compiled variable synopses),
14
+ ``geniekit.io`` (download and load), ``geniekit.synthetic`` (synthetic cohorts
15
+ for tests and demos).
16
+
17
+ The package ships metadata only. Patient-level GENIE data must be obtained
18
+ from Synapse under the GENIE access requirement.
19
+ """
20
+
21
+ from ._version import __version__
22
+ from .releases import COHORTS, get_release, list_releases, normalize_cohort
23
+
24
+ __all__ = [
25
+ "COHORTS",
26
+ "__version__",
27
+ "get_release",
28
+ "list_releases",
29
+ "normalize_cohort",
30
+ ]
geniekit/_version.py ADDED
@@ -0,0 +1,8 @@
1
+ """Single source of truth for the package version.
2
+
3
+ Keep in sync with ``pyproject.toml``. Bump according to semantic versioning:
4
+ MAJOR for breaking API changes, MINOR for backward-compatible features, PATCH
5
+ for backward-compatible fixes.
6
+ """
7
+
8
+ __version__ = "0.0.1"
geniekit/cli.py ADDED
@@ -0,0 +1,200 @@
1
+ """Command line interface: ``geniekit <command> [options]``.
2
+
3
+ Commands: ``releases``, ``dictionary``, ``access``, ``download``, ``inspect``.
4
+ ``harmonize``, ``lot`` and ``aggregate`` are added with their modules.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import argparse
10
+ import sys
11
+ from collections.abc import Sequence
12
+
13
+ import pandas as pd
14
+
15
+ from . import dictionary, io, releases
16
+ from ._version import __version__
17
+
18
+
19
+ def _print_frame(frame: pd.DataFrame, max_rows: int | None = None) -> None:
20
+ with pd.option_context("display.max_rows", max_rows, "display.max_columns", None, "display.width", 200):
21
+ print(frame.to_string(index=False) if not frame.empty else "(no rows)")
22
+
23
+
24
+ def cmd_releases(args: argparse.Namespace) -> int:
25
+ rels = releases.list_releases(args.cohort)
26
+ rows = [
27
+ {
28
+ "cohort": r.cohort,
29
+ "version": r.version,
30
+ "patients": r.n_patients,
31
+ "institutions": "/".join(r.institutions),
32
+ "schema_gen": r.schema_generation,
33
+ "release_folder": r.release_folder,
34
+ "clinical_files": len(r.clinical),
35
+ "genomic_files": len(r.genomic),
36
+ }
37
+ for r in rels
38
+ ]
39
+ _print_frame(pd.DataFrame(rows))
40
+ if args.files:
41
+ frame = releases.to_frame()
42
+ if args.cohort:
43
+ frame = frame[frame["cohort"] == releases.normalize_cohort(args.cohort)]
44
+ print()
45
+ _print_frame(frame[frame["group"].isin(["clinical", "genomic", "documentation"])])
46
+ print(f"\nregistry generated on {releases.registry_generated_on()}")
47
+ return 0
48
+
49
+
50
+ def cmd_dictionary(args: argparse.Namespace) -> int:
51
+ dd = dictionary.load()
52
+ if args.dict_command == "lookup":
53
+ rows = dd.lookup(args.variable, args.table)
54
+ if rows.empty:
55
+ print(f"{args.variable!r} is not declared in any cohort", file=sys.stderr)
56
+ return 1
57
+ out = rows[["cohort", "table", "dtype", "n_values", "label"]]
58
+ _print_frame(out)
59
+ if args.values:
60
+ for c, vals in zip(rows["cohort"], rows["values"], strict=True):
61
+ print(f"\n{c}:")
62
+ for v in vals:
63
+ print(f" - {v}")
64
+ return 0
65
+ if args.dict_command == "diff":
66
+ kinds = args.kind or None
67
+ diff = dd.differences(args.table, kinds)
68
+ _print_frame(diff, max_rows=None)
69
+ print(f"\n{len(diff)} rows")
70
+ return 0
71
+ if args.dict_command == "presence":
72
+ mat = dd.presence(args.table)
73
+ if args.only_partial:
74
+ mat = mat[~mat.all(axis=1)]
75
+ with pd.option_context("display.max_rows", None, "display.width", 200):
76
+ print(mat.replace({True: "x", False: "."}).to_string())
77
+ return 0
78
+ return 2
79
+
80
+
81
+ def cmd_access(args: argparse.Namespace) -> int:
82
+ try:
83
+ session = io.SynapseSession(args.token)
84
+ who = session.whoami()
85
+ status = session.access_status()
86
+ except io.SynapseError as exc:
87
+ print(f"error: {exc}", file=sys.stderr)
88
+ return 1
89
+ print(f"Synapse user: {who.get('userName')} (owner id {who.get('ownerId')})")
90
+ print(status.describe())
91
+ return 0 if status.approved else 2
92
+
93
+
94
+ def cmd_download(args: argparse.Namespace) -> int:
95
+ try:
96
+ session = io.SynapseSession(args.token)
97
+ folder = session.download_release(
98
+ args.cohort,
99
+ version=args.version,
100
+ dest=args.dest,
101
+ groups=args.groups,
102
+ names=args.tables or None,
103
+ overwrite=args.overwrite,
104
+ progress=print,
105
+ )
106
+ except (io.SynapseError, KeyError, ValueError) as exc:
107
+ print(f"error: {exc}", file=sys.stderr)
108
+ return 1
109
+ print(f"release folder: {folder}")
110
+ return 0
111
+
112
+
113
+ def cmd_inspect(args: argparse.Namespace) -> int:
114
+ try:
115
+ data = io.load_release(
116
+ args.path, cohort=args.cohort, version=args.version, genomic=not args.no_genomic
117
+ )
118
+ except (FileNotFoundError, ValueError) as exc:
119
+ print(f"error: {exc}", file=sys.stderr)
120
+ return 1
121
+ print(data)
122
+ _print_frame(data.summary())
123
+ report = data.validation.get("columns") or {}
124
+ if report:
125
+ print("\ncolumn differences versus the packaged dictionary:")
126
+ for table, r in report.items():
127
+ print(f" {table}: missing {len(r['missing'])}, unexpected {len(r['extra'])}")
128
+ if r["extra"]:
129
+ print(" unexpected: " + ", ".join(r["extra"][:15]))
130
+ return 0
131
+
132
+
133
+ def build_parser() -> argparse.ArgumentParser:
134
+ p = argparse.ArgumentParser(prog="geniekit", description=__doc__.splitlines()[0])
135
+ p.add_argument("--version", action="version", version=f"geniekit {__version__}")
136
+ sub = p.add_subparsers(dest="command", required=True)
137
+
138
+ pr = sub.add_parser("releases", help="list the known public BPC releases")
139
+ pr.add_argument("--cohort", help="restrict to one cohort")
140
+ pr.add_argument(
141
+ "--files", action="store_true", help="also list clinical, genomic and documentation files"
142
+ )
143
+ pr.set_defaults(func=cmd_releases)
144
+
145
+ pdict = sub.add_parser("dictionary", help="query the compiled variable synopses")
146
+ dsub = pdict.add_subparsers(dest="dict_command", required=True)
147
+ lk = dsub.add_parser("lookup", help="show how a variable is declared in each cohort")
148
+ lk.add_argument("variable")
149
+ lk.add_argument("--table", choices=dictionary.TABLES)
150
+ lk.add_argument("--values", action="store_true", help="print permitted values per cohort")
151
+ df = dsub.add_parser("diff", help="list variables not declared identically across cohorts")
152
+ df.add_argument("--table", choices=dictionary.TABLES)
153
+ df.add_argument(
154
+ "--kind",
155
+ action="append",
156
+ choices=["missing_in_some", "dtype", "value_set", "value_text", "label"],
157
+ help="restrict to one or more kinds of difference (repeatable)",
158
+ )
159
+ pres = dsub.add_parser("presence", help="presence matrix of variables by cohort")
160
+ pres.add_argument("--table", choices=dictionary.TABLES)
161
+ pres.add_argument("--only-partial", action="store_true", help="hide variables present in every cohort")
162
+ pdict.set_defaults(func=cmd_dictionary)
163
+
164
+ pa = sub.add_parser("access", help="check the Synapse token and GENIE access status")
165
+ pa.add_argument("--token", help="Synapse personal access token (default: SYNAPSE_AUTH_TOKEN)")
166
+ pa.set_defaults(func=cmd_access)
167
+
168
+ pdl = sub.add_parser("download", help="download a public BPC release from Synapse")
169
+ pdl.add_argument("cohort")
170
+ pdl.add_argument("--version", help="release version, e.g. v2.0-public (default: latest public)")
171
+ pdl.add_argument("--dest", help="destination directory (default: $GENIEKIT_DATA_DIR or ./data/genie_bpc)")
172
+ pdl.add_argument(
173
+ "--groups",
174
+ nargs="+",
175
+ default=["clinical", "genomic"],
176
+ choices=list(releases.FILE_GROUPS),
177
+ help="file groups to download",
178
+ )
179
+ pdl.add_argument("--tables", nargs="+", help="restrict to these logical table names")
180
+ pdl.add_argument("--overwrite", action="store_true", help="re-download files that already exist")
181
+ pdl.add_argument("--token", help="Synapse personal access token (default: SYNAPSE_AUTH_TOKEN)")
182
+ pdl.set_defaults(func=cmd_download)
183
+
184
+ pi = sub.add_parser("inspect", help="load a release folder and summarise its tables")
185
+ pi.add_argument("path")
186
+ pi.add_argument("--cohort")
187
+ pi.add_argument("--version")
188
+ pi.add_argument("--no-genomic", action="store_true", help="skip genomic files")
189
+ pi.set_defaults(func=cmd_inspect)
190
+ return p
191
+
192
+
193
+ def main(argv: Sequence[str] | None = None) -> int:
194
+ parser = build_parser()
195
+ args = parser.parse_args(argv)
196
+ return int(args.func(args))
197
+
198
+
199
+ if __name__ == "__main__": # pragma: no cover
200
+ sys.exit(main())
geniekit/dictionary.py ADDED
@@ -0,0 +1,317 @@
1
+ """Machine-readable data dictionary for the six public GENIE BPC cohorts.
2
+
3
+ AACR publishes a Variable Synopsis workbook with every public BPC release. The
4
+ six workbooks are compiled by ``data-raw/build_dictionary.py`` into one long
5
+ table shipped as ``resources/dictionary.csv.gz``, with one row per
6
+ (cohort, table, variable). This module exposes that table and the
7
+ cross-cohort comparisons that motivate the harmonisation rules:
8
+
9
+ * which variables exist in which cohorts (``presence``),
10
+ * variables whose declared type differs across cohorts,
11
+ * variables whose permitted value sets differ across cohorts.
12
+
13
+ The dictionary contains no patient-level data.
14
+
15
+ Example
16
+ -------
17
+ >>> from geniekit import dictionary
18
+ >>> dd = dictionary.load()
19
+ >>> dd.compare("ca_cigarette", table="cancer").present_in
20
+ ('BrCa', 'PANC', 'Prostate', 'BLADDER')
21
+ >>> dd.differences(table="patient").kind.value_counts() # doctest: +SKIP
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import json
27
+ import re
28
+ from collections.abc import Iterable
29
+ from dataclasses import dataclass
30
+ from functools import lru_cache
31
+ from importlib import resources as importlib_resources
32
+
33
+ import pandas as pd
34
+
35
+ from .releases import COHORTS, normalize_cohort
36
+
37
+ __all__ = [
38
+ "TABLES",
39
+ "DataDictionary",
40
+ "VariableComparison",
41
+ "load",
42
+ "normalize_level",
43
+ ]
44
+
45
+ #: Logical table names in the order they appear in the synopses.
46
+ TABLES: tuple[str, ...] = (
47
+ "patient",
48
+ "cancer",
49
+ "regimen",
50
+ "imaging",
51
+ "pathology",
52
+ "med_onc",
53
+ "tumor_marker",
54
+ "radiation",
55
+ "cpt",
56
+ )
57
+
58
+ # hyphen, non-breaking hyphen, figure dash, en dash, em dash, minus sign
59
+ _DASH_CHARS = "".join(chr(c) for c in (0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2212))
60
+ _DASHES = re.compile("[" + re.escape(_DASH_CHARS) + "]")
61
+ _WS = re.compile(r"\s+")
62
+
63
+
64
+ def normalize_level(level: str) -> str:
65
+ """Cosmetic normalisation of a permitted value for set comparison.
66
+
67
+ Lower-cases, collapses whitespace, unifies dash characters and strips
68
+ trailing punctuation so that ``"Mixed Gliomas"`` and ``"Mixed gliomas"``
69
+ compare equal while genuinely different levels do not.
70
+ """
71
+ s = _DASHES.sub("-", str(level))
72
+ s = _WS.sub(" ", s).strip().lower()
73
+ s = s.replace(" - ", "-").replace("- ", "-").replace(" -", "-")
74
+ return s.rstrip(".;, ")
75
+
76
+
77
+ @dataclass(frozen=True)
78
+ class VariableComparison:
79
+ """How one variable is declared across the cohorts."""
80
+
81
+ table: str
82
+ variable: str
83
+ present_in: tuple[str, ...]
84
+ missing_in: tuple[str, ...]
85
+ labels: dict[str, str]
86
+ dtypes: dict[str, str]
87
+ values: dict[str, list[str]]
88
+
89
+ @property
90
+ def is_universal(self) -> bool:
91
+ return not self.missing_in
92
+
93
+ @property
94
+ def dtype_conflict(self) -> bool:
95
+ return len(set(self.dtypes.values())) > 1
96
+
97
+ @property
98
+ def label_conflict(self) -> bool:
99
+ return len({normalize_level(v) for v in self.labels.values()}) > 1
100
+
101
+ @property
102
+ def value_set_conflict(self) -> bool:
103
+ """True when the permitted value sets differ after cosmetic normalisation."""
104
+ sets = {frozenset(normalize_level(v) for v in vals) for vals in self.values.values() if vals}
105
+ return len(sets) > 1
106
+
107
+ @property
108
+ def value_text_conflict(self) -> bool:
109
+ """True when value sets are equal after normalisation but differ as raw text."""
110
+ if self.value_set_conflict:
111
+ return False
112
+ raw = {tuple(sorted(vals)) for vals in self.values.values() if vals}
113
+ return len(raw) > 1
114
+
115
+ @property
116
+ def union_values(self) -> list[str]:
117
+ seen: dict[str, str] = {}
118
+ for vals in self.values.values():
119
+ for v in vals:
120
+ seen.setdefault(normalize_level(v), v)
121
+ return list(seen.values())
122
+
123
+ def summary(self) -> str:
124
+ parts = [f"{self.table}.{self.variable}: present in {', '.join(self.present_in) or 'none'}"]
125
+ if self.missing_in:
126
+ parts.append(f"missing in {', '.join(self.missing_in)}")
127
+ if self.dtype_conflict:
128
+ parts.append("dtype conflict " + ", ".join(f"{c}={t}" for c, t in self.dtypes.items()))
129
+ if self.value_set_conflict:
130
+ parts.append("value sets differ")
131
+ elif self.value_text_conflict:
132
+ parts.append("value text differs (cosmetic)")
133
+ return "; ".join(parts)
134
+
135
+
136
+ class DataDictionary:
137
+ """The compiled dictionary with cross-cohort comparison helpers."""
138
+
139
+ def __init__(self, frame: pd.DataFrame) -> None:
140
+ required = {"cohort", "version", "schema_generation", "table", "variable", "label", "dtype", "values"}
141
+ missing = required - set(frame.columns)
142
+ if missing:
143
+ raise ValueError(f"dictionary frame lacks columns: {sorted(missing)}")
144
+ frame = frame.copy()
145
+ if len(frame) and not isinstance(frame["values"].iloc[0], list):
146
+ frame["values"] = [json.loads(v) if isinstance(v, str) and v else [] for v in frame["values"]]
147
+ self._frame = frame.reset_index(drop=True)
148
+ present = [c for c in COHORTS if c in set(self._frame["cohort"])]
149
+ self.cohorts: tuple[str, ...] = tuple(present)
150
+
151
+ # -- basic access --------------------------------------------------------
152
+ @property
153
+ def frame(self) -> pd.DataFrame:
154
+ """The full long table (one row per cohort, table, variable)."""
155
+ return self._frame
156
+
157
+ def tables(self) -> list[str]:
158
+ return [t for t in TABLES if t in set(self._frame["table"])]
159
+
160
+ def schema_generation(self, cohort: str) -> int:
161
+ c = normalize_cohort(cohort)
162
+ gens = self._frame.loc[self._frame["cohort"] == c, "schema_generation"].unique()
163
+ if len(gens) != 1:
164
+ raise KeyError(f"cohort {c!r} not in dictionary")
165
+ return int(gens[0])
166
+
167
+ def variables(self, cohort: str | None = None, table: str | None = None) -> pd.DataFrame:
168
+ """Rows filtered by cohort and/or table."""
169
+ f = self._frame
170
+ if cohort is not None:
171
+ f = f[f["cohort"] == normalize_cohort(cohort)]
172
+ if table is not None:
173
+ self._check_table(table)
174
+ f = f[f["table"] == table]
175
+ return f.reset_index(drop=True)
176
+
177
+ def lookup(self, variable: str, table: str | None = None) -> pd.DataFrame:
178
+ """All declarations of ``variable`` (across cohorts and, if unspecified, tables)."""
179
+ f = self._frame[self._frame["variable"] == variable]
180
+ if table is not None:
181
+ self._check_table(table)
182
+ f = f[f["table"] == table]
183
+ return f.reset_index(drop=True)
184
+
185
+ def values(self, variable: str, table: str) -> dict[str, list[str]]:
186
+ """Permitted values per cohort for one variable."""
187
+ rows = self.lookup(variable, table)
188
+ return {c: list(v) for c, v in zip(rows["cohort"], rows["values"], strict=True)}
189
+
190
+ # -- comparisons ---------------------------------------------------------
191
+ def presence(self, table: str | None = None, cohorts: Iterable[str] | None = None) -> pd.DataFrame:
192
+ """Boolean matrix: rows (table, variable), columns cohorts."""
193
+ f = self.variables(table=table)
194
+ cols = tuple(normalize_cohort(c) for c in cohorts) if cohorts else self.cohorts
195
+ f = f[f["cohort"].isin(cols)]
196
+ mat = f.assign(flag=True).pivot_table(
197
+ index=["table", "variable"], columns="cohort", values="flag", aggfunc="any", fill_value=False
198
+ )
199
+ mat = mat.reindex(columns=list(cols), fill_value=False).astype(bool)
200
+ mat.columns.name = None
201
+ # keep synopsis order of first appearance
202
+ order = f.drop_duplicates(["table", "variable"])[["table", "variable"]]
203
+ return mat.reindex(pd.MultiIndex.from_frame(order))
204
+
205
+ def common_variables(self, table: str, cohorts: Iterable[str] | None = None) -> list[str]:
206
+ """Variables present in every requested cohort for ``table``."""
207
+ mat = self.presence(table, cohorts)
208
+ return [v for (_, v), row in mat.iterrows() if bool(row.all())]
209
+
210
+ def compare(self, variable: str, table: str) -> VariableComparison:
211
+ rows = self.lookup(variable, table)
212
+ if rows.empty:
213
+ raise KeyError(f"{table}.{variable} is not declared in any cohort")
214
+ by = {c: r for c, r in zip(rows["cohort"], rows.to_dict("records"), strict=True)}
215
+ present = tuple(c for c in self.cohorts if c in by)
216
+ return VariableComparison(
217
+ table=table,
218
+ variable=variable,
219
+ present_in=present,
220
+ missing_in=tuple(c for c in self.cohorts if c not in by),
221
+ labels={c: str(by[c]["label"]) for c in present},
222
+ dtypes={c: str(by[c]["dtype"]) for c in present},
223
+ values={c: list(by[c]["values"]) for c in present},
224
+ )
225
+
226
+ def differences(self, table: str | None = None, kinds: Iterable[str] | None = None) -> pd.DataFrame:
227
+ """Every variable that is not declared identically in all cohorts.
228
+
229
+ Returns one row per (table, variable, kind) with ``kind`` in
230
+ ``{"missing_in_some", "dtype", "value_set", "value_text", "label"}``
231
+ and a human-readable ``detail`` column.
232
+ """
233
+ wanted = set(kinds) if kinds else {"missing_in_some", "dtype", "value_set", "value_text", "label"}
234
+ f = self.variables(table=table)
235
+ rows: list[dict] = []
236
+ for (tbl, var), _ in f.groupby(["table", "variable"], sort=False):
237
+ cmp = self.compare(var, tbl)
238
+ if "missing_in_some" in wanted and cmp.missing_in:
239
+ rows.append(
240
+ {
241
+ "table": tbl,
242
+ "variable": var,
243
+ "kind": "missing_in_some",
244
+ "present_in": ",".join(cmp.present_in),
245
+ "detail": f"missing in {', '.join(cmp.missing_in)}",
246
+ }
247
+ )
248
+ if "dtype" in wanted and cmp.dtype_conflict:
249
+ rows.append(
250
+ {
251
+ "table": tbl,
252
+ "variable": var,
253
+ "kind": "dtype",
254
+ "present_in": ",".join(cmp.present_in),
255
+ "detail": ", ".join(f"{c}={t}" for c, t in cmp.dtypes.items()),
256
+ }
257
+ )
258
+ if "value_set" in wanted and cmp.value_set_conflict:
259
+ union = {normalize_level(v) for vals in cmp.values.values() for v in vals}
260
+ lacks = {
261
+ c: sorted(union - {normalize_level(v) for v in vals})
262
+ for c, vals in cmp.values.items()
263
+ if vals
264
+ }
265
+ rows.append(
266
+ {
267
+ "table": tbl,
268
+ "variable": var,
269
+ "kind": "value_set",
270
+ "present_in": ",".join(cmp.present_in),
271
+ "detail": "; ".join(
272
+ f"{c} lacks {len(missing)}" for c, missing in lacks.items() if missing
273
+ ),
274
+ }
275
+ )
276
+ if "value_text" in wanted and cmp.value_text_conflict:
277
+ rows.append(
278
+ {
279
+ "table": tbl,
280
+ "variable": var,
281
+ "kind": "value_text",
282
+ "present_in": ",".join(cmp.present_in),
283
+ "detail": "same levels, different spelling/case",
284
+ }
285
+ )
286
+ if "label" in wanted and cmp.label_conflict:
287
+ rows.append(
288
+ {
289
+ "table": tbl,
290
+ "variable": var,
291
+ "kind": "label",
292
+ "present_in": ",".join(cmp.present_in),
293
+ "detail": " | ".join(sorted({v for v in cmp.labels.values()}))[:200],
294
+ }
295
+ )
296
+ return pd.DataFrame(rows, columns=["table", "variable", "kind", "present_in", "detail"])
297
+
298
+ # -- helpers -------------------------------------------------------------
299
+ def _check_table(self, table: str) -> None:
300
+ if table not in TABLES:
301
+ raise ValueError(f"Unknown table {table!r}; expected one of {', '.join(TABLES)}")
302
+
303
+ def __repr__(self) -> str:
304
+ n_vars = self._frame.drop_duplicates(["table", "variable"]).shape[0]
305
+ return f"DataDictionary({len(self._frame)} rows, {n_vars} variables, cohorts={list(self.cohorts)})"
306
+
307
+
308
+ @lru_cache(maxsize=1)
309
+ def load() -> DataDictionary:
310
+ """Load the packaged dictionary (cached)."""
311
+ path = importlib_resources.files("geniekit.resources").joinpath("dictionary.csv.gz")
312
+ with path.open("rb") as fh:
313
+ frame = pd.read_csv(fh, compression="gzip", dtype=str, keep_default_na=False)
314
+ frame["schema_generation"] = frame["schema_generation"].astype(int)
315
+ frame["n_values"] = frame["n_values"].astype(int)
316
+ frame["order"] = frame["order"].astype(int)
317
+ return DataDictionary(frame)
@@ -0,0 +1,36 @@
1
+ """Loading GENIE BPC releases: from Synapse (with a personal access token) or
2
+ from files already on disk. Both paths produce a :class:`CohortData`.
3
+
4
+ >>> from geniekit import io
5
+ >>> data = io.load_release("data/genie_bpc/CRC_v2.0-public") # doctest: +SKIP
6
+ >>> data["patient"].shape # doctest: +SKIP
7
+ """
8
+
9
+ from .cohort import CLINICAL_TABLES, GENOMIC_TABLES, CohortData
10
+ from .local import FILENAME_TO_TABLE, find_release_files, load_release, read_table
11
+ from .synapse import (
12
+ GENIE_ACCESS_REQUIREMENT,
13
+ AccessDeniedError,
14
+ AccessStatus,
15
+ SynapseError,
16
+ SynapseSession,
17
+ download_release,
18
+ resolve_token,
19
+ )
20
+
21
+ __all__ = [
22
+ "CLINICAL_TABLES",
23
+ "FILENAME_TO_TABLE",
24
+ "GENIE_ACCESS_REQUIREMENT",
25
+ "GENOMIC_TABLES",
26
+ "AccessDeniedError",
27
+ "AccessStatus",
28
+ "CohortData",
29
+ "SynapseError",
30
+ "SynapseSession",
31
+ "download_release",
32
+ "find_release_files",
33
+ "load_release",
34
+ "read_table",
35
+ "resolve_token",
36
+ ]