From f1eb64c102a31136cfbef6f3d68e8c465414484d Mon Sep 17 00:00:00 2001 From: Felix Rudat Date: Thu, 29 Jan 2026 08:53:36 +0100 Subject: [PATCH] fix: runtime issues with plankapy --- .gitignore | 3 +-- Makefile | 4 +-- planka-cli.spec | 49 +++++++++++++++++++++++++++++++++++++ scripts/pyi_rth_plankapy.py | 28 +++++++++++++++++++++ 4 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 planka-cli.spec create mode 100644 scripts/pyi_rth_plankapy.py diff --git a/.gitignore b/.gitignore index 1203532..28f759b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,5 +28,4 @@ htmlcov/ .idea/ .DS_Store -# PyInstaller -*.spec +# PyInstaller (planka-cli.spec is committed for reproducible builds) diff --git a/Makefile b/Makefile index 0ba17fd..7c9746b 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ run: uv run python scripts/planka_cli.py status build: - uv run pyinstaller --onefile --name planka-cli --collect-all plankapy --collect-submodules rich._unicode_data scripts/planka_cli.py + uv run pyinstaller planka-cli.spec --noconfirm smoke: build @set -e; \ @@ -21,4 +21,4 @@ smoke: build ./dist/planka-cli --help clean: - rm -rf dist build *.spec __pycache__ scripts/__pycache__ + rm -rf dist build __pycache__ scripts/__pycache__ diff --git a/planka-cli.spec b/planka-cli.spec new file mode 100644 index 0000000..86b801f --- /dev/null +++ b/planka-cli.spec @@ -0,0 +1,49 @@ +# -*- mode: python ; coding: utf-8 -*- +from PyInstaller.utils.hooks import collect_submodules +from PyInstaller.utils.hooks import collect_all + +datas = [] +binaries = [] +hiddenimports = ['plankapy.v2', 'plankapy.v2.interface', 'plankapy.v2.models', 'plankapy.v2.api', 'plankapy.v2.utils'] +hiddenimports += collect_submodules('plankapy.v2.models') +hiddenimports += collect_submodules('plankapy.v2.api') +hiddenimports += collect_submodules('rich._unicode_data') +tmp_ret = collect_all('plankapy.v2') +datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] + + +a = Analysis( + ['scripts/planka_cli.py'], + pathex=[], + binaries=binaries, + datas=datas, + hiddenimports=hiddenimports, + hookspath=[], + hooksconfig={}, + runtime_hooks=['scripts/pyi_rth_plankapy.py'], + excludes=['plankapy.v1'], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='planka-cli', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/scripts/pyi_rth_plankapy.py b/scripts/pyi_rth_plankapy.py new file mode 100644 index 0000000..bc79eb2 --- /dev/null +++ b/scripts/pyi_rth_plankapy.py @@ -0,0 +1,28 @@ +# PyInstaller runtime hook: stub out plankapy.v1 to avoid circular import issues +import sys +import types + + +class _DummyPlanka: + """Stub for plankapy.v1.Planka to satisfy root __init__.py""" + + def __init__(self, *args, **kwargs): + raise NotImplementedError( + "plankapy.v1 is not available in this build; use plankapy.v2" + ) + + +class _DummyPasswordAuth: + """Stub for plankapy.v1.PasswordAuth to satisfy root __init__.py""" + + def __init__(self, *args, **kwargs): + raise NotImplementedError( + "plankapy.v1 is not available in this build; use plankapy.v2" + ) + + +# Create a dummy v1 module to satisfy plankapy's root __init__.py +v1_stub = types.ModuleType("plankapy.v1") +v1_stub.Planka = _DummyPlanka +v1_stub.PasswordAuth = _DummyPasswordAuth +sys.modules["plankapy.v1"] = v1_stub