Programming
6. add
import re
from functools import lru_cache
def _file_range(path):
"""
Rough period range a file covers, from its name. Used only to skip files
we definitely don't need — rows are filtered exactly after reading, so a
range that is too WIDE is harmless and too NARROW loses data. When in
doubt, return None and the file gets read.
history_2023.parquet -> whole of 2023
history_10.2026.parquet -> October 2026
"""
s = path.stem
years = re.findall(r"20\d{2}", s)
if not years:
return None
year = int(years[-1])
months = [int(m) for m in re.findall(r"\d{1,2}", re.sub(r"20\d{2}", " ", s))
if 1 <= int(m) <= 12]
if months:
p = year * 100 + months[0]
return p - 2, p + 2 # pad: the filename may be the stamp, not the period
return (year - 1) * 100 + 11, (year + 1) * 100 + 1
def read_months(data_dir, period_from=None, period_to=None):
files = sorted(Path(data_dir).glob("*.parquet"))
if not files:
raise FileNotFoundError(f"нет parquet-файлов в {data_dir}")
chosen = []
for f in files:
rng = _file_range(f)
if rng is None:
chosen.append(f); continue
lo, hi = rng
if period_from and hi < int(period_from):
continue
if period_to and lo > int(period_to):
continue
chosen.append(f)
if not chosen:
raise ValueError(f"нет файлов за период {period_from}–{period_to}")
df = normalise(pd.concat([pd.read_parquet(f) for f in chosen], ignore_index=True))
# Exact row-level filter — a yearly file carries months outside the window.
per = ((df["report_date"] - pd.Timedelta(days=1)).dt.year * 100
+ (df["report_date"] - pd.Timedelta(days=1)).dt.month)
if period_from:
df = df[per >= int(period_from)]
if period_to:
df = df[per <= int(period_to)]
if df.empty:
raise ValueError(f"нет данных за период {period_from}–{period_to}")
return df
@lru_cache(maxsize=8)
def available_periods(data_dir):
"""
For the dropdown. Reads only the report_date column, so a yearly file
costs almost nothing. Cached — clear it after uploading a new file.
"""
out = set()
for f in sorted(Path(str(data_dir)).glob("*.parquet")):
try:
s = pd.read_parquet(f, columns=["report_date"])["report_date"]
except Exception:
continue
a = pd.to_datetime(s, errors="coerce").dropna() - pd.Timedelta(days=1)
out |= set((a.dt.year * 100 + a.dt.month).unique().tolist())
return sorted(int(p) for p in out)
PO
powerty
Muallif
· Staff
Okt. 8, 2026
Okt. 8, 2026
22
Ko'rishlar
0
Yoqishlar
2m
O'qildi