60 lines
2.1 KiB
Python
60 lines
2.1 KiB
Python
"""Runtime configuration loader — reads secrets from a gitignored ``.env``.
|
|
|
|
Broker login lives in ``.env`` (gitignored). The bridge reads these at runtime
|
|
and injects them into ``tester.ini``'s ``[Common]`` section **without printing
|
|
them** (doc 07 §5). Never hard-code credentials and never print them.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
try:
|
|
from dotenv import load_dotenv # type: ignore
|
|
_HAS_DOTENV = True
|
|
except ImportError:
|
|
_HAS_DOTENV = False
|
|
|
|
|
|
def load_env(project_root: Optional[str | Path] = None) -> dict[str, str]:
|
|
"""Load ``.env`` from ``project_root`` (defaults to this file's parent).
|
|
|
|
Returns the MT5 credential keys without their values exposed in logs.
|
|
Falls back to plain line parsing if ``python-dotenv`` isn't installed.
|
|
"""
|
|
root = Path(project_root) if project_root else Path(__file__).resolve().parent.parent
|
|
env_path = root / ".env"
|
|
if _HAS_DOTENV and env_path.exists():
|
|
load_dotenv(env_path)
|
|
elif env_path.exists():
|
|
_parse_plain(env_path)
|
|
return {
|
|
"MT5_DEMO_LOGIN": os.environ.get("MT5_DEMO_LOGIN", ""),
|
|
"MT5_DEMO_SERVER": os.environ.get("MT5_DEMO_SERVER", ""),
|
|
# Password is intentionally not returned here; read via get_secret().
|
|
"MT5_TERMINAL_PATH": os.environ.get(
|
|
"MT5_TERMINAL_PATH",
|
|
r"C:\Program Files\MetaTrader 5 IC Markets Global\terminal64.exe",
|
|
),
|
|
}
|
|
|
|
|
|
def get_secret(name: str) -> str:
|
|
"""Read a secret from the environment (load_env must be called first)."""
|
|
return os.environ.get(name, "")
|
|
|
|
|
|
def _parse_plain(env_path: Path) -> None:
|
|
"""Minimal ``.env`` parser (KEY=VALUE) without python-dotenv."""
|
|
for line in env_path.read_text(encoding="utf-8").splitlines():
|
|
line = line.strip()
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
continue
|
|
k, _, v = line.partition("=")
|
|
k, v = k.strip(), v.strip()
|
|
# Strip optional surrounding quotes.
|
|
if len(v) >= 2 and v[0] == v[-1] and v[0] in ("'", '"'):
|
|
v = v[1:-1]
|
|
os.environ.setdefault(k, v)
|