Spaces:
Running
Running
| """JSON serialization helpers for pandas, numpy, and datetime values.""" | |
| from __future__ import annotations | |
| import json | |
| import math | |
| from datetime import date, datetime | |
| from decimal import Decimal | |
| from typing import Any | |
| import numpy as np | |
| import pandas as pd | |
| def _normalize_text(value: Any) -> str: | |
| """Normalize dict keys / text values to valid UTF-8 strings.""" | |
| if isinstance(value, bytes): | |
| value = value.decode("utf-8-sig", errors="replace") | |
| text = str(value) | |
| # Drop any bytes that cannot round-trip through UTF-8; prevents invalid | |
| # characters from reaching JSON serialization. | |
| return text.encode("utf-8", errors="ignore").decode("utf-8") | |
| # Intentionally expose the helper for use by other modules. | |
| __all__ = ["to_jsonable", "dataframe_to_records", "dumps_json", "loads_json", "_normalize_text"] | |
| def to_jsonable(value: Any) -> Any: | |
| """Convert common data-science objects into strict JSON-compatible values.""" | |
| if value is None: | |
| return None | |
| if isinstance(value, (str, bool, int)): | |
| return value | |
| if isinstance(value, float): | |
| return value if math.isfinite(value) else None | |
| if isinstance(value, Decimal): | |
| return float(value) | |
| if isinstance(value, (datetime, date, pd.Timestamp)): | |
| if pd.isna(value): | |
| return None | |
| return value.isoformat() | |
| if isinstance(value, np.generic): | |
| return to_jsonable(value.item()) | |
| if isinstance(value, dict): | |
| return {_normalize_text(k): to_jsonable(v) for k, v in value.items()} | |
| if isinstance(value, (list, tuple, set)): | |
| return [to_jsonable(item) for item in value] | |
| if isinstance(value, pd.DataFrame): | |
| return dataframe_to_records(value) | |
| if isinstance(value, pd.Series): | |
| return to_jsonable(value.to_dict()) | |
| if pd.isna(value): | |
| return None | |
| return _normalize_text(value) | |
| def dataframe_to_records(df: pd.DataFrame, limit: int | None = None) -> list[dict[str, Any]]: | |
| """Return JSON-safe records while preserving AKShare's Chinese column names.""" | |
| if df is None: | |
| return [] | |
| work = df.head(limit).copy() if limit else df.copy() | |
| work.columns = [_normalize_text(c) for c in work.columns] | |
| return [to_jsonable(record) for record in work.to_dict(orient="records")] | |
| def dumps_json(value: Any) -> str: | |
| return json.dumps(to_jsonable(value), ensure_ascii=False, separators=(",", ":")) | |
| def loads_json(value: str) -> Any: | |
| return json.loads(value) | |