chgksuite_tk 0.0.2b0__py3-none-any.whl → 0.0.3b0__py3-none-any.whl

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.
chgksuite_tk/gui.py CHANGED
@@ -4,11 +4,14 @@ from __future__ import unicode_literals
4
4
 
5
5
  import argparse
6
6
  import os
7
+ import subprocess
7
8
  import sys
9
+ import urllib.request
8
10
 
9
11
  try:
10
12
  import tkinter as tk
11
13
  import tkinter.filedialog as filedialog
14
+ import tkinter.messagebox as messagebox
12
15
  import tkinter.simpledialog as simpledialog
13
16
 
14
17
  TKINTER = True
@@ -31,6 +34,62 @@ from chgksuite.version import __version__
31
34
  from chgksuite.cli import ArgparseBuilder, single_action
32
35
 
33
36
 
37
+ def get_pyapp_executable():
38
+ """Return the pyapp executable path if running inside pyapp, else None."""
39
+ pyapp_env = os.environ.get("PYAPP", "")
40
+ # PYAPP_PASS_LOCATION sets PYAPP to the executable path instead of "1"
41
+ if pyapp_env and pyapp_env != "1" and os.path.isfile(pyapp_env):
42
+ return pyapp_env
43
+ return None
44
+
45
+
46
+ def get_installed_version(package_name):
47
+ """Get installed version of a package."""
48
+ try:
49
+ from importlib.metadata import version
50
+
51
+ return version(package_name)
52
+ except Exception:
53
+ return None
54
+
55
+
56
+ def check_pypi_version(package_name):
57
+ """Get latest version of a package from PyPI."""
58
+ try:
59
+ url = f"https://pypi.org/pypi/{package_name}/json"
60
+ with urllib.request.urlopen(url, timeout=10) as response:
61
+ data = json.loads(response.read().decode())
62
+ return data["info"]["version"]
63
+ except Exception:
64
+ return None
65
+
66
+
67
+ def check_for_updates():
68
+ """Check PyPI for updates to chgksuite and chgksuite-tk. Returns (has_update, details_str, error)."""
69
+ packages = ["chgksuite", "chgksuite-tk"]
70
+ updates = []
71
+
72
+ for pkg in packages:
73
+ installed = get_installed_version(pkg)
74
+ latest = check_pypi_version(pkg)
75
+ if installed is None or latest is None:
76
+ continue
77
+ if installed != latest:
78
+ updates.append((pkg, installed, latest))
79
+
80
+ if updates:
81
+ details = "\n".join(f"{pkg}: {inst} → {lat}" for pkg, inst, lat in updates)
82
+ return True, details, None
83
+
84
+ # No updates - show current versions
85
+ current = ", ".join(
86
+ f"{pkg} {get_installed_version(pkg)}"
87
+ for pkg in packages
88
+ if get_installed_version(pkg)
89
+ )
90
+ return False, current, None
91
+
92
+
34
93
  class InputRequester:
35
94
  """Helper to request input from main thread via Tk dialog."""
36
95
 
@@ -40,7 +99,9 @@ class InputRequester:
40
99
  self.event = threading.Event()
41
100
 
42
101
  def _show_dialog(self, prompt):
43
- self.response = simpledialog.askstring("Input Required", prompt, parent=self.tk_root)
102
+ self.response = simpledialog.askstring(
103
+ "Input Required", prompt, parent=self.tk_root
104
+ )
44
105
  if self.response is None:
45
106
  self.response = ""
46
107
  self.event.set()
@@ -211,6 +272,70 @@ class ParserWrapper(object):
211
272
  else:
212
273
  self.advanced_frame.pack_forget()
213
274
 
