Skip to content

Commit a4e2e7d

Browse files
Merge pull request #71 from CDCgov/copilot/update-ruff-config-and-pre-commit
Sync ruff config between ruff.toml and pre-commit; upgrade to v0.15.8
2 parents cfbf865 + 61fb799 commit a4e2e7d

24 files changed

Lines changed: 145 additions & 327 deletions

.pre-commit-config.yaml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,12 @@ repos:
1414
#####
1515
# Python
1616
- repo: https://github.com/astral-sh/ruff-pre-commit
17-
rev: v0.6.8
17+
rev: v0.15.8
1818
hooks:
1919
# Sort imports
20-
- id: ruff
21-
args: ['check', '--select', 'I', '--fix']
22-
# Run the linter
23-
- id: ruff
24-
args: ['--line-length', '79']
20+
- id: ruff-check
2521
# Run the formatter
2622
- id: ruff-format
27-
args: ['--line-length', '79']
2823
#####
2924
# R
3025
# - repo: https://github.com/lorenzwalthert/precommit

cfa/dataops/catalog.py

Lines changed: 23 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
import json
44
import os
55
import pkgutil
6+
from collections.abc import Sequence
67
from configparser import ConfigParser
78
from importlib import import_module
89
from io import BytesIO
910
from pathlib import PurePosixPath
1011
from types import SimpleNamespace
11-
from typing import Any, List, Literal, Sequence, overload
12+
from typing import Any, Literal, overload
1213

