Skip to content

Commit

Permalink
modified init in main package for pyinstaller compatibility, added sp…
Browse files Browse the repository at this point in the history
…ec for pyinstaller, moved and renamed main files, added github action for exe generation
  • Loading branch information
Samuel Hoermann committed Nov 29, 2024
1 parent 4a5a391 commit 681dbb5
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 51 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/pyinstaller.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: PyInstaller
on:
push:
branches:
- main
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup python
uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: 'pip' # caching pip dependencies
- name: Install dependencies
run: pip install -r requirements.txt
- name: Build executable
run: |
pyinstaller src/lasercontrol.spec
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: lasercontrol.exe
path: dist/lasercontrol.exe
- name: Build executable scope
run: |
pyinstaller src/lasercontrol_scope.spec
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: lasercontrol_scope.exe
path: dist/lasercontrol_scope.exe
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ MANIFEST
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
Expand Down
14 changes: 8 additions & 6 deletions LaserConfig.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# - Configuration file stored 2024-07-30 12:55:54.088188 -
# - Configuration file stored 2024-11-28 16:28:24.693820 -
LaserConfig: #!!python/object:controller.LaserConfig
wl_sweep_start: 857 # wl_sweep_start: None
wl_sweep_stop: 870 # wl_sweep_stop: None
velocity: 1.0 # velocity: None
acceleration: 1.0 # acceleration: None
deceleration: 2.0 # deceleration: None
epos_dll: "@Path:<C:/Users/samue/git/PySacherECLControl/src/SacherECLControl/libs/SacherLib/PythonMotorControlClass/EposCmd64.dll>" # epos_dll: None
motor_control_pyd: "@Path:<C:/Users/samue/git/PySacherECLControl/src/SacherECLControl/libs/SacherLib/PythonMotorControlClass/lib/Python312/SacherMotorControl.pyd>" # motor_control_pyd: None
wl_sweep_start: 845 # wl_sweep_start: None
wl_sweep_stop: 855 # wl_sweep_stop: None
velocity: 1.6540566248074888 # velocity: None
acceleration: 1.9904737652227005 # acceleration: None
deceleration: 1.9904737652227005 # deceleration: None
available_ports: ['USB0', 'USB1', 'USB2', 'USB3', 'USB4', 'USB5', 'USB6', 'USB7', 'USB8', 'USB9'] # available_ports: None
port: "USB0" # port: None
8 changes: 0 additions & 8 deletions examples/CaptDeviceConfig.yaml

This file was deleted.

11 changes: 0 additions & 11 deletions examples/LaserConfig.yaml

This file was deleted.

45 changes: 30 additions & 15 deletions src/SacherECLControl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
import ctypes
import os
import pathlib
import shutil
from pathlib import Path
import sys

from WidgetCollection.Tools.PyProjectExtractor import extract_pyproject_info

from . import Helpers

sys.path.append(os.path.join(os.path.dirname(__file__), '../'))


def toml_exists(path: Path):
return (path / 'pyproject.toml').exists()

def resolve_path(path):
if getattr(sys, "frozen", False):
# If the 'frozen' flag is set, we are in bundled-app mode!
p = Path(sys._MEIPASS) / path
else:
# Normal development mode. Use os.getcwd() or __file__ as appropriate in your case...
p = path
return p.resolve()

def get_pyprojecttoml() -> Path:
# is found in ../../pyconfig.toml
pytoml_via_git = resolve_path(Path('../..'))
if toml_exists(pytoml_via_git):
return pytoml_via_git
pytoml_via_pip = resolve_path(Path('.'))
if toml_exists(pytoml_via_pip):
return pytoml_via_pip
return resolve_path(Path(__file__))

# ======================================================================================================================
# The pyconfig.toml file is needed, to get the metadata. Depending on the installation method (pip or git) the file
# is found in different places.
# ======================================================================================================================
pytoml = Helpers.get_pyprojecttoml()
pytoml = get_pyprojecttoml()