275
+ def check_and_update(self):
276
+ """Check for updates and run self-update if available."""
277
+ self.update_button.config(state="disabled", text="Проверка обновлений...")
278
+
279
+ def check_thread():
280
+ has_update, details, error = check_for_updates()
281
+ # Schedule UI update on main thread
282
+ self.tk.after(
283
+ 0, lambda: self._handle_update_check(has_update, details, error)
284
+ )
285
+
286
+ threading.Thread(target=check_thread, daemon=True).start()
287
+
288
+ def _handle_update_check(self, has_update, details, error):
289
+ """Handle update check result on main thread."""
290
+ self.update_button.config(state="normal", text="Обновить chgksuite")
291
+
292
+ if has_update is None or (not has_update and not details):
293
+ messagebox.showwarning(
294
+ "Ошибка",
295
+ "Не удалось проверить обновления. Проверьте подключение к интернету.",
296
+ )
297
+ return
298
+
299
+ if not has_update:
300
+ messagebox.showinfo(
301
+ "Обновления", f"Уже установлена последняя версия.\n\n{details}"
302
+ )
303
+ return
304
+
305
+ # Update available - ask user
306
+ reply = messagebox.askyesno(
307
+ "Доступно обновление",
308
+ f"Доступны обновления:\n{details}\n\n"
309
+ "Обновить сейчас? Приложение будет закрыто.",
310
+ )
311
+
312
+ if reply:
313
+ self._run_self_update()
314
+
315
+ def _run_self_update(self):
316
+ """Run pyapp self-update command and close the application."""
317
+ try:
318
+ # Start the update process detached from current process
319
+ if sys.platform == "win32":
320
+ # On Windows, use CREATE_NEW_PROCESS_GROUP to detach
321
+ subprocess.Popen(
322
+ [self.pyapp_executable, "self", "update"],
323
+ creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
324
+ | subprocess.DETACHED_PROCESS,
325
+ close_fds=True,
326
+ )
327
+ else:
328
+ # On Unix, use start_new_session to detach
329
+ subprocess.Popen(
330
+ [self.pyapp_executable, "self", "update"],
331
+ start_new_session=True,
332
+ close_fds=True,
333
+ )
334
+ # Close the application
335
+ self.tk.quit()
336
+ except Exception as e:
337
+ messagebox.showerror("Ошибка", f"Не удалось запустить обновление: {e}")
338
+
214
339
  def init_tk(self):
215
340
  self.tk = tk.Tk()
216
341
  self.tk.title("chgksuite v{}".format(__version__))
@@ -247,13 +372,28 @@ class ParserWrapper(object):
247
372
  # Output text widget
248
373
  self.output_frame = tk.Frame(self.mainframe)
249
374
  self.output_frame.pack(side="top", fill="both", expand=True, pady=10)
250
- self.output_text = tk.Text(self.output_frame, height=10, width=70, font=("Courier", 10))
251
- self.output_scrollbar = tk.Scrollbar(self.output_frame, command=self.output_text.yview)
375
+ self.output_text = tk.Text(
376
+ self.output_frame, height=10, width=70, font=("Courier", 10)
377
+ )
378
+ self.output_scrollbar = tk.Scrollbar(
379
+ self.output_frame, command=self.output_text.yview
380
+ )
252
381
  self.output_text.configure(yscrollcommand=self.output_scrollbar.set)
253
382
  self.output_text.pack(side="left", fill="both", expand=True)
254
383
  self.output_scrollbar.pack(side="right", fill="y")
255
384
  self.output_text.config(state="disabled")
256
385
 
386
+ # Update button (only shown when running inside pyapp)
387
+ self.pyapp_executable = get_pyapp_executable()
388
+ if self.pyapp_executable:
389
+ self.update_button = tk.Button(
390
+ self.mainframe,
391
+ text="Обновить chgksuite",
392
+ command=self.check_and_update,
393
+ width=20,
394
+ )
395
+ self.update_button.pack(side="top", pady=5)
396
+
257
397
  def add_argument(self, *args, **kwargs):
258
398
  if kwargs.pop("advanced", False):
259
399
  frame = self.advanced_frame
chgksuite_tk/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.0.2b0"
1
+ __version__ = "0.0.3b0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chgksuite_tk
3
- Version: 0.0.2b0
3
+ Version: 0.0.3b0
4
4
  Summary: A GUI wrapper for chgksuite using tkinter
5
5
  Author-email: Alexander Pecheny <ap@pecheny.me>
6
6
  License-Expression: MIT
