Source code for episia.data.io
"""
This module provides functions for reading and writing epidemiological
data in various formats with automatic format detection and validation.
"""
import pandas as pd
from typing import Union, Dict, List
from pathlib import Path
from ..core.exceptions import FileError
from .dataset import Dataset
[docs]
def read_csv(
path: Union[str, Path],
low_memory: bool = True,
**kwargs
) -> Dataset:
"""
Read CSV file into Dataset.
Args:
path: Path to CSV file
low_memory: Optimize memory usage
**kwargs: Additional arguments for pd.read_csv
Returns:
Dataset object
"""
try:
df = pd.read_csv(path, **kwargs)
return Dataset(df, low_memory=low_memory)
except Exception as e:
raise FileError(f"Failed to read CSV file {path}: {e}")
[docs]
def read_excel(
path: Union[str, Path],
sheet_name: Union[str, int, List, None] = 0,
low_memory: bool = True,
**kwargs
) -> Dataset:
"""
Read Excel file into Dataset.
Args:
path: Path to Excel file
sheet_name: Sheet to read
low_memory: Optimize memory usage
**kwargs: Additional arguments for pd.read_excel
Returns:
Dataset object
"""
try:
df = pd.read_excel(path, sheet_name=sheet_name, **kwargs)
return Dataset(df, low_memory=low_memory)
except Exception as e:
raise FileError(f"Failed to read Excel file {path}: {e}")
[docs]
def read_parquet(
path: Union[str, Path],
low_memory: bool = True,
**kwargs
) -> Dataset:
"""
Read Parquet file into Dataset.
Args:
path: Path to Parquet file
low_memory: Optimize memory usage
**kwargs: Additional arguments for pd.read_parquet
Returns:
Dataset object
"""
try:
df = pd.read_parquet(path, **kwargs)
return Dataset(df, low_memory=low_memory)
except Exception as e:
raise FileError(f"Failed to read Parquet file {path}: {e}")
[docs]
def from_pandas(
df: pd.DataFrame,
low_memory: bool = True
) -> Dataset:
"""
Create Dataset from pandas DataFrame.
Args:
df: pandas DataFrame
low_memory: Optimize memory usage
Returns:
Dataset object
"""
return Dataset(df, low_memory=low_memory)
[docs]
def from_dict(
data: Dict,
low_memory: bool = True,
**kwargs
) -> Dataset:
"""
Create Dataset from dictionary.
Args:
data: Dictionary of data
low_memory: Optimize memory usage
**kwargs: Additional arguments for pd.DataFrame
Returns:
Dataset object
"""
df = pd.DataFrame(data, **kwargs)
return Dataset(df, low_memory=low_memory)
[docs]
def from_records(
records: List[Dict],
low_memory: bool = True,
**kwargs
) -> Dataset:
"""
Create Dataset from list of records.
Args:
records: List of dictionaries
low_memory: Optimize memory usage
**kwargs: Additional arguments for pd.DataFrame.from_records
Returns:
Dataset object
"""
df = pd.DataFrame.from_records(records, **kwargs)
return Dataset(df, low_memory=low_memory)
[docs]
def read_surveillance_format(
path: Union[str, Path],
format_type: str = 'auto',
low_memory: bool = True,
**kwargs
) -> Dataset:
"""
Read surveillance data in standard formats.
.. warning::
Parsers for named surveillance standards ('sidesp', 'who', 'ecdc')
are not yet implemented. This function currently only supports
generic tabular files (CSV/Excel/Parquet) via ``format_type='auto'``.
Passing 'sidesp', 'who', or 'ecdc' raises ``NotImplementedError``
rather than silently misreading the file.
Args:
path: Path to surveillance data file
format_type: Format type ('sidesp', 'who', 'ecdc', 'auto')
low_memory: Optimize memory usage
**kwargs: Additional arguments passed to the underlying reader
Returns:
Dataset object
Raises:
NotImplementedError: If format_type is a named surveillance
standard ('sidesp', 'who', 'ecdc'), since no parser for it
exists yet.
FileError: If the file cannot be read.
"""
if format_type == 'auto':
detected = detect_format(path)
if detected == 'csv':
return read_csv(path, low_memory=low_memory, **kwargs)
if detected == 'excel':
return read_excel(path, low_memory=low_memory, **kwargs)
if detected == 'parquet':
return read_parquet(path, low_memory=low_memory, **kwargs)
raise FileError(
f"Could not auto-detect a supported format for {path} "
f"(detected: '{detected}'). Use read_csv/read_excel/read_parquet directly."
)
if format_type in ('sidesp', 'who', 'ecdc'):
raise NotImplementedError(
f"format_type='{format_type}' is not implemented yet. "
"Only format_type='auto' (generic CSV/Excel/Parquet) is currently supported. "
"Contributions implementing SIDESP/WHO/ECDC-specific parsing are welcome."
)
raise ValueError(
f"Unknown format_type: '{format_type}'. "
"Expected one of: 'auto', 'sidesp', 'who', 'ecdc'."
)
[docs]
def detect_format(path: Union[str, Path]) -> str:
"""
Detect file format from extension or content.
Args:
path: Path to file
Returns:
Detected format string
"""
path = Path(path)
suffix = path.suffix.lower()
format_map = {
'.csv': 'csv',
'.xlsx': 'excel',
'.xls': 'excel',
'.parquet': 'parquet',
'.feather': 'feather',
'.json': 'json',
'.txt': 'text'
}
return format_map.get(suffix, 'unknown')
[docs]
def export_dataset(
dataset: Dataset,
path: Union[str, Path],
format: str = 'auto',
**kwargs
) -> None:
"""
Export Dataset to file.
Args:
dataset: Dataset to export
path: Output path
format: Output format ('csv', 'excel', 'parquet', 'auto')
**kwargs: Additional arguments for writer
"""
path = Path(path)
if format == 'auto':
format = detect_format(path)
try:
if format == 'csv':
dataset.df.to_csv(path, **kwargs)
elif format in ['excel', 'xlsx', 'xls']:
dataset.df.to_excel(path, **kwargs)
elif format == 'parquet':
dataset.df.to_parquet(path, **kwargs)
elif format == 'json':
dataset.df.to_json(path, **kwargs)
else:
raise FileError(f"Unsupported export format: {format}")
except Exception as e:
raise FileError(f"Failed to export dataset: {e}")