文件内容
paper_trading/env_file.py
"""Load optional gitignored ``.env`` at skill root into ``os.environ``.
Precedence for quote upstream env (highest first):
1. Process env (``export`` in shell, SkillHub-injected env, IDE env)
2. ``<skill-root>/.env`` (optional local fallback; never shipped by SkillHub)
``auth`` in ``config/main.yaml`` selects auth mode only:
- ``bearer`` — ``STOCKI_GATEWAY_URL`` + ``STOCKI_API_KEY``
- ``none`` — ``STOCKI_GATEWAY_URL`` (no API key)
``load_env_file`` never overrides keys already in ``os.environ``.
``resolve_stocki_quote()`` reads env — see ``config.py``.
"""
from __future__ import annotations
import os
from pathlib import Path
SKILL_ROOT = Path(__file__).resolve().parent.parent
def skill_root() -> Path:
return SKILL_ROOT
def _parse_line(line: str) -> tuple[str, str] | None:
stripped = line.strip()
if not stripped or stripped.startswith("#"):
return None
if stripped.startswith("export "):
stripped = stripped[7:].strip()
if "=" not in stripped:
return None
key, _, value = stripped.partition("=")
key = key.strip()
value = value.strip()
if len(value) >= 2 and value[0] == value[-1] and value[0] in "\"'":
value = value[1:-1]
if not key:
return None
return key, value
def load_env_file(root: Path | None = None) -> Path | None:
"""Load ``<root>/.env`` if present. Returns the path loaded, else None."""
base = root or SKILL_ROOT
path = base / ".env"
if not path.is_file():
return None
for raw in path.read_text(encoding="utf-8").splitlines():
parsed = _parse_line(raw)
if parsed is None:
continue
key, value = parsed
if key in os.environ:
continue
os.environ[key] = value
return path