pyship 0.4.0__py3-none-any.whl → 0.4.2__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.
pyship/clip.py CHANGED
@@ -60,8 +60,8 @@ def create_base_clip(target_app_info: AppInfo, app_dir: Path, cache_dir: Path) -
60
60
  pyship_print(f'building clip {clip_dir_name} ("{clip_dir}")')
61
61
 
62
62
  uv_path = find_or_bootstrap_uv(cache_dir)
63
- uv_python_install(uv_path, python_version)
64
- uv_venv_create(uv_path, clip_dir, python_version)
63
+ python_path = uv_python_install(uv_path, python_version)
64
+ uv_venv_create(uv_path, clip_dir, str(python_path))
65
65
 
66
66
  return clip_dir
67
67
 
pyship/create_launcher.py CHANGED
@@ -16,6 +16,63 @@ from pyship.launcher_stub import compile_launcher_stub
16
16
  log = get_logger(launcher_application_name)
17
17
 
18
18
 
19
+ @typechecked
20
+ def _write_diagnostic_bat(app_name: str, bat_path: Path):
21
+ """
22
+ Write a diagnostic .bat file that runs the launcher script with python.exe (not pythonw.exe)
23
+ so that all console output is visible for troubleshooting.
24
+ :param app_name: target application name
25
+ :param bat_path: path where the .bat file will be written
26
+ """
27
+ bat_content = f"""@echo off
28
+ REM Diagnostic launcher for {app_name}
29
+ REM Runs the launcher script with python.exe (console) so output is always visible.
30
+
31
+ setlocal
32
+
33
+ set "LAUNCHER_DIR=%~dp0"
34
+ REM Remove trailing backslash
35
+ if "%LAUNCHER_DIR:~-1%"=="\\" set "LAUNCHER_DIR=%LAUNCHER_DIR:~0,-1%"
36
+
37
+ REM app_dir is the parent of launcher_dir
38
+ for %%I in ("%LAUNCHER_DIR%") do set "APP_DIR=%%~dpI"
39
+ if "%APP_DIR:~-1%"=="\\" set "APP_DIR=%APP_DIR:~0,-1%"
40
+
41
+ REM Find the latest CLIP directory containing Scripts\\python.exe
42
+ set "PYTHON_EXE="
43
+ for /d %%D in ("%APP_DIR%\\{app_name}_*") do (
44
+ if exist "%%D\\Scripts\\python.exe" (
45
+ set "PYTHON_EXE=%%D\\Scripts\\python.exe"
46
+ )
47
+ )
48
+
49
+ if not defined PYTHON_EXE (
50
+ echo ERROR: No Python environment found for {app_name} in %APP_DIR%
51
+ pause
52
+ exit /b 1
53
+ )
54
+
55
+ echo Using Python: %PYTHON_EXE%
56
+ echo Running: %PYTHON_EXE% "%LAUNCHER_DIR%\\{app_name}_launcher.py" --app-dir "%APP_DIR%" %*
57
+ echo.
58
+
59
+ "%PYTHON_EXE%" "%LAUNCHER_DIR%\\{app_name}_launcher.py" --app-dir "%APP_DIR%" %*
60
+
61
+ set "EXIT_CODE=%ERRORLEVEL%"
62
+ echo.
63
+ echo Exit code: %EXIT_CODE%
64
+ if not "%EXIT_CODE%"=="0" (
65
+ echo.
66
+ echo ERROR: {app_name} exited with code %EXIT_CODE%
67
+ pause
68
+ )
69
+
70
+ endlocal
71
+ exit /b %EXIT_CODE%
72
+ """
73
+ bat_path.write_text(bat_content, encoding="utf-8")
74
+
75
+
19
76
  @typechecked
20
77
  def create_pyship_launcher(target_app_info: AppInfo, app_path_output: Path):
