pyimagej icon indicating copy to clipboard operation
pyimagej copied to clipboard

Add callback mechanism for GUI mode

Open elevans opened this issue 11 months ago • 3 comments

Update

Update I wanted to preserve the original text (below) for this PR as its relevant to the goals (i.e. create a better experience for macOS users). With the awesome work that @ctrueden has done with jaunch we now have a way to actually support interactive mode on macOS. This PR introduces the following new elements and also paves the way for interactive mode on macOS via jaunch.

This PR adds:

  • A "global gateway" which enables other projects to hook into a already running instance of imagej (e.g. napari-imagej).
  • A callback mechanism which enables users to register functions with when_imagej_starts(). This can enable some GUI related workflows on macOS (a kind of limited psuedo-interactive mode). See notebook 5 section 5.2 for the relevant documentation. This callback mechanism is not compatible with napari.
  • An override flag to the main init method. This flag will enable users/developers to bypass initialization checks/blocks we've put in place to stop unsupported/application breaking behavior -- mainly interactive mode on macOS. To test interactive mode on macOS:
    • Install/setup jaunch.
    • Modify jaunch's fiji.py file. Add the override=True flag to ij = imagej.init(app_dir, mode="interactive") on line 72.
    • Jaunch Fiji with ./fiji-macos-universal -i --python.

Some other relevant information: Based on what I now understand about Python's threading system and some experimentation on macOS/Linux with jaunch, Python will always think its in a main thread. There is no way (from what I gather) to know if a particular Python instance was started with/in a pthread. Instead, threads that are spawned from an already running instance, say in a function that creates threads, are identified as "non-main" thread. This is obvious, but it would have been cool if there was a way to know about how the current instance was started.

Original text

Until we can find a true interactive mode for macOS (see https://github.com/imagej/pyimagej/issues/298) this callback mechanism gives macOS users the ability to run their desired Python functions before the REPL is locked by the AppHelper.runConsoleEventLoop().

Here's how you register a callback with PyImageJ:

import imagej

# register a function that takes no params
imagej.when_imagej_starts(lambda: func())

# register an ImageJ function (if a parameter is present, assume its ij)
imagej.when_imagej_starts(lambda ij: ij.RoiManager.getRoiManager())

# initialize ImageJ in GUI mode
ij = imagej.init(mode='gui')

Unfortunately this callback strategy doesn't work with napari. Registering the callback lambda: napari.Viewer() results in this segfault:

(pyimagej) loci@dyn-144-92-48-223 Documents % python test.py
WARNING: package sun.awt.X11 not in java.desktop
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by net.imagej.legacy.IJ1Helper (file:/Users/loci/.jgo/net.imagej/imagej/RELEASE/28b74e6959b0634f2a8e10c27afe06e7039fb4a0dc582d9746d028ba40e5bd04/imagej-legacy-1.2.1.jar) to method com.apple.eawt.Application.getApplication()
WARNING: Please consider reporting this to the maintainers of net.imagej.legacy.IJ1Helper
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGILL (0x4) at pc=0x00007ff8116c90c2, pid=2487, tid=42247
#
# JRE version: OpenJDK Runtime Environment Zulu11.70+15-CA (11.0.22+7) (build 11.0.22+7-LTS)
# Java VM: OpenJDK 64-Bit Server VM Zulu11.70+15-CA (11.0.22+7-LTS, mixed mode, tiered, compressed oops, g1 gc, bsd-amd64)
# Problematic frame:
# C  [libdispatch.dylib+0x50c2]  _dispatch_assert_queue_fail+0x66
#
# No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/loci/Documents/hs_err_pid2487.log
#
# If you would like to submit a bug report, please visit:
#   http://www.azul.com/support/
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
zsh: abort      python test.py
(pyimagej) loci@dyn-144-92-48-223 Documents % 

elevans avatar Mar 04 '24 21:03 elevans

Codecov Report

Attention: Patch coverage is 78.39506% with 35 lines in your changes missing coverage. Please review.

Project coverage is 77.48%. Comparing base (a173d5a) to head (a833767). Report is 14 commits behind head on main.

Files Patch % Lines
src/imagej/__init__.py 43.33% 17 Missing :warning:
tests/test_legacy.py 68.57% 11 Missing :warning:
tests/test_fiji.py 12.50% 7 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #301      +/-   ##
==========================================
- Coverage   77.81%   77.48%   -0.33%     
==========================================
  Files          16       17       +1     
  Lines        2010     2034      +24     
==========================================
+ Hits         1564     1576      +12     
- Misses        446      458      +12     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov[bot] avatar Mar 04 '24 21:03 codecov[bot]

~~Just fyi all PyImageJ builds will fail for python 3.12 until labeling=0.1.14 no longer pins pillow <10 in the conda-feedstock recipe. See this issue.~~

Edit: This is no longer an issue with labeling 0.1.14's release.

elevans avatar Jun 10 '24 17:06 elevans

Thanks @gselzer for your review! It made it sooo much better! I addressed all your comments. Ready to merge?

elevans avatar Jul 15 '24 16:07 elevans