52 lines
1.4 KiB
Python
Executable File
52 lines
1.4 KiB
Python
Executable File
import os
|
|
from io import StringIO
|
|
import json
|
|
import pandas as pd
|
|
from datetime import date, timedelta, datetime
|
|
from typing import Annotated
|
|
|
|
SavePathType = Annotated[str, "File path to save data. If None, data is not saved."]
|
|
|
|
def save_output(data: pd.DataFrame, tag: str, save_path: SavePathType = None) -> None:
|
|
if save_path:
|
|
data.to_csv(save_path)
|
|
print(f"{tag} saved to {save_path}")
|
|
|
|
|
|
def get_current_date():
|
|
return date.today().strftime("%Y-%m-%d")
|
|
|
|
|
|
def decorate_all_methods(decorator):
|
|
def class_decorator(cls):
|
|
for attr_name, attr_value in cls.__dict__.items():
|
|
if callable(attr_value):
|
|
setattr(cls, attr_name, decorator(attr_value))
|
|
return cls
|
|
|
|
return class_decorator
|
|
|
|
|
|
def get_next_weekday(date):
|
|
|
|
if not isinstance(date, datetime):
|
|
date = datetime.strptime(date, "%Y-%m-%d")
|
|
|
|
if date.weekday() >= 5:
|
|
days_to_add = 7 - date.weekday()
|
|
next_weekday = date + timedelta(days=days_to_add)
|
|
return next_weekday
|
|
else:
|
|
return date
|
|
|
|
def safe_read_csv(text, **kwargs):
|
|
"""
|
|
Try the default C engine first; on ParserError fall back to python engine
|
|
and skip bad lines to avoid tokenizing errors from malformed rows.
|
|
"""
|
|
try:
|
|
return pd.read_csv(StringIO(text), **kwargs)
|
|
except pd.errors.ParserError:
|
|
return pd.read_csv(StringIO(text), engine='python', on_bad_lines='skip', **kwargs)
|
|
|