Skip to content

Commit 27864ad

Browse files
authored
Merge pull request #109 from CDCgov/dmb/catalog-generated-type-stubs
Generate precise catalog type stubs
2 parents d9239db + 8fc56d4 commit 27864ad

12 files changed

Lines changed: 841 additions & 33 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ This project provides data tools and low friction access to versioned datasets w
3333
df = datacat.{{dataset}}.load.get_dataframe()
3434
df.glimpse()
3535
```
36+
6. Generate project-local type stubs for the installed catalog:
37+
```bash
38+
dataops_catalog_stubs
39+
```
40+
This writes stubs under `typings/`, which Pyright/Pylance uses by default.
41+
For mypy, include that directory with `MYPYPATH=typings`.
3642

3743
Read the [Dataset User Guide](docs/data_user_guide.md) for more information about accessing datasets.
3844

cfa/dataops/catalog.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from io import BytesIO
1010
from pathlib import PurePosixPath
1111
from types import SimpleNamespace
12-
from typing import TYPE_CHECKING, Any, Literal, overload
12+
from typing import Any, Literal, overload
1313

1414
import pandas as pd
1515
import polars as pl
@@ -85,38 +85,14 @@ def get_all_catalogs() -> list:
8585

8686

8787
class CatalogNamespace(SimpleNamespace):
88-
"""Recursive namespace wrapper for statically-typed catalog access.
89-
90-
Runtime instances still behave like ``SimpleNamespace`` objects, but the
91-
declared attributes let editors resolve endpoint methods on dynamic access
92-
chains such as ``datacat.public.team.dataset.load``.
93-
"""
94-
95-
if TYPE_CHECKING:
96-
load: "BlobEndpoint"
97-
extract: "BlobEndpoint"
98-
data: "BlobEndpoint"
99-
_ledger_endpoint: "BlobEndpoint"
100-
config: dict[str, Any]
101-
__namespace_list__: list[str]
102-
103-
def __getattr__(self, name: str) -> "CatalogNamespace":
104-
raise AttributeError(
105-
f"{type(self).__name__!s} object has no attribute {name!r}"
106-
)
88+
"""Runtime namespace wrapper for catalog access."""
10789

10890

10991
class DatasetEndpoint:
11092
"""The DatasetEndpoint class for including in the datacat namespace.
11193
This ends the namespace branching at a config file and creates all the
11294
blob endpoints for each 'stage' of the config (e.g., extract, load, stage_01)."""
11395

114-
if TYPE_CHECKING:
115-
config: dict[str, Any]
116-
load: "BlobEndpoint"
117-
extract: "BlobEndpoint"
118-
data: "BlobEndpoint"
119-
12096
def __init__(self, config_path: str, defaults: dict, ns: str):
12197
"""Basic functionality to interact with datasets to be included
12298
via the datasets configs.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Package resources for generated type stubs."""
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
from collections.abc import Sequence
2+
from types import SimpleNamespace
3+
from typing import Any, Literal, overload
4+
5+
import pandas as pd
6+
import polars as pl
7+
8+
from .reporting.catalog import NotebookEndpoint
9+
10+
11+
def get_all_catalogs() -> list[tuple[str, str, str]]: ...
12+
13+
14+
class CatalogNamespace(SimpleNamespace):
15+
pass
16+
17+
18+
class DatasetEndpoint:
19+
config_path: str
20+
defaults: dict[str, Any]
21+
config: dict[str, Any]
22+
__ns_str__: str
23+
_ledger_location: dict[str, Any]
24+
25+
26+
class BlobEndpoint:
27+
account: str
28+
container: str
29+
prefix: str
30+
ledger_location: dict[str, Any]
31+
is_ledger: bool
32+
__ns_str__: str
33+
def write_blob(
34+
self,
35+
file_buffer: bytes | Sequence[bytes],
36+
path_after_prefix: str,
37+
auto_version: bool = False,
38+
append: bool = False,
39+
) -> None: ...
40+
def read_blobs(
41+
self,
42+
version_spec: str | None = None,
43+
selection: Literal["newest", "oldest", "all"] = "newest",
44+
print_version: bool = True,
45+
) -> list[bytes]: ...
46+
def read_csv(self, suffix: str) -> pd.DataFrame: ...
47+
def get_versions(self) -> list[str]: ...
48+
def get_file_ext(
49+
self,
50+
version_spec: str | None = None,
51+
selection: Literal["newest", "oldest", "all"] = "newest",
52+
) -> str: ...
53+
def download_version_to_local(
54+
self,
55+
local_path: str,
56+
version_spec: str | None = None,
57+
force: bool = False,
58+
selection: Literal["newest", "oldest", "all"] = "newest",
59+
) -> bool: ...
60+
@overload
61+
def get_dataframe(
62+
self,
63+
output: Literal["pandas", "pd"] = "pandas",
64+
version_spec: str | None = None,
65+
selection: Literal["newest", "oldest"] = "newest",
66+
) -> pd.DataFrame: ...
67+
@overload
68+
def get_dataframe(
69+
self,
70+
output: Literal["polars", "pl"],
71+
version_spec: str | None = None,
72+
selection: Literal["newest", "oldest"] = "newest",
73+
) -> pl.DataFrame: ...
74+
@overload
75+
def get_dataframe(
76+
self,
77+
output: Literal["pl_lazy", "lazy"],
78+
version_spec: str | None = None,
79+
selection: Literal["newest", "oldest"] = "newest",
80+
) -> pl.LazyFrame: ...
81+
def ledger_entry(self, action: str) -> None: ...
82+
def save_dataframe(
83+
self,
84+
df: pd.DataFrame | pl.DataFrame,
85+
path_after_prefix: str,
86+
file_format: str = "parquet",
87+
auto_version: bool = False,
88+
) -> None: ...
89+
def save_file_to_blob(
90+
self,
91+
file_path: str,
92+
path_after_prefix: str,
93+
auto_version: bool = False,
94+
) -> None: ...
95+
def save_dir_to_blob(
96+
self,
97+
dir_path: str,
98+
path_after_prefix: str,
99+
auto_version: bool = False,
100+
) -> None: ...
101+
102+
103+
def dict_to_sn(
104+
d: Any,
105+
defaults: dict[str, Any] | None = None,
106+
ns: str = "",
107+
) -> CatalogNamespace: ...
108+
109+
110+
% for cls in model.classes:
111+
class ${cls.name}(${cls.base}):
112+
% if cls.attributes:
113+
% for attr in cls.attributes:
114+
${attr.name}: ${attr.type_name}
115+
% endfor
116+
% else:
117+
pass
118+
% endif
119+
120+
121+
% endfor
122+
datacat: DataCatalog
123+
reportcat: ReportCatalog
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .catalog import datacat as datacat, reportcat as reportcat
2+
3+
__version__: str
4+
__all__: list[str]

0 commit comments

Comments
 (0)