diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 0da59d810..620903ac8 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -25,7 +25,7 @@ jobs: platforms: all - name: Build ${{ matrix.os }} wheels - uses: pypa/cibuildwheel@v2.21.3 + uses: pypa/cibuildwheel@v2.22.0 env: # we only support what's supported by wxPython, therefore we skip: # * PyPy Python implementation diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1e8f32630..10a24df72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,20 +9,21 @@ on: jobs: functional_test: name: Functional testing with Python ${{ matrix.python-version }} - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.11", "3.13"] include: - python-version: "3.8" - wxpython-wheel: "ubuntu-22.04/wxPython-4.2.1-cp38-cp38-linux_x86_64.whl" - - python-version: "3.9" - wxpython-wheel: "ubuntu-22.04/wxPython-4.2.1-cp39-cp39-linux_x86_64.whl" - - python-version: "3.10" - wxpython-wheel: "ubuntu-22.04/wxPython-4.2.1-cp310-cp310-linux_x86_64.whl" + os: "ubuntu-20.04" + wxpython-wheel: "ubuntu-20.04/wxPython-4.2.0-cp38-cp38-linux_x86_64.whl" - python-version: "3.11" + os: "ubuntu-22.04" wxpython-wheel: "ubuntu-22.04/wxPython-4.2.1-cp311-cp311-linux_x86_64.whl" + - python-version: "3.13" + os: "ubuntu-24.04" + wxpython-wheel: "ubuntu-24.04/wxPython-4.2.2-cp313-cp313-linux_x86_64.whl" steps: - uses: actions/checkout@v4 @@ -56,7 +57,7 @@ jobs: fail-fast: false matrix: # Unit testing uses functions not available on Python < 3.11 - python-version: ["3.11", "3.12", "3.13"] + python-version: ["3.11", "3.13", "3.14"] steps: - uses: actions/checkout@v4 diff --git a/printrun/pronterface.py b/printrun/pronterface.py index d37b8d051..914ad3257 100644 --- a/printrun/pronterface.py +++ b/printrun/pronterface.py @@ -81,21 +81,23 @@ def format_length(mm, fractional=2): return '%%.%df' % fractional % units + suffix class ConsoleOutputHandler: - """Handle console output. All messages go through the logging submodule. We setup a logging handler to get logged messages and write them to both stdout (unless a log file path is specified, in which case we add another logging handler to write to this file) and the log panel. - We also redirect stdout and stderr to ourself to catch print messages and al.""" + """Handle console output. All messages go through the logging submodule. We + setup a logging handler to get logged messages and write them to both + stdout (unless a log file path is specified, in which case we add another + logging handler to write to this file) and the log panel. We also redirect + stdout and stderr to ourselves to catch print messages et al.""" - def __init__(self, target, log_path): + def __init__(self, target, log_path, log_stdout): self.stdout = sys.stdout self.stderr = sys.stderr sys.stdout = self sys.stderr = self - self.print_on_stdout = not log_path - if log_path: - setup_logging(self, log_path, reset_handlers = True) - else: - setup_logging(sys.stdout, reset_handlers = True) + + self.print_on_stdout = log_stdout or not log_path self.target = target + setup_logging(self, log_path, reset_handlers=True) + def __del__(self): sys.stdout = self.stdout sys.stderr = self.stderr @@ -103,13 +105,15 @@ def __del__(self): def write(self, data): try: self.target(data) - except: - pass + except Exception as e: + # This shouldn't generally happen, unless there is something very wrong with the code + self.stderr.write(_("An exception occurred during an attempt to log a message: {}").format(e)) + if self.print_on_stdout: self.stdout.write(data) def flush(self): - if self.stdout: + if self.print_on_stdout: self.stdout.flush() class PronterWindow(MainWindow, pronsole.pronsole): @@ -223,7 +227,7 @@ def __init__(self, app, filename = None, size = winsize): self.statusbar = self.CreateStatusBar() self.statusbar.SetStatusText(_("Not connected to printer.")) - self.t = ConsoleOutputHandler(self.catchprint, self.settings.log_path) + self.t = ConsoleOutputHandler(self.catchprint, self.settings.log_path, self.settings.log_stdout) self.stdout = sys.stdout self.slicing = False self.loading_gcode = False diff --git a/printrun/settings.py b/printrun/settings.py index 2adf6c4f8..9afceeb2a 100644 --- a/printrun/settings.py +++ b/printrun/settings.py @@ -409,7 +409,9 @@ def __init__(self, root): self._add(StringSetting("start_command", "", _("Start Command:"), _("Executable to run when the print is started"), "External")) self._add(StringSetting("final_command", "", _("Final Command:"), _("Executable to run when the print is finished"), "External")) self._add(StringSetting("error_command", "", _("Error Command:"), _("Executable to run when an error occurs"), "External")) - self._add(DirSetting("log_path", str(Path.home()), _("Log Path:"), _("Path to the log file. An empty path will log to the console."), "UI")) + self._add(DirSetting("log_path", str(Path.home()), _("Log Path:"), + _("Path to the log file. If the path is a directory the file will be named 'printrun.log'"), "UI")) + self._add(BooleanSetting("log_stdout", False, _("Log to console:"), _("Duplicate log messages to stdout"), "UI")) self._add(HiddenSetting("project_offset_x", 0.0)) self._add(HiddenSetting("project_offset_y", 0.0))