pyappify 0.0.2__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyappify
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: My awesome Python application
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -0,0 +1,146 @@
1
+ # pyappify/__init__.py
2
+ import os
3
+ import signal
4
+ import hashlib
5
+ import shutil
6
+ import urllib.request
7
+ import zipfile
8
+ import threading
9
+
10
+ app_version = os.environ.get("PYAPPIFY_APP_VERSION")
11
+ app_profile = os.environ.get("PYAPPIFY_APP_PROFILE")
12
+ pyappify_version = os.environ.get("PYAPPIFY_VERSION")
13
+ pyappify_executable = os.environ.get("PYAPPIFY_EXECUTABLE")
14
+
15
+ pyappify_upgradeable = os.environ.get("PYAPPIFY_UPGRADEABLE") == '1'
16
+ logger = None
17
+
18
+ try:
19
+ pid = int(os.environ.get("PYAPPIFY_PID"))
20
+ except (ValueError, TypeError):
21
+ pid = None
22
+
23
+ import sys
24
+
25
+ try:
26
+ import ctypes
27
+ except ImportError:
28
+ ctypes = None
29
+
30
+
31
+ def minimize_window_by_pid(pid):
32
+ if not ctypes or sys.platform != "win32":
33
+ return False
34
+
35
+ found_hwnd = []
36
+ EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
37
+
38
+ def enum_windows_callback(hwnd, lParam):
39
+ owner_pid = ctypes.c_ulong()
40
+ ctypes.windll.user32.GetWindowThreadProcessId(hwnd, ctypes.byref(owner_pid))
41
+ if owner_pid.value == pid and ctypes.windll.user32.IsWindowVisible(hwnd):
42
+ found_hwnd.append(hwnd)
43
+ return False
44
+ return True
45
+
46
+ ctypes.windll.user32.EnumWindows(EnumWindowsProc(enum_windows_callback), 0)
47
+
48
+ if found_hwnd:
49
+ ctypes.windll.user32.ShowWindow(found_hwnd[0], 6)
50
+ return True
51
+
52
+ return False
53
+
54
+ def kill_pyappify():
55
+ if pid:
56
+ if logger:
57
+ logger.info(f"Attempting to terminate process with PID: {pid}")
58
+ try:
59
+ os.kill(pid, signal.SIGTERM)
60
+ except Exception as e:
61
+ if logger:
62
+ logger.error(f"Failed to terminate process with PID {pid}: {e}")
63
+ pass
64
+
65
+ def hide_pyappify():
66
+ if pid:
67
+ if logger:
68
+ logger.info(f"Attempting to minimize window for process with PID: {pid}")
69
+ try:
70
+ minimize_window_by_pid(pid)
71
+ except Exception as e:
72
+ if logger:
73
+ logger.error(f"Failed to minimize window for process with PID {pid}: {e}")
74
+ pass
75
+
76
+ def upgrade(to_version, executable_sha256, executable_zip_urls, stop_event=None):
77
+ if not pyappify_upgradeable or to_version == pyappify_version:
78
+ return
79
+
80
+ def _do_upgrade():
81
+ tmp_dir = os.path.join(os.getcwd(), "tmp")
82
+ try:
83
+ os.makedirs(tmp_dir, exist_ok=True)
84
+ downloaded_zip_path = None
85
+ for url in executable_zip_urls:
86
+ try:
87
+ local_zip_path = os.path.join(tmp_dir, os.path.basename(url))
88
+ with urllib.request.urlopen(url) as response, open(local_zip_path, 'wb') as out_file:
89
+ while True:
90
+ if stop_event and stop_event.is_set():
91
+ if logger:
92
+ logger.info("Upgrade download cancelled by stop event.")
93
+ return
94
+ chunk = response.read(8192)
95
+ if not chunk:
96
+ break
97
+ out_file.write(chunk)
98
+ downloaded_zip_path = local_zip_path
99
+ break
100
+ except Exception as e:
101
+ if logger:
102
+ logger.warning(f"Failed to download from {url}: {e}")
103
+ continue
104
+
105
+ if not downloaded_zip_path:
106
+ if logger:
107
+ logger.error("Failed to download upgrade.")
108
+ return
109
+
110
+ with zipfile.ZipFile(downloaded_zip_path, 'r') as zip_ref:
111
+ zip_ref.extractall(tmp_dir)
112
+
113
+ new_executable_name = os.path.basename(pyappify_executable)
114
+ found_executable_path = None
115
+ for root, _, files in os.walk(tmp_dir):
116
+ if new_executable_name in files:
117
+ found_executable_path = os.path.join(root, new_executable_name)
118
+ break
119
+
120
+ if not found_executable_path:
121
+ if logger:
122
+ logger.error("Executable not found in zip.")
123
+ return
124
+
125
+ sha256_hash = hashlib.sha256()
126
+ with open(found_executable_path, "rb") as f:
127
+ for byte_block in iter(lambda: f.read(4096), b""):
128
+ sha256_hash.update(byte_block)
129
+
130
+ if sha256_hash.hexdigest() != executable_sha256:
131
+ if logger:
132
+ logger.error("SHA256 checksum mismatch.")
133
+ return
134
+
135
+ kill_pyappify()
136
+ shutil.move(found_executable_path, pyappify_executable)
137
+ except Exception as e:
138
+ if logger:
139
+ logger.error(f"Upgrade failed: {e}")
140
+ finally:
141
+ if os.path.exists(tmp_dir):
142
+ shutil.rmtree(tmp_dir)
143
+
144
+ thread = threading.Thread(target=_do_upgrade)
145
+ thread.daemon = True
146
+ thread.start()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyappify
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: My awesome Python application
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyappify"
7
- version = "0.0.2"
7
+ version = "0.0.4"
8
8
  description = "My awesome Python application"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.7"
File without changes
File without changes
File without changes