21
78
  """
@@ -69,13 +126,18 @@ def create_pyship_launcher(target_app_info: AppInfo, app_path_output: Path):
69
126
  shutil.copy2(str(standalone_source), str(standalone_dest))
70
127
  log.info(f"copied launcher script to {standalone_dest}")
71
128
 
72
- # 3. Copy the icon alongside
129
+ # 3. Generate diagnostic .bat launcher (always uses python.exe for console output)
130
+ bat_path = Path(launcher_dir, f"{target_app_info.name}.bat")
131
+ _write_diagnostic_bat(target_app_info.name, bat_path)
132
+ log.info(f"wrote diagnostic bat to {bat_path}")
133
+
134
+ # 4. Copy the icon alongside
73
135
  if icon_path.exists():
74
136
  icon_dest = Path(launcher_dir, f"{target_app_info.name}.ico")
75
137
  shutil.copy2(str(icon_path), str(icon_dest))
76
138
  log.info(f"copied icon to {icon_dest}")
77
139
 
78
- # 4. Store metadata for cache invalidation
140
+ # 5. Store metadata for cache invalidation
79
141
  store_metadata(app_path_output, metadata_filename, metadata)
80
142
 
81
143
  if launcher_exe_path.exists():
@@ -241,6 +241,27 @@ def launch(app_dir=None, additional_path=None):
241
241
  std_out = target_process.stdout
242
242
  std_err = target_process.stderr
243
243
 
244
+ # When pythonw.exe fails silently (no stderr), re-run with python.exe to capture the actual error
245
+ if is_gui and return_code not in (OK_RETURN_CODE, RESTART_RETURN_CODE) and not (std_err and std_err.strip()):
246
+ log.warning(f"pythonw.exe exited with return_code={return_code} but produced no error output, re-running with python.exe for diagnostics")
247
+ diag_python = Path(versions[latest_version], "Scripts", "python.exe")
248
+ if diag_python.exists():
249
+ diag_cmd = [str(diag_python), "-X", "faulthandler"] + cmd[1:]
250
+ log.info(f"diagnostic cmd={diag_cmd}")
251
+ try:
252
+ diag_process = subprocess.run(diag_cmd, cwd=str(python_exe_path.parent), capture_output=True, text=True)
253
+ diag_return_code = diag_process.returncode
254
+ std_out = diag_process.stdout
255
+ std_err = diag_process.stderr
256
+ if std_err and std_err.strip():
257
+ log.info(f"diagnostic stderr captured (return_code={diag_return_code})")
258
+ elif std_out and std_out.strip():
259
+ log.info(f"diagnostic stdout captured (return_code={diag_return_code})")
260
+ else:
261
+ log.warning(f"diagnostic re-run with python.exe also produced no output (return_code={diag_return_code})")
262
+ except Exception as diag_e:
263
+ log.error(f"diagnostic re-run failed: {diag_e}")
264
+
244
265
  if (std_err and std_err.strip()) or (return_code != OK_RETURN_CODE and return_code != RESTART_RETURN_CODE):
245
266
  if std_out and std_out.strip():
246
267
  log.warning(std_out)
pyship/uv_util.py CHANGED
@@ -92,17 +92,24 @@ def uv_python_install(uv_path: Path, python_version: str) -> Path:
92
92
 
93
93
 
94
94
  @typechecked
95
- def uv_venv_create(uv_path: Path, venv_dir: Path, python_version: str) -> None:
95
+ def uv_venv_create(uv_path: Path, venv_dir: Path, python_version_or_path: str) -> None:
96
96
  """
97
97
  Create a relocatable venv using uv.
98
98
  :param uv_path: path to uv executable
99
99
  :param venv_dir: destination directory for the venv