@@ -0,0 +1,15 @@
1
+ chgksuite_tk/__main__.py,sha256=Da4F7YuRwygswPriZaDJE0VmJCtERNA9oXG_OW1xPyE,143
2
+ chgksuite_tk/gui.py,sha256=JNSYLBUziXJAktWiKEJVSGOxnLLwB4Bh1V2qHOndNYg,19293
3
+ chgksuite_tk/version.py,sha256=mBnMYfxg52DfwMea2Iskot56mAShybAVXEQQkyRqxKc,24
4
+ chgksuite_tk-0.0.3b0.dist-info/licenses/LICENSE,sha256=u8H6CkkghnAGkqpks_lKx1ZCuLfPj3Wcs70HS29Wi4Y,1074
5
+ chgksuite_tk-0.0.3b0.dist-info/._PKG-INFO,sha256=9hfxnKhlz0AhPf2RDy1ursI9aFfrZ9KVhb4hqssJRyE,4096
6
+ chgksuite_tk-0.0.3b0.dist-info/._SOURCES.txt,sha256=JpjCqSfETkikUXy0dxxg1nwdODFvI47pQ7gtkyycFUA,4096
7
+ chgksuite_tk-0.0.3b0.dist-info/._dependency_links.txt,sha256=oPBPTt_nNayPWNXs9i2UOSrfH_6zOSwpz4xROgaMoZ0,4096
8
+ chgksuite_tk-0.0.3b0.dist-info/._entry_points.txt,sha256=DQoWirPOlazFqDCa9isiAHuKDNqCjm2J2Zty1NSiiRo,4096
9
+ chgksuite_tk-0.0.3b0.dist-info/._requires.txt,sha256=M8Rs0Z3G0BnzDXCMYI_YsqwOe1ESTqITke-ffGFPQI8,4096
10
+ chgksuite_tk-0.0.3b0.dist-info/._top_level.txt,sha256=ArlFn1aVwLS4LLpBo1fLnG0QjpbTsxNEuLenOjTdRjg,4096
11
+ chgksuite_tk-0.0.3b0.dist-info/METADATA,sha256=LQb02_iun1jgWj1UBlPnVonlScjw2Kmy4oy0Xg589UM,550
12
+ chgksuite_tk-0.0.3b0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
13
+ chgksuite_tk-0.0.3b0.dist-info/entry_points.txt,sha256=89cXXBf7_WslybKh16vAx4kuf15qE0QMTigRb_V82xo,53
14
+ chgksuite_tk-0.0.3b0.dist-info/top_level.txt,sha256=KBLwuBeg1TUEBwNzpQoRrBXDYYdRnp16mc93VPwTQBk,13
15
+ chgksuite_tk-0.0.3b0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,15 +0,0 @@
1
- chgksuite_tk/__main__.py,sha256=Da4F7YuRwygswPriZaDJE0VmJCtERNA9oXG_OW1xPyE,143
2
- chgksuite_tk/gui.py,sha256=7GMfk-Ag9g7BmgXCgKHHIr9gINi7GRaP8ewONT6svoo,14301
3
- chgksuite_tk/version.py,sha256=HSIvRR5bDp7ZB-GCVG4s1osWGFbXVGQAektEhEkRFTI,24
4
- chgksuite_tk-0.0.2b0.dist-info/licenses/LICENSE,sha256=u8H6CkkghnAGkqpks_lKx1ZCuLfPj3Wcs70HS29Wi4Y,1074
5
- chgksuite_tk-0.0.2b0.dist-info/._PKG-INFO,sha256=9hfxnKhlz0AhPf2RDy1ursI9aFfrZ9KVhb4hqssJRyE,4096
6
- chgksuite_tk-0.0.2b0.dist-info/._SOURCES.txt,sha256=JpjCqSfETkikUXy0dxxg1nwdODFvI47pQ7gtkyycFUA,4096
7
- chgksuite_tk-0.0.2b0.dist-info/._dependency_links.txt,sha256=oPBPTt_nNayPWNXs9i2UOSrfH_6zOSwpz4xROgaMoZ0,4096
8
- chgksuite_tk-0.0.2b0.dist-info/._entry_points.txt,sha256=DQoWirPOlazFqDCa9isiAHuKDNqCjm2J2Zty1NSiiRo,4096
9
- chgksuite_tk-0.0.2b0.dist-info/._requires.txt,sha256=M8Rs0Z3G0BnzDXCMYI_YsqwOe1ESTqITke-ffGFPQI8,4096
10
- chgksuite_tk-0.0.2b0.dist-info/._top_level.txt,sha256=ArlFn1aVwLS4LLpBo1fLnG0QjpbTsxNEuLenOjTdRjg,4096
11
- chgksuite_tk-0.0.2b0.dist-info/METADATA,sha256=Ew3eP-CzxKxDj9niAhVkILj6Ke0_AlURQpdKs0YIxeE,550
12
- chgksuite_tk-0.0.2b0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
- chgksuite_tk-0.0.2b0.dist-info/entry_points.txt,sha256=89cXXBf7_WslybKh16vAx4kuf15qE0QMTigRb_V82xo,53
14
- chgksuite_tk-0.0.2b0.dist-info/top_level.txt,sha256=KBLwuBeg1TUEBwNzpQoRrBXDYYdRnp16mc93VPwTQBk,13
15
- chgksuite_tk-0.0.2b0.dist-info/RECORD,,