-
Notifications
You must be signed in to change notification settings - Fork 12
Flip/rotation operations crash or hang in stand-alone (PyInstaller) version #304
Description
Describe the bug
In the stand-alone Windows version of DataLab (built with PyInstaller), image flip and rotation operations ("Flip horizontally", "Flip vertically", "Rotate 90° left/right", "Flip diagonally") either crash with an unhandled exception or hang indefinitely (the progress dialog with the Cancel button stays open and nothing happens).
This does not affect the Python package version of DataLab — only the frozen stand-alone executable.
To Reproduce
- Launch the stand-alone version of DataLab (
DataLab_v1) - Create a ramp image (or any image)
- Open the Processing menu (or Operations menu)
- Select Flip horizontally (or any flip/rotation operation)
- The application either:
- Shows an error dialog with the traceback below, or
- Hangs with the progress/cancel dialog open indefinitely (the computation never completes)
Expected behavior
The image should be flipped/rotated and the result displayed normally, as it does in the Python package version.
Error traceback
Traceback (most recent call last):
File "multiprocessing\process.py", line 313, in _bootstrap
File "multiprocessing\process.py", line 108, in run
File "multiprocessing\pool.py", line 114, in worker
File "multiprocessing\queues.py", line 387, in get
File "pyimod02_importers.py", line 457, in exec_module
File "datalab\gui\processor\image.py", line 34, in <module>
ImportError: cannot import name 'BaseProcessor' from partially initialized module
'datalab.gui.processor.base' (most likely due to a circular import)
(C:\Program Files (x86)\DataLab_v1\_internal\datalab\gui\processor\base.py)
A secondary error also appears during the application's error logging:
Traceback (most recent call last):
File "start.pyw", line 26, in <module>
...
File "datalab\gui\processor\base.py", line 231, in <module>
File "pyi_rth_multiprocessing.py", line 48, in _freeze_support
File "multiprocessing\spawn.py", line 122, in spawn_main
File "multiprocessing\process.py", line 326, in _bootstrap
AttributeError: 'NoneType' object has no attribute 'write'
Screenshots
Root cause analysis
Flip and rotation operations are the only image operations wrapped in a GeometricTransformWrapper class (defined in datalab/gui/processor/image.py), which applies geometry metadata transformations after the image data transformation. This wrapper is pickled and sent to the multiprocessing worker process.
In the PyInstaller frozen executable, when the worker process unpickles GeometricTransformWrapper, Python must import the module where the class is defined (datalab.gui.processor.image). This module imports BaseProcessor from datalab.gui.processor.base, which triggers the full DataLab GUI import chain inside the worker process. This causes:
- A circular import error because
base.pyis only partially initialized at that point multiprocessing.freeze_support()being called at module level inbase.pyduring the child process bootstrap, causing theAttributeError: 'NoneType' object has no attribute 'write'- In some configurations, the worker process crashes silently and the main process hangs indefinitely waiting for a result that will never come
Other processing operations (e.g., filters, normalization, FFT) are not affected because they are registered as plain Sigima functions that only require importing sigima.proc.image in the worker — a pure computation module with no DataLab GUI dependencies.
Fix
The fix involves moving GeometricTransformWrapper and apply_geometry_transform to a new standalone module (datalab/gui/processor/geometry_postprocess.py) that has no dependency on BaseProcessor, Qt, or PlotPy. When the worker unpickles the wrapper, it now only imports this lightweight module instead of the full GUI chain.
Installation information
- DataLab installation type: stand-alone Windows version (PyInstaller)
- Reproduced on: Windows 10, Windows 11 (multiple machines, both networked and isolated)
Additional context
Reported by end users on multiple machines at different sites. The bug is specific to the PyInstaller build because in standard Python execution, freeze_support() is a no-op and the multiprocessing spawn method re-executes the script entry point (which is protected by if __name__ == '__main__'), whereas in frozen builds the child process re-enters the import chain directly.