33import json
44import os
55import pkgutil
6+ from collections .abc import Sequence
67from configparser import ConfigParser
78from importlib import import_module
89from io import BytesIO
910from pathlib import PurePosixPath
1011from types import SimpleNamespace
11- from typing import Any , List , Literal , Sequence , overload
12+ from typing import Any , Literal , overload
1213
1314import pandas as pd
1415import polars as pl
1516import tomli
1617from azure .identity import ManagedIdentityCredential
17-
1818from 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:
762735rc = []
763736for 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
769740datacat = SimpleNamespace (** combined_dict )
770741datacat .__setattr__ ("__namespace_list__" , dataset_namespaces )
771742reportcat = SimpleNamespace (** combined_reports_dict )
772743reportcat .__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 )
0 commit comments