100
- :param python_version: Python version string
100
+ :param python_version_or_path: Python version string (e.g. "3.11") or path to Python executable
101
101
  """
102
102
  pyship_print(f'creating relocatable venv at "{venv_dir}"')
103
- cmd = [str(uv_path), "venv", "--relocatable", "--python", python_version, str(venv_dir)]
103
+ cmd = [str(uv_path), "venv", "--relocatable", "--clear", "--python", python_version_or_path, str(venv_dir)]
104
104
  log.info(f"uv venv cmd: {cmd}")
105
- subprocess.run(cmd, check=True, capture_output=True, text=True)
105
+ result = subprocess.run(cmd, capture_output=True, text=True)
106
+ if result.stdout:
107
+ log.info(result.stdout)
108
+ if result.stderr:
109
+ log.info(result.stderr)
110
+ if result.returncode != 0:
111
+ log.error(f"uv venv failed (exit {result.returncode}): {result.stderr}")
112
+ result.check_returncode()
106
113
 
107
114
 
108
115
  @typechecked
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyship
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: freezer, installer and updater for Python applications
5
5
  Author-email: abel <j@abel.co>
6
6
  License: MIT
@@ -3,10 +3,10 @@ pyship/__main__.py,sha256=KtAdk7BCWhXbhywlFB8P4HbvypVkqJXbxgMW3XVD-To,84
3
3
  pyship/__version__.py,sha256=y-oqerPvrMS7jU7JSdHdUyKkSxJWA0anyoCQCfQ3INQ,502
4
4
  pyship/app_info.py,sha256=UTWD4ol226sNAAYsiByMJswIIL1lN8nx96PpD43YQG4,6866
5
5
  pyship/arguments.py,sha256=p4cA8FwbNSZqg4XI6LsYit1QN7TpAWWZH2xrgLf-f-g,1882
6
- pyship/clip.py,sha256=N6es31zy0l3kakf1Enxt2fqkcMQoaUSXMlcCqhHJdWI,3700
6
+ pyship/clip.py,sha256=9RGqXSYGmR89T8ng6f9fDkhy61_aytRvMcXKp3yh6Yo,3716
7
7
  pyship/cloud.py,sha256=k8m-254Akpp3NALeP0pJzFs21_2qZmmK0GHfSC-Z0sw,1282
8
8
  pyship/constants.py,sha256=Y-yA_MMwL572UbZqmhILrJL6NH9xK3q5jELJR6atw7I,243
9
- pyship/create_launcher.py,sha256=2wyEmB7Xe-CwpTi8qfpSE6ki0iO6hw1HkVq0GrM0CYs,3783
9
+ pyship/create_launcher.py,sha256=vg2vsyeQlxsmVNVlgO1KVtbtacUTwJG8pWZkUf35jmQ,5771
10
10
  pyship/download.py,sha256=QHbdVwxLNBToMEC0tOF2ZquDpoydRu0-cj7LOERr5Q4,2460
11
11
  pyship/launcher_stub.py,sha256=3yC1EKk45m4GOJ_uat1OWKUFqgAWdcpfQZKh7qhflnk,6889
12
12
  pyship/logging.py,sha256=cIB7487tN8TsKeDHwwzjA30rHRW5Ci5GA5uPbaEXaY0,966
@@ -20,15 +20,15 @@ pyship/pyship_exceptions.py,sha256=teUOh3FuRUU9hyv7L4owACQZPWNdwpYTEz6l-Ao35nw,9
20
20
  pyship/pyship_get_icon.py,sha256=BQp_xYl8CXt2e7nDB0llSxr0hbP7to2fkQqPeu8WpIg,2050
21
21
  pyship/pyship_path.py,sha256=RpU2n7pWXTr0501S7U8KxWCpBc8jOqKPuaX0X6IWPI8,262
22
22
  pyship/pyship_subprocess.py,sha256=hH4MW_j2zLJLDmLDkkl2JWupXrvSemAeCPAEtPdSGyk,3212
23
- pyship/uv_util.py,sha256=vGvaR9Uj7MGAhc5mS1q8LpoM9ctetQwkYQCZS7rwyWM,5654
23
+ pyship/uv_util.py,sha256=sAofeT4I9Xs__UW9w3sY2r9b_lLrfuZmOomxVLXdikE,5990
24
24
  pyship/launcher/__init__.py,sha256=25vVghziYIHDBA0mCaGqhj6hWxxjQqlm4LrY0Hem0YY,245
25
25
  pyship/launcher/__main__.py,sha256=KhFSf1RU5Cj15y0c4FlzvIvDpWWi9NKYy0gzJ-w7KQE,115
26
26
  pyship/launcher/hash.py,sha256=THEh8G-StEJeh5tH24RnAQpYB0Zv1nnBwqOoStN6_NY,1153
27
- pyship/launcher/launcher.py,sha256=1HIXieq17IQFuldBAkmo7tjpsjADQVw7R8zXXQpEMXs,10654
27
+ pyship/launcher/launcher.py,sha256=FNUNApE2L9Ol7JISwTxFi2mK_eHBBTSOcOpkPyQkwG4,12422
28
28
  pyship/launcher/metadata.py,sha256=PnOkYLQf6NYvPiZWhf0LAUjmFWzURKWriRQJSy3T-x4,1969
29
29
  pyship/launcher/restart_monitor.py,sha256=jfzchLxGuC_xUNdPAr849FhAdozJ6BX9M-gqLd-gGIA,952
30
- pyship-0.4.0.dist-info/licenses/LICENSE,sha256=vfTkV97IHvr2g_I1pGQg2bRYT05ktYYgaPwBDKNRv98,1093
31
- pyship-0.4.0.dist-info/METADATA,sha256=qxJGV9jequ_Q_68h0pV1aRiuYACDn6h-Ec9bmA_JH5I,2513
32
- pyship-0.4.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
33
- pyship-0.4.0.dist-info/top_level.txt,sha256=mlozeft-UInVAceSajzNvtkn2vPa8El9j0RulsTVtlU,7
34
- pyship-0.4.0.dist-info/RECORD,,
30
+ pyship-0.4.2.dist-info/licenses/LICENSE,sha256=vfTkV97IHvr2g_I1pGQg2bRYT05ktYYgaPwBDKNRv98,1093
31
+ pyship-0.4.2.dist-info/METADATA,sha256=lI2OnHEw5uFnXUBi1inlIkPtYfraEQrGC-YGhR7adNc,2513
32
+ pyship-0.4.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
33
+ pyship-0.4.2.dist-info/top_level.txt,sha256=mlozeft-UInVAceSajzNvtkn2vPa8El9j0RulsTVtlU,7
34
+ pyship-0.4.2.dist-info/RECORD,,
File without changes