-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhelper.py
More file actions
169 lines (146 loc) · 5.05 KB
/
helper.py
File metadata and controls
169 lines (146 loc) · 5.05 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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/usr/bin/env python3
# src/core/helper.py
import os
import sys
import platform
import subprocess
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
class Helper:
"""
Small collection of cross-app helpers.
"""
def __init__(self, root_dir: str | None = None, script_dir: str | None = None):
if script_dir is None:
if getattr(sys, "frozen", False):
script_dir = os.path.dirname(sys.executable)
else:
script_dir = os.path.dirname(os.path.abspath(__file__))
self.script_dir = script_dir
if root_dir is None:
# If we are in .../src/app, root_dir should be project root (two levels up).
base = os.path.dirname(self.script_dir) # e.g. .../src
parent = os.path.dirname(base) # e.g. project_root
self.root_dir = parent
else:
self.root_dir = root_dir
self.home_dir = os.path.expanduser("~")
def get_path(self, rel_path: str) -> str | None:
rel = rel_path.replace("\\", "/")
# 1) PyInstaller onefile temp dir
meipass = getattr(sys, "_MEIPASS", None)
if meipass:
p = os.path.join(meipass, rel)
if os.path.exists(p):
return p
# 2) Next to the frozen exe
if getattr(sys, "frozen", False):
p = os.path.join(self.script_dir, rel)
if os.path.exists(p):
return p
# 3) macOS .app Resources
res = os.path.join(self.root_dir, "Resources", rel)
if os.path.exists(res):
return res
# 4) repo src/
src = os.path.join(self.root_dir, "src", rel)
if os.path.exists(src):
return src
print(f"[Helper] Could not find resource: {rel}")
return None
@staticmethod
def get_os() -> str:
name = platform.system()
if name == "Darwin":
return "macos"
if name == "Linux":
return "linux"
if name == "Windows":
return "windows"
return "unknown"
@staticmethod
def get_arch() -> str:
arch = platform.machine().lower()
if arch in ("x86_64", "amd64"):
return "x86_64"
if arch in ("aarch64", "arm64"):
return "arm64"
if arch in ("i386", "i686", "x86", "i86pc"):
return "x86"
if arch in ("armv7l", "armv8l", "arm"):
return "armhf"
return "unknown"
@staticmethod
def get_serial() -> str:
# Linux / Pi: /proc/cpuinfo usually contains a 'Serial' line
try:
if Helper.get_os() == "linux":
cpuinfo_path = "/proc/cpuinfo"
if os.path.exists(cpuinfo_path):
with open(cpuinfo_path, "r", encoding="utf-8", errors="ignore") as f:
for line in f:
if line.lower().startswith("serial"):
parts = line.split(":", 1)
if len(parts) == 2:
return parts[1].strip()
except Exception:
# Swallow errors and fall through to empty string
pass
# Fallback: nothing suitable found
return ""
@staticmethod
def get_screen_resolution() -> tuple[int, int]:
app = QApplication.instance()
if not app:
return (0, 0)
screen = app.primaryScreen()
size = screen.size()
return (size.width(), size.height())
@staticmethod
def get_now() -> str:
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@staticmethod
def file_exists(path: str | None) -> bool:
return bool(path) and os.path.isfile(path)
@staticmethod
def dir_exists(path: str | None) -> bool:
return bool(path) and os.path.isdir(path)
@staticmethod
def join(*paths: str) -> str:
return os.path.join(*paths)
@staticmethod
def qss_url(p: str | None) -> str:
"""
Return a url("...") QSS literal, or url("") for None.
"""
if not p:
return 'url("")'
return f'url("{p.replace(os.sep, "/")}")'
@staticmethod
def run(cmd):
try:
p = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
timeout=6
)
return p.returncode, (p.stdout or "").strip()
except Exception as e:
return 1, f"{type(e).__name__}: {e}"
# ---------- StyleSheet Handling ----------
def load_stylesheet(self, rel_path: str) -> str | None:
"""
Load a stylesheet from a relative path.
"""
p = self.get_path(rel_path)
if not p:
return None
try:
with open(p, "r", encoding="utf-8") as f:
return f.read()
except Exception as e:
print(f"[Helper] Failed to load stylesheet {rel_path}: {e}")
return None