def try_and_set(func, *args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Error reading '{args[1]}' from {pathlib.Path(args[0])}: {e}")
print(f"Error reading '{args[1]}' from {Path(args[0])}: {e}")
return "unknown"

__rootdir__ = os.path.dirname(os.path.realpath(__file__))
__version__ = try_and_set(extract_pyproject_info, pytoml.parent, "version")
__author__ = try_and_set(extract_pyproject_info, pytoml.parent, "author")
__description__ = try_and_set(extract_pyproject_info, pytoml.parent, "description")
__license__ = try_and_set(extract_pyproject_info, pytoml.parent, "license")
__url__ = try_and_set(extract_pyproject_info, pytoml.parent, "url")
__version__ = try_and_set(extract_pyproject_info, pytoml, "version")
__author__ = try_and_set(extract_pyproject_info, pytoml, "author")
__description__ = try_and_set(extract_pyproject_info, pytoml, "description")
__license__ = try_and_set(extract_pyproject_info, pytoml, "license")
__url__ = try_and_set(extract_pyproject_info, pytoml, "url")

# For correctly display the icon in the taskbar
myappid = f'agentsmith29.SacherECLControl.{__version__}' # arbitrary string
Expand Down
3 changes: 2 additions & 1 deletion examples/main.py → src/lasercontrol.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import logging
import os
import pathlib
from pathlib import Path
import sys
from PySide6.QtWidgets import QApplication
from rich.logging import RichHandler
from multiprocessing import freeze_support

sys.path.append('../src')
import SacherECLControl as Laser

if __name__ == "__main__":
freeze_support()
FORMAT = "%(name)s %(message)s"
logging.basicConfig(
level="DEBUG", format=FORMAT, datefmt="[%X]", handlers=[
Expand Down
40 changes: 40 additions & 0 deletions src/lasercontrol.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- mode: python ; coding: utf-8 -*-


a = Analysis(
['lasercontrol.py'],
pathex=[],
binaries=[],
datas=[('../pyproject.toml', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
onefile=True,
windowed=True,
)
pyz = PYZ(a.pure)

exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='lasercontrol',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
25 changes: 16 additions & 9 deletions examples/Main_ADScope.py → src/lasercontrol_scope.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import logging
import sys
import os
import pathlib
from multiprocessing import Value
from pathlib import Path
from multiprocessing import Value, freeze_support

from rich.logging import RichHandler
from PySide6.QtWidgets import QApplication
Expand All @@ -16,6 +16,7 @@
import SacherECLControl as Laser

if __name__ == "__main__":
freeze_support()
FORMAT = "%(name)s %(message)s"
logging.basicConfig(
level="DEBUG", format=FORMAT, datefmt="[%X]", handlers=[
Expand All @@ -28,24 +29,30 @@
else:
app = QApplication.instance()

conf_capt_dev = captdev.Config()
#conf_capt_dev.load("CaptDeviceConfig.yaml")
conf_capt_dev.autosave()

capt_conf = captdev.Config()
capt_conf_file = Path('./CaptDeviceConfig.yaml')
if capt_conf_file.exists():
capt_conf.load(capt_conf_file, as_auto_save=True)
capt_conf.autosave(enable=True, path='./')

start_capture_flag = Value('i', 0)

capt_dev_model = captdev.Model(conf_capt_dev)
capt_dev_model = captdev.Model(capt_conf)
capt_dev_controller = captdev.Controller(capt_dev_model, start_capture_flag)
capt_dev_window = captdev.View(capt_dev_model, capt_dev_controller)


conf = Laser.Config()
conf_file = Path('./LaserConfig.yaml')
if conf_file.exists():
conf.load(conf_file, as_auto_save=True)
conf.autosave(True, './')

# Set the path to the EposCmd64.dll and the SacherMotorControl.pyd
conf.epos_dll.set(pathlib.Path(
conf.epos_dll.set(Path(
f'{Laser.__rootdir__}/libs/SacherLib/PythonMotorControlClass/EposCmd64.dll'))

conf.motor_control_pyd.set(pathlib.Path(
conf.motor_control_pyd.set(Path(
f'{Laser.__rootdir__}/libs/SacherLib/PythonMotorControlClass/'
f'lib/Python312/SacherMotorControl.pyd'))

Expand Down
40 changes: 40 additions & 0 deletions src/lasercontrol_scope.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- mode: python ; coding: utf-8 -*-


a = Analysis(
['lasercontrol_scope.py'],
pathex=[],
binaries=[],
datas=[('../pyproject.toml', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
onefile=True,
windowed=True,
)
pyz = PYZ(a.pure)

exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='lasercontrol_scope',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

0 comments on commit 681dbb5

Please sign in to comment.