sahil-shetty
10/04/2024, 3:30 AMElijah Ben Izzy
10/04/2024, 3:41 AMpl.DataFrame — the code you showed above suggests applicable_types[0] is an actual dataframes.
@classmethod
@abc.abstractmethod
def applicable_types(cls) -> Collection[Type]:
return [pl.DataFrame]
What’s the code for your custom loader look like?Thierry Jean
10/04/2024, 4:47 AM@dataloader decorated function is type annotated to return a tuple?
It should be
@dataloader()
def my_loader() -> tuple[pl.DataFrame, dict]:
return data, metadata
rather than
@dataloader()
def my_loader() -> pl.DataFrame:
return datasahil-shetty
10/04/2024, 5:05 AM@dataclass
class S3ExcelDataLoader(DataLoader):
"""Data Loader that retrieves Excel files from an S3 bucket and loads them into a DataFrame.
It validates the S3 path and file extension to ensure proper loading of the specified Excel sheet.
Attributes:
s3_path (str): The S3 path to the Excel file to be loaded.
sheet_name (str | None): The name of the sheet to load from the Excel file (optional).
session (boto3.Session): The boto3 session used to interact with AWS services.
Methods:
load_data(type_): Loads the Excel data from the specified S3 path and returns it as a DataFrame along with metadata.
applicable_types(): Returns a collection of data types that this loader can handle.
name(): Returns the name of the data loader.
Raises:
ValueError: If the provided S3 path does not end with .xls or .xlsx or does not start with s3://.
"""
s3_path: str
sheet_name: str | None = None
session: boto3.Session = field(default_factory=boto3.Session)
def __post_init__(self) -> None: # noqa: D105
if not self.s3_path.endswith((".xls", ".xlsx")):
msg: str = f"Excel files must end with .xls or .xlsx, got {self.s3_path}"
raise ValueError(msg)
if not self.s3_path.startswith("s3://"):
msg: str = f"S3 path must start with s3://, got {self.s3_path}"
raise ValueError(msg)
@classmethod
def applicable_types(cls) -> Collection[type]:
return [pl.DataFrame]
def load_data(self, type_: type) -> tuple[pl.DataFrame, dict[str, Any]]: # noqa: D102
logger.info(f"Loading Excel data from {self.s3_path}, sheet: {self.sheet_name}...")
s3_client = self.session.client("s3")
bucket_name, key = self.s3_path.replace("s3://", "").split("/", 1)
obj = s3_client.get_object(Bucket=bucket_name, Key=key)
excel_data: io.BytesIO = io.BytesIO(obj["Body"].read())
raw_df: pd.DataFrame = pl.read_excel(
source=excel_data, sheet_name=self.sheet_name, infer_schema_length=20000
)
metadata: dict[str, Any] = utils.get_dataframe_metadata(raw_df)
logger.info("Loaded Excel data successfully!")
return raw_df, metadata
@classmethod
def name(cls) -> str: # noqa: D102
return "s3_excel_loader" # the name for `from_.{name}`sahil-shetty
10/04/2024, 5:11 AMStefan Krawczyk
10/04/2024, 5:13 AMtype_: type here?Stefan Krawczyk
10/04/2024, 5:17 AMStefan Krawczyk
10/04/2024, 5:19 AMfrom typing import Any
from polars import pl
Any in [pl.DataFrame]
Doesn’t break with polars 1.7.1 & python 3.9, nor with python 3.11 and polars==1.9.0Stefan Krawczyk
10/04/2024, 5:23 AMs3_excel_loader ?sahil-shetty
10/04/2024, 5:54 AMsahil-shetty
10/04/2024, 5:55 AMStefan Krawczyk
10/04/2024, 6:13 AMStefan Krawczyk
10/04/2024, 6:15 AMfrom typing import Any
import polars as pl
a = pl.DataFrame({"a":[1,2,3,4]})
Any in [a]Stefan Krawczyk
10/04/2024, 6:16 AMcls.applicable_types() is somehow returning an object — rather than a type.Stefan Krawczyk
10/04/2024, 6:18 AM() to make that type an object?sahil-shetty
10/04/2024, 6:21 AM()Stefan Krawczyk
10/04/2024, 6:25 AM.applicable_types() function is being called?Stefan Krawczyk
10/04/2024, 6:27 AMsahil-shetty
10/04/2024, 6:29 AMStefan Krawczyk
10/04/2024, 6:39 AMStefan Krawczyk
10/04/2024, 6:41 AMname. Hamilton just takes the last one that was registered.
Some ideas to remedy:
• if in a notebook or REPL, restart python to wipe what loader is registered.
• register the class you think should be used again for that namesahil-shetty
10/04/2024, 12:31 PMapplicable_types method at some point. Debugging to figure out where.sahil-shetty
10/04/2024, 1:52 PMStefan Krawczyk
10/04/2024, 3:35 PM