1314
import pandas as pd
1415
import polars as pl
1516
import tomli
1617
from azure.identity import ManagedIdentityCredential
17-
1818
from cfa.cloudops.blob_helpers import (
1919
read_blob_stream,
2020
walk_blobs_in_container,
@@ -53,9 +53,7 @@ def get_all_catalogs() -> list:
5353
catalog_nspace = _config.get("DEFAULT", "catalog_namespaces")
5454
try:
5555
catalog_pkg = import_module(catalog_nspace)
56-
for module_finder, modname, ispkg in pkgutil.iter_modules(
57-
catalog_pkg.__path__
58-
):
56+
for module_finder, modname, ispkg in pkgutil.iter_modules(catalog_pkg.__path__):
5957
if ispkg:
6058
catalogs.append((catalog_nspace, modname, module_finder.path))
6159
except ModuleNotFoundError:
@@ -76,9 +74,7 @@ def get_all_catalogs() -> list:
7674
report_mod = import_module(f"{cns}.{cat_name}.reports")
7775
all_dataset_ns_map.update(dataset_mod.dataset_ns_map)
7876
all_reports_ns_map.update(report_mod.report_ns_map)
79-
with open(
80-
os.path.join(cat_path, cat_name, "catalog_defaults.toml"), "rb"
81-
) as f:
77+
with open(os.path.join(cat_path, cat_name, "catalog_defaults.toml"), "rb") as f:
8278
defaults = tomli.load(f)
8379
for k in dataset_mod.dataset_ns_map.keys():
8480
all_defaults.update({k: defaults})
@@ -111,13 +107,9 @@ def __init__(self, config_path: str, defaults: dict, ns: str):
111107
account = v.get("account", "")
112108
container = v.get("container", "")
113109
if account == "":
114-
self.config[k]["account"] = self.defaults["storage"][
115-
"account"
116-
]
110+
self.config[k]["account"] = self.defaults["storage"]["account"]
117111
if container == "":
118-
self.config[k]["container"] = self.defaults["storage"][
119-
"container"
120-
]
112+
self.config[k]["container"] = self.defaults["storage"]["container"]
121113
self.validate_dataset_config(config_path)
122114
self._ledger_location = {
123115
"account": self.defaults["storage"]["account"],
@@ -144,8 +136,7 @@ def validate_dataset_config(self, config_path) -> None:
144136
config_models = {}
145137
for c_key, c_value in self.config.items():
146138
if (
147-
c_key.startswith("stage_")
148-
or c_key in ["load", "extract", "data"]
139+
c_key.startswith("stage_") or c_key in ["load", "extract", "data"]
149140
) and c_value is not None:
150141
config_models[c_key] = StorageEndpointValidation(**c_value)
151142
elif c_key == "properties":
@@ -207,9 +198,7 @@ def write_blob(
207198
append (bool, optional): whether to append to existing file (only for single file writes).
208199
"""
209200
if auto_version and not append:
210-
path_after_prefix = (
211-
f"{get_timestamp()}/{path_after_prefix.lstrip('/')}"
212-
)
201+
path_after_prefix = f"{get_timestamp()}/{path_after_prefix.lstrip('/')}"
213202
path_after_prefix = path_after_prefix.lstrip("/")
214203
full_path = f"{self.prefix}/{path_after_prefix}"
215204
if isinstance(file_buffer, bytes):
@@ -231,9 +220,7 @@ def write_blob(
231220
self.ledger_entry(action="write")
232221
# print(f"file written to: {full_path}")
233222

234-
def read_blobs(
235-
self, version: str = "latest", newest: bool = True
236-
) -> List[bytes]:
223+
def read_blobs(self, version: str = "latest", newest: bool = True) -> list[bytes]:
237224
"""Read a blob in as bytes so it can be loaded into a dataframe
238225
239226
Args:
@@ -295,18 +282,16 @@ def get_file_ext(self, version: str = "latest") -> str:
295282
Returns:
296283
str: the file extension
297284
"""
298-
return self._get_version_blobs(version=version, print_version=False)[
299-
0
300-
]["name"].split(".")[-1]
285+
return self._get_version_blobs(version=version, print_version=False)[0][
286+
"name"
287+
].split(".")[-1]
301288

302289
def _get_version_blobs(
303290
self, version: str = "latest", newest=True, print_version=True
304291
) -> list:
305292
if not self.is_ledger:
306293
available_versions = self.get_versions()
307-
version = version_matcher(
308-
version, available_versions, newest=newest
309-
)
294+
version = version_matcher(version, available_versions, newest=newest)
310295
if not version:
311296
raise ValueError(
312297
f"Version {version} not found in available versions: {available_versions}"
@@ -414,9 +399,7 @@ def get_dataframe(
414399

415400
def get_dataframe(
416401
self,
417-
output: Literal[
418-
"pandas", "pd", "polars", "pl", "pl_lazy", "lazy"
419-
] = "pandas",
402+
output: Literal["pandas", "pd", "polars", "pl", "pl_lazy", "lazy"] = "pandas",
420403
version: str = "latest",
421404
newest: bool = True,
422405
) -> pd.DataFrame | pl.DataFrame | pl.LazyFrame:
@@ -489,9 +472,7 @@ def get_dataframe(
489472
self.ledger_entry(action="read")
490473
return df
491474
else:
492-
raise ValueError(
493-
f"Lazy loading not supported for {file_ext} files."
494-
)
475+
raise ValueError(f"Lazy loading not supported for {file_ext} files.")
495476
blobs = self.read_blobs(version, newest=newest)
496477
blob_bytes = [blob.content_as_bytes() for blob in blobs]
497478
blob_files = [BytesIO(pq) for pq in blob_bytes]
@@ -523,9 +504,7 @@ def get_dataframe(
523504
return df
524505
elif file_ext == "jsonl" or file_ext == "ndjson":
525506
if output in ["pandas", "pd"]:
526-
df = pd.concat(
527-
[pd.read_json(blob, lines=True) for blob in blob_files]
528-
)
507+
df = pd.concat([pd.read_json(blob, lines=True) for blob in blob_files])
529508
df.reset_index(inplace=True, drop=True)
530509
else:
531510
df = pl.concat(
@@ -535,9 +514,7 @@ def get_dataframe(
535514
return df
536515
elif file_ext == "parquet" or file_ext == "parq":
537516
if output in ["pandas", "pd"]:
538-
df = pd.concat(
539-
[pd.read_parquet(pq_file) for pq_file in blob_files]
540-
)
517+
df = pd.concat([pd.read_parquet(pq_file) for pq_file in blob_files])
541518
df.reset_index(inplace=True, drop=True)
542519
else:
543520
df = pl.concat(
@@ -593,9 +570,7 @@ def save_dataframe(
593570
raise ValueError(
594571
f"File format {file_format} not supported. Use 'parquet', 'csv', 'json', or 'jsonl'."
595572
)
596-
if file_format in ["json", "jsonl"] and path_after_prefix.endswith(
597-
".json"
598-
):
573+
if file_format in ["json", "jsonl"] and path_after_prefix.endswith(".json"):
599574
path_after_prefix = path_after_prefix[:-5] + ".jsonl"
600575
print("Changing file extension to .jsonl for line-delimited JSON.")
601576
if isinstance(df, pd.DataFrame):
@@ -618,9 +593,7 @@ def save_dataframe(
618593
auto_version=auto_version,
619594
)
620595
elif file_format in ["json", "jsonl"]:
621-
json_bytes = df.to_json(orient="records", lines=True).encode(
622-
"utf-8"
623-
)
596+
json_bytes = df.to_json(orient="records", lines=True).encode("utf-8")
624597
self.write_blob(
625598
file_buffer=json_bytes,
626599
path_after_prefix=path_after_prefix
@@ -762,19 +735,15 @@ def dict_to_sn(d: Any, defaults: dict = None, ns: str = "") -> SimpleNamespace:
762735
rc = []
763736
for k in all_reports_ns_map.keys():
764737
rc.append(report_dict_to_sn({k: all_reports_ns_map[k]}))
765-
combined_reports_dict = {
766-
key: value for ns in rc for key, value in vars(ns).items()
767-
}
738+
combined_reports_dict = {key: value for ns in rc for key, value in vars(ns).items()}
768739

769740
datacat = SimpleNamespace(**combined_dict)
770741
datacat.__setattr__("__namespace_list__", dataset_namespaces)
771742
reportcat = SimpleNamespace(**combined_reports_dict)
772743
reportcat.__setattr__("__namespace_list__", report_namespaces)
773744

774745

775-
def _attach_schema_mock_functions(
776-
datacat: SimpleNamespace, catalogs: list
777-
) -> None:
746+
def _attach_schema_mock_functions(datacat: SimpleNamespace, catalogs: list) -> None:
778747
"""Recursively walk the datacat namespace and attach mock_data functions to
779748
the extract and load BlobEndpoints of each DatasetEndpoint, sourced from
780749
a schema module co-located with the dataset.
@@ -812,14 +781,11 @@ def _walk(ns: SimpleNamespace) -> None:
812781
# strip cat_name prefix -> "stf.nhsn_hrd_prelim"
813782
# then split into team ("stf") and dataset ("nhsn_hrd_prelim")
814783
# so the schema lives at: datasets.stf.schemas.nhsn_hrd_prelim
815-
ns_within_datasets = val.__ns_str__.removeprefix(
816-
f"{cat_name}."
817-
)
784+
ns_within_datasets = val.__ns_str__.removeprefix(f"{cat_name}.")
818785
ns_parts = ns_within_datasets.rsplit(".", 1)
819786
team_path = ns_parts[0] if len(ns_parts) > 1 else ""
820787
schema_mod_path = (
821-
f"{cns}.{cat_name}.datasets"
822-
f".{team_path}.schemas.{dataset_name}"
788+
f"{cns}.{cat_name}.datasets.{team_path}.schemas.{dataset_name}"
823789
if team_path
824790
else f"{cns}.{cat_name}.datasets.schemas.{dataset_name}"
825791
)

cfa/dataops/command.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,7 @@ def get_available_data():
5858
Retrieve a list of available datasets for CFA.
5959
"""
6060
parser = ArgumentParser(description="Get list of available datasets")
61-
parser.add_argument(
62-
"-p", "--prefix", help="optional prefix filter", default=None
63-
)
61+
parser.add_argument("-p", "--prefix", help="optional prefix filter", default=None)
6462
args = parser.parse_args()
6563
datasets = datacat.__namespace_list__
6664
if args.prefix:
@@ -125,9 +123,7 @@ def save_data_locally():
125123
parser.add_argument(
126124
"--stage", "-s", help="specific stage to get version for", default=None
127125
)
128-
parser.add_argument(
129-
"--version", "-v", help="specific version to get", default=None
130-
)
126+
parser.add_argument("--version", "-v", help="specific version to get", default=None)
131127
parser.add_argument(
132128
"--force", "-f", help="force re-download of data", action="store_true"
133129
)

cfa/dataops/config_validator.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""The dataset config validator."""
22

33
from enum import Enum
4-
from typing import List, Optional
54

65
from pydantic import (
76
BaseModel,
@@ -34,15 +33,15 @@ class PropertiesValidation(BaseModel):
3433
...,
3534
description="The type of the dataset.",
3635
)
37-
schemas: Optional[str] = Field(
36+
schemas: str | None = Field(
3837
None,
3938
description="the relative path to where the data schema(s) are defined.",
4039
)
41-
transform_templates: Optional[List[str]] = Field(
40+
transform_templates: list[str] | None = Field(
4241
None,
4342
description="A list of transform templates to applied to raw data.",
4443
)
45-
automate: Optional[bool] = Field(
44+
automate: bool | None = Field(
4645
False,
4746
description="Whether to automate workflows that cache raw data and transform it.",
4847
)
@@ -80,9 +79,9 @@ class ConfigValidator(BaseModel):
8079

8180
model_config = ConfigDict(extra="allow")
8281
properties: PropertiesValidation
83-
load: Optional[StorageEndpointValidation] = None
84-
source: Optional[SourceValidation] = None
85-
extract: Optional[StorageEndpointValidation] = None
82+
load: StorageEndpointValidation | None = None
83+
source: SourceValidation | None = None
84+
extract: StorageEndpointValidation | None = None
8685

8786
# Any stage_xx field will be validated dynamically; no need for explicit field or nesting.
8887
@classmethod

cfa/dataops/create_catalog/command.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
_here_dir = os.path.split(os.path.abspath(__file__))[0]
2020
template_dirs = [os.path.join(_here_dir, "repo_templates")]
2121
repo_files_dirs = os.path.join(_here_dir, "repo_files")
22-
repo_template_lookup = TemplateLookup(
23-
directories=template_dirs, cache_enabled=False
24-
)
22+
repo_template_lookup = TemplateLookup(directories=template_dirs, cache_enabled=False)
2523

2624

2725
def main():
@@ -84,9 +82,7 @@ def main():
8482
with open(
8583
os.path.join(library_modules_root, "catalog_defaults.toml"), "w"
8684
) as f:
87-
template = repo_template_lookup.get_template(
88-
"catalog_defaults.toml.mako"
89-
)
85+
template = repo_template_lookup.get_template("catalog_defaults.toml.mako")
9086
f.write(
9187
template.render(
9288
unique_name=unique_name,
@@ -129,9 +125,7 @@ def main():
129125
sys.exit(0)
130126

131127
if args.expanded_repo_for_cfa:
132-
print(
133-
"Including CFA expanded repository pre-commit and workflow files."
134-
)
128+
print("Including CFA expanded repository pre-commit and workflow files.")
135129
for copy_i in [
136130
".pre-commit-config.yaml",
137131
".secrets.baseline",

cfa/dataops/create_catalog/repo_files/_cfa_only/.pre-commit-config.yaml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,12 @@ repos:
1313
#####
1414
# Python
1515
- repo: https://github.com/astral-sh/ruff-pre-commit
16-
rev: v0.6.8
16+
rev: v0.15.8
1717
hooks:
1818
# Sort imports
19-
- id: ruff
20-
args: ['check', '--select', 'I', '--fix']
21-
# Run the linter
22-
- id: ruff
23-
args: ['--line-length', '79']
19+
- id: ruff-check
2420
# Run the formatter
2521
- id: ruff-format
26-
args: ['--line-length', '79']
2722
# Secrets
2823
- repo: https://github.com/Yelp/detect-secrets
2924
rev: v1.4.0
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
extend-include = ["*.ipynb"]
2-
line-length = 79
3-
ignore = []
2+
fix = true
3+
lint.select = ["I", "E4", "E7", "E9", "F", "UP"]

cfa/dataops/create_catalog/repo_files/datasets/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import glob
44
import os
5+
from collections.abc import Callable
56
from os import path
6-
from typing import Optional
77

88
import tomli
99

@@ -44,7 +44,7 @@ def get_dataset_name(p: str) -> str:
4444

4545

4646
def get_fs_ns_map(
47-
base_dir: str, file_ext: str, endpoint_func: Optional[callable] = None
47+
base_dir: str, file_ext: str, endpoint_func: Callable[[str], str] | None = None
4848
) -> dict:
4949
"""Get a nested dictionary representing the filesystem structure starting from base_dir.
5050
@@ -60,9 +60,7 @@ def get_fs_ns_map(
6060
"""
6161
base_dir = os.path.abspath(base_dir)
6262
file_ext = file_ext.lstrip(".")
63-
fs_paths = glob.glob(
64-
os.path.join(base_dir, "**", f"*.{file_ext}"), recursive=True
65-
)
63+
fs_paths = glob.glob(os.path.join(base_dir, "**", f"*.{file_ext}"), recursive=True)
6664
fs_map = {}
6765
for p_i in fs_paths:
6866
if p_i.startswith(base_dir):

0 commit comments

Comments
 (0)