-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathresources.py
More file actions
146 lines (132 loc) · 3.79 KB
/
Copy pathresources.py
File metadata and controls
146 lines (132 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
"""Resolve bundled data paths (dev tree vs PyInstaller _MEIPASS)."""
from __future__ import annotations
import json
import logging
import sys
from datetime import date, datetime
from pathlib import Path
from zoneinfo import ZoneInfo
logger = logging.getLogger(__name__)
DEFAULT_SESSIONS: list[dict] = [
{
"id": "HKG",
"mkt": "HKEX ",
"type": "MAIN",
"tz": "Asia/Hong_Kong",
"open": 9,
"close": 18,
"icon": "🏮",
"venue": "exchange",
},
{
"id": "FRA",
"mkt": "XETRA",
"type": "MAIN",
"tz": "Europe/Berlin",
"open": 9,
"close": 17.5,
"icon": "🇩🇪",
"venue": "exchange",
},
{
"id": "LDN",
"mkt": "LSE ",
"type": "MAIN",
"tz": "Europe/London",
"open": 8,
"close": 16,
"icon": "🔵",
"venue": "exchange",
},
{
"id": "NYC",
"mkt": "NYSE ",
"type": "PRE ",
"tz": "America/New_York",
"open": 4,
"close": 9.5,
"icon": "🌤️",
"venue": "exchange",
},
{
"id": "NYC",
"mkt": "NYSE ",
"type": "MAIN",
"tz": "America/New_York",
"open": 9.5,
"close": 16,
"icon": "🗽",
"venue": "exchange",
},
{
"id": "CHI",
"mkt": "CME ",
"type": "CME ",
"tz": "America/Chicago",
"open": 17,
"close": 16,
"icon": "📊",
"venue": "cme",
},
]
def app_data_dir() -> Path:
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
return Path(sys._MEIPASS) / "data"
return Path(__file__).resolve().parent / "data"
def load_sessions() -> list[dict]:
path = app_data_dir() / "sessions.json"
try:
with open(path, encoding="utf-8") as f:
data = json.load(f)
if not isinstance(data, list):
raise ValueError("sessions.json must be a JSON array")
return data
except (OSError, json.JSONDecodeError, ValueError) as e:
logger.warning("Failed to load sessions.json, using defaults: %s", e)
return list(DEFAULT_SESSIONS)
def load_cpi_document() -> dict:
path = app_data_dir() / "cpi_dates.json"
try:
with open(path, encoding="utf-8") as f:
data = json.load(f)
if not isinstance(data, dict):
raise ValueError("cpi_dates.json must be a JSON object")
return data
except (OSError, json.JSONDecodeError, ValueError) as e:
logger.warning("Failed to load cpi_dates.json: %s", e)
return {"releases": []}
def upcoming_cpi_lines(doc: dict, ref_date: date, limit: int = 4) -> list[str]:
"""Human-readable lines for releases on or after ref_date (ISO calendar day)."""
releases = doc.get("releases", [])
if not isinstance(releases, list):
return []
lines: list[str] = []
try:
sorted_r = sorted(
(r for r in releases if isinstance(r, dict)),
key=lambda r: str(r.get("date", "")),
)
except (TypeError, ValueError):
return []
for r in sorted_r:
ds = r.get("date")
if not ds:
continue
try:
d = datetime.fromisoformat(str(ds)).date()
except ValueError:
continue
if d < ref_date:
continue
label = r.get("label") or str(ds)
lines.append(f"{label} — {ds} (ET calendar)")
if len(lines) >= limit:
break
return lines
def menu_lines_for_cpi_section() -> list[str]:
ref = datetime.now(ZoneInfo("America/New_York")).date()
doc = load_cpi_document()
lines = upcoming_cpi_lines(doc, ref)
if not lines:
return ["No upcoming CPI rows — edit data/cpi_dates.json"]
return lines