Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging new updates from main fork #1

Merged
merged 41 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
70316f8
update NDViewer version and PycroManagerJava version (Created by Gith…
github-actions[bot] Sep 22, 2023
10b05eb
Merge pull request #701 from micro-manager/ndviewer-update
friendly-mm-pr-robot[bot] Sep 28, 2023
a77de41
Merge branch 'main' into main
henrypinkard Sep 29, 2023
46d1db1
update expected versions
henrypinkard Sep 29, 2023
3a9547e
Merge pull request #703 from henrypinkard/main
henrypinkard Sep 29, 2023
2733b4f
add better error message when no default devices set
henrypinkard Sep 29, 2023
0e71556
Merge branch 'main' of https://github.com/henrypinkard/pycro-manager
henrypinkard Sep 29, 2023
09cbf35
Merge branch 'main' into main
henrypinkard Sep 29, 2023
dee8e41
update AcqEngJ version and PycroManagerJava version (Created by Githu…
github-actions[bot] Sep 29, 2023
3cb2d07
Merge pull request #704 from henrypinkard/main
henrypinkard Sep 29, 2023
f896c29
update AcqEngPy
henrypinkard Sep 29, 2023
f4eae1c
Merge branch 'main' of https://github.com/henrypinkard/pycro-manager
henrypinkard Sep 29, 2023
337639f
increase default timeout to avoid errors
henrypinkard Sep 29, 2023
ec363e5
Merge branch 'main' into main
henrypinkard Sep 29, 2023
d6fb88a
Merge pull request #706 from henrypinkard/main
henrypinkard Sep 29, 2023
c23a4e2
update NDViewer version and PycroManagerJava version (Created by Gith…
github-actions[bot] Sep 29, 2023
456341c
Merge branch 'main' into acqengj-update
henrypinkard Sep 29, 2023
d07e9c0
restore import of Dataset
henrypinkard Sep 29, 2023
b7ac146
Merge branch 'main' of https://github.com/micro-manager/pycro-manager
henrypinkard Sep 29, 2023
6d8646f
Merge branch 'main' into ndviewer-update
henrypinkard Sep 29, 2023
5733b3b
Merge pull request #708 from henrypinkard/main
henrypinkard Sep 29, 2023
5e0868f
Merge branch 'main' into ndviewer-update
henrypinkard Sep 29, 2023
2bb399d
Merge branch 'main' into acqengj-update
henrypinkard Sep 29, 2023
fc644b9
Merge pull request #707 from micro-manager/ndviewer-update
friendly-mm-pr-robot[bot] Sep 29, 2023
b03171c
Merge branch 'main' into acqengj-update
henrypinkard Sep 29, 2023
09dd40f
Merge pull request #705 from micro-manager/acqengj-update
friendly-mm-pr-robot[bot] Sep 29, 2023
a9fcf8d
update AcqEngJ version and PycroManagerJava version (Created by Githu…
github-actions[bot] Sep 29, 2023
c02b595
Merge pull request #709 from micro-manager/acqengj-update
friendly-mm-pr-robot[bot] Oct 5, 2023
bac0e88
fix some python backend bugs
henrypinkard Oct 5, 2023
c79cc6a
remove directory from python backend acq
henrypinkard Oct 5, 2023
269aeac
fix documentation of acquisition class
henrypinkard Oct 5, 2023
5e4473a
merge
henrypinkard Oct 5, 2023
7b00ee8
dummy commit to trigger tests
henrypinkard Oct 5, 2023
7045132
fix acq notification interpretation
henrypinkard Oct 5, 2023
a29aa9c
remove tmp file
henrypinkard Oct 5, 2023
5893a29
change doc dependency versions
henrypinkard Oct 5, 2023
31e66af
revert back because it breaks java acqs
henrypinkard Oct 5, 2023
de3b62a
Merge pull request #711 from henrypinkard/main
henrypinkard Oct 5, 2023
c2a475f
correct fix for python backend
henrypinkard Oct 5, 2023
cb4127e
Merge branch 'main' into main
henrypinkard Oct 5, 2023
4248193
Merge pull request #712 from henrypinkard/main
henrypinkard Oct 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Sphinx==2.1.0
Sphinx
nbsphinx
pygments<3,>=2.4.1
pygments
ipykernel
sphinx_rtd_theme
docstring-inheritance
5 changes: 4 additions & 1 deletion docs/source/apis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,13 @@ Acquisition APIs

Acquisition
==============
.. currentmodule:: pycromanager
.. currentmodule:: pycromanager.acquisition.acquisition_superclass
.. autoclass:: Acquisition
:members:


.. currentmodule:: pycromanager

multi_d_acquisition_events
===========================
.. autofunction:: multi_d_acquisition_events
Expand Down
8 changes: 4 additions & 4 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.micro-manager.pycro-manager</groupId>
<artifactId>PycroManagerJava</artifactId>
<version>0.44.2</version>
<version>0.44.5</version>
<packaging>jar</packaging>
<name>Pycro-Manager Java</name>
<description>The Java components of Pycro-Manager</description>
Expand Down Expand Up @@ -54,12 +54,12 @@
<dependency>
<groupId>org.micro-manager.acqengj</groupId>
<artifactId>AcqEngJ</artifactId>
<version>0.33.0</version>
<version>0.34.0</version>
</dependency>
<dependency>
<groupId>org.micro-manager.ndviewer</groupId>
<artifactId>NDViewer</artifactId>
<version>0.10.0</version>
<version>0.10.2</version>
</dependency>
<dependency>
<groupId>org.micro-manager.ndtiffstorage</groupId>
Expand Down Expand Up @@ -144,4 +144,4 @@
</repository>
</distributionManagement>

</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class ZMQServer extends ZMQSocketWrapper {
//map of objects that exist in some client of the server
protected final ConcurrentHashMap<String, Object> externalObjects_ = new ConcurrentHashMap<String, Object>();

public static final String VERSION = "5.0.0";
public static final String VERSION = "5.1.0";

private static Function<Class, Object> classMapper_;
private static ZMQServer mainServer_;
Expand Down
1 change: 1 addition & 0 deletions pycromanager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
from pycromanager.core import Core
from pycromanager.zmq_bridge.wrappers import JavaObject, JavaClass, PullSocket, PushSocket
from pycromanager.acquisition.acq_eng_py.main.acq_notification import AcqNotification
from ndtiff import Dataset
from ._version import __version__, version_info
2 changes: 1 addition & 1 deletion pycromanager/_version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version_info = (0, 29, 5)
version_info = (0, 29, 9)
__version__ = ".".join(map(str, version_info))
2 changes: 1 addition & 1 deletion pycromanager/acq_future.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

def _axes_to_key(axes):
""" Turn axes into a hashable key """
return frozenset(axes.items())
return None if axes is None else frozenset(axes.items())

class AcquisitionFuture:

Expand Down
9 changes: 9 additions & 0 deletions pycromanager/acquisition/acq_eng_py/internal/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,18 @@ def submit_event_iterator_inner():
return self.event_generator_executor.submit(submit_event_iterator_inner)


def check_for_default_devices(self, event: AcquisitionEvent):
xy_stage = self.core.get_xy_stage_device()
z_stage = self.core.get_focus_device()
if event.get_z_position() is not None and (z_stage is None or z_stage == ""):
raise Exception("Event requires a z position, but no Core-Focus device is set")
if event.get_x_position() is not None and (xy_stage is None or xy_stage == ""):
raise Exception("Event requires an x position, but no Core-XYStage device is set")

def process_acquisition_event(self, event: AcquisitionEvent) -> Future:
def process_acquisition_event_inner():
try:
self.check_for_default_devices(event)
if event.acquisition_.is_debug_mode():
self.core.logMessage("Processing event: " + event.to_string())
if event.acquisition_.is_debug_mode():
Expand Down
9 changes: 5 additions & 4 deletions pycromanager/acquisition/acq_eng_py/main/acq_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,22 @@ def to_string():
return "image"

def __init__(self, type, id, phase=None):
if type == AcqNotification.Acquisition.to_string():
if type == AcqNotification.Acquisition or type == AcqNotification.Acquisition.to_string():
self.type = AcqNotification.Acquisition
self.id = id
self.phase = phase
elif type == AcqNotification.Image.to_string() and phase == AcqNotification.Image.DATA_SINK_FINISHED:
elif (type == AcqNotification.Image or type == AcqNotification.Image.to_string()) and \
phase == AcqNotification.Image.DATA_SINK_FINISHED:
self.type = AcqNotification.Image
self.id = id
self.phase = phase
elif phase in [AcqNotification.Camera.PRE_SNAP, AcqNotification.Camera.POST_EXPOSURE,
AcqNotification.Camera.PRE_SEQUENCE_STARTED]:
self.type = AcqNotification.Camera
self.id = json.loads(id)
self.id = json.loads(id) if isinstance(id, str) else id # convert from '{'time': 5}' to {'time': 5}
elif phase in [AcqNotification.Hardware.PRE_HARDWARE, AcqNotification.Hardware.POST_HARDWARE]:
self.type = AcqNotification.Hardware
self.id = json.loads(id)
self.id = json.loads(id) if isinstance(id, str) else id # convert from '{'time': 5}' to {'time': 5}
elif phase == AcqNotification.Image.IMAGE_SAVED:
self.type = AcqNotification.Image
self.id = id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def copy(self):
e.stageDeviceNamesToAxisNames_ = self.stageDeviceNamesToAxisNames_.copy()
e.xPosition_ = self.xPosition_
e.yPosition_ = self.yPosition_
e.zPosition_ = self.zPosition_
e.miniumumStartTime_ms_ = self.miniumumStartTime_ms_
e.slmImage_ = self.slmImage_
e.acquireImage_ = self.acquireImage_
Expand Down
14 changes: 13 additions & 1 deletion pycromanager/acquisition/acquisition_superclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __init__(
----------
directory : str
saving directory for this acquisition. If it is not supplied, the image data will be stored in RAM
(Java backend only)
name : str
Name of the acquisition. This will be used to generate the folder where the data is saved.
image_process_fn : Callable
Expand Down Expand Up @@ -76,7 +77,7 @@ def __init__(
external timing device that synchronizes with other hardware. Accepts either one argument (the current
acquisition event) or two arguments (current event, event_queue)
notification_callback_fn : Callable
(Experimental) function that will be called whenever a notification is received from the acquisition engine. These
function that will be called whenever a notification is received from the acquisition engine. These
include various stages of the control of hardware and the camera and saving of images. Notification
callbacks will execute asynchronously with respect to the acquisition process. The supplied function
should take a single argument, which will be an AcqNotification object. It should execute quickly,
Expand All @@ -91,6 +92,17 @@ def __init__(
the user
debug : bool
whether to print debug messages
show_display : bool
If True, show the image viewer window. If False, show no viewer. (Java backend only)
saving_queue_size : int
The number of images to queue (in memory) while waiting to write to disk. Higher values should
in theory allow sequence acquisitions to go faster, but requires the RAM to hold images while
they are waiting to save (Java backend only)
timeout :
Timeout in ms for connecting to Java side (Java backend only)
port :
Allows overriding the default port for using Java backends on a different port. Use this
after calling start_headless with the same non-default port (Java backend only)
"""
self._debug = debug
self._dataset = None
Expand Down
39 changes: 12 additions & 27 deletions pycromanager/acquisition/java_backend_acquisitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,25 +234,10 @@ def __init__(
show_display: bool=True,
napari_viewer=None,
saving_queue_size: int=20,
timeout: int=2000,
timeout: int=2500,
port: int=DEFAULT_PORT,
debug: int=False
):
"""
Parameters
----------
show_display : bool
If True, show the image viewer window. If False, show no viewer.
saving_queue_size : int
The number of images to queue (in memory) while waiting to write to disk. Higher values should
in theory allow sequence acquisitions to go faster, but requires the RAM to hold images while
they are waiting to save
timeout :
Timeout in ms for connecting to Java side
port :
Allows overriding the default port for using Java backends on a different port. Use this
after calling start_headless with the same non-default port
"""
# Get a dict of all named argument values (or default values when nothing provided)
arg_names = [k for k in signature(JavaBackendAcquisition.__init__).parameters.keys() if k != 'self']
l = locals()
Expand Down Expand Up @@ -286,7 +271,8 @@ def __init__(

try:
self._remote_notification_handler = JavaObject('org.micromanager.remote.RemoteNotificationHandler',
args=[self._acq], port=self._port, new_socket=False)
args=[self._acq], port=self._port, new_socket=False,
timeout=self._timeout)
self._acq_notification_recieving_thread = self._start_receiving_notifications()
self._acq_notification_dispatcher_thread = self._start_notification_dispatcher(notification_callback_fn)
# TODO: can remove this after this feature has been present for a while
Expand Down Expand Up @@ -476,7 +462,7 @@ def _initialize_image_processor(self, **kwargs):

if kwargs['image_process_fn'] is not None:
java_processor = JavaObject(
"org.micromanager.remote.RemoteImageProcessor", port=self._port
"org.micromanager.remote.RemoteImageProcessor", port=self._port, timeout=self._timeout
)
self._acq.add_image_processor(java_processor)
self._processor_thread = self._start_processor(
Expand All @@ -489,29 +475,29 @@ def _initialize_hooks(self, **kwargs):
self._hook_threads = []
if kwargs['event_generation_hook_fn'] is not None:
hook = JavaObject(
"org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq]
"org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq], timeout=self._timeout
)
self._hook_threads.append(self._start_hook(hook, kwargs['event_generation_hook_fn'],
self._event_queue, process=False))
self._acq.add_hook(hook, self._acq.EVENT_GENERATION_HOOK)
if kwargs['pre_hardware_hook_fn'] is not None:
hook = JavaObject(
"org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq]
"org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq], timeout=self._timeout
)
self._hook_threads.append(self._start_hook(hook,
kwargs['pre_hardware_hook_fn'], self._event_queue,
process=False))
self._acq.add_hook(hook, self._acq.BEFORE_HARDWARE_HOOK)
if kwargs['post_hardware_hook_fn'] is not None:
hook = JavaObject(
"org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq]
"org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq], timeout=self._timeout
)
self._hook_threads.append(self._start_hook(hook, kwargs['post_hardware_hook_fn'],
self._event_queue, process=False))
self._acq.add_hook(hook, self._acq.AFTER_HARDWARE_HOOK)
if kwargs['post_camera_hook_fn'] is not None:
hook = JavaObject(
"org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq],
"org.micromanager.remote.RemoteAcqHook", port=self._port, args=[self._acq], timeout=self._timeout
)
self._hook_threads.append(self._start_hook(hook, kwargs['post_camera_hook_fn'],
self._event_queue, process=False))
Expand All @@ -523,7 +509,7 @@ def _create_remote_acquisition(self, **kwargs):
# create a new socket for it to run on so that it can have blocking calls without interfering with
# the main socket or other internal sockets
new_socket=True,
port=self._port, args=[core], debug=self._debug)
port=self._port, args=[core], debug=self._debug, timeout=self._timeout)
show_viewer = kwargs['show_display'] is True and kwargs['napari_viewer'] is None
self._acq = acq_factory.create_acquisition(kwargs['directory'], kwargs['name'], show_viewer,
kwargs['saving_queue_size'], self._debug,)
Expand Down Expand Up @@ -665,9 +651,8 @@ def __init__(

def _create_remote_acquisition(self, port, **kwargs):
core = ZMQRemoteMMCoreJ(port=self._port, timeout=self._timeout)
acq_factory = JavaObject(
"org.micromanager.remote.RemoteAcquisitionFactory", port=self._port, args=[core]
)
acq_factory = JavaObject("org.micromanager.remote.RemoteAcquisitionFactory",
port=self._port, args=[core], timeout=self._timeout)

show_viewer = kwargs['show_display'] is True and\
kwargs['napari_viewer'] is None and\
Expand Down Expand Up @@ -711,7 +696,7 @@ def __init__(
show_display: bool=True,
image_saved_fn: callable=None,
saving_queue_size: int=20,
timeout: int=1000,
timeout: int=2500,
port: int=DEFAULT_PORT,
debug: bool=False,
):
Expand Down
9 changes: 6 additions & 3 deletions pycromanager/acquisition/python_backend_acquisitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class PythonBackendAcquisition(Acquisition, metaclass=NumpyDocstringInheritanceM

def __init__(
self,
directory: str=None,
name: str='default_acq_name',
image_process_fn: callable=None,
event_generation_hook_fn: callable = None,
Expand All @@ -30,16 +29,20 @@ def __init__(
napari_viewer=None,
image_saved_fn: callable=None,
debug: int=False,
# Specificly so the directory arg can be absorbed and ignored without error,
**kwargs
):
# Get a dict of all named argument values (or default values when nothing provided)
arg_names = [k for k in signature(PythonBackendAcquisition.__init__).parameters.keys() if k != 'self']
l = locals()
named_args = {arg_name: (l[arg_name] if arg_name in l else
dict(signature(PythonBackendAcquisition.__init__).parameters.items())[arg_name].default)
for arg_name in arg_names }
if 'kwargs' in named_args:
if 'directory' in named_args['kwargs'] and named_args['kwargs']['directory'] is not None:
raise Exception('The directory argument is not supported in Python backend acquisitions')
del named_args['kwargs']
super().__init__(**named_args)
if directory is not None:
raise NotImplementedError('Saving to disk is not yet implemented for the python backend. ')
self._dataset = RAMDataStorage()
self._finished = False
self._notifications_finished = False
Expand Down
2 changes: 1 addition & 1 deletion pycromanager/zmq_bridge/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ class _Bridge:

DEFAULT_PORT = 4827
DEFAULT_TIMEOUT = 500
_EXPECTED_ZMQ_SERVER_VERSION = "5.0.0"
_EXPECTED_ZMQ_SERVER_VERSION = "5.1.0"

_bridge_creation_lock = threading.Lock()
_cached_bridges_by_port_and_thread = {}
Expand Down