BioImager  3.9.1
A .NET microscopy imaging library. Supports various microscopes by using imported libraries & GUI automation. Supported libraries include PriorĀ® & ZeissĀ® & all devices supported by Micromanager 2.0 and python-microscope.
Loading...
Searching...
No Matches
microscope.device_server.DeviceServer Class Reference
Inheritance diagram for microscope.device_server.DeviceServer:
microscope.testsuite.test_device_server.DeviceServerExceptionQueue

Public Member Functions

def __init__ (self, device_def, DeviceServerOptions options, typing.Mapping[str, str] id_to_host, typing.Mapping[str, int] id_to_port, typing.Optional[multiprocessing.Event] exit_event=None)
 
def clone (self)
 
def run (self)
 

Public Attributes

 exit_event
 
 daemon
 

Detailed Description

Initialise a device and serve at host/port according to its id.

Args:
    device_def: definition of the device.
    options: configuration for the device server.
    id_to_host: host or mapping of device identifiers to hostname.
    id_to_port: map or mapping of device identifiers to port
        number.
    exit_event: a shared event to signal that the process should
        quit.

Definition at line 241 of file device_server.py.

Constructor & Destructor Documentation

◆ __init__()

def microscope.device_server.DeviceServer.__init__ (   self,
  device_def,
DeviceServerOptions  options,
typing.Mapping[str, str]  id_to_host,
typing.Mapping[str, int]  id_to_port,
typing.Optional[multiprocessing.Event]   exit_event = None 
)

Definition at line 255 of file device_server.py.

262 ):
263 # The device to serve.
264 self._device_def = device_def
265 self._options = options
266 self._devices: typing.Dict[str, microscope.abc.Device] = {}
267 # Where to serve it.
268 self._id_to_host = id_to_host
269 self._id_to_port = id_to_port
270 # A shared event to allow clean shutdown.
271 self.exit_event = exit_event
272 super().__init__()
273 self.daemon = True
274

Member Function Documentation

◆ clone()

def microscope.device_server.DeviceServer.clone (   self)
Create new instance with same settings.

This is useful to restart a device server.

Definition at line 275 of file device_server.py.

275 def clone(self):
276 """Create new instance with same settings.
277
278 This is useful to restart a device server.
279
280 """
281 return DeviceServer(
282 self._device_def,
283 self._options,
284 self._id_to_host,
285 self._id_to_port,
286 exit_event=self.exit_event,
287 )
288

References microscope.device_server.DeviceServer._device_def, microscope.device_server.DeviceServer._devices, microscope.simulators.SimulatedController._devices, microscope.device_server.DeviceServer._id_to_host, microscope.device_server.DeviceServer._id_to_port, microscope.device_server.DeviceServer._options, and microscope.device_server.DeviceServer.exit_event.

◆ run()

def microscope.device_server.DeviceServer.run (   self)

Definition at line 289 of file device_server.py.

289 def run(self):
290 cls = self._device_def["cls"]
291 cls_name = cls.__name__
292
293 # If the multiprocessing start method is fork, the child
294 # process gets a copy of the root logger. The copy is
295 # configured to sign the messages as "device-server", and
296 # write to the main log file and stderr. We remove those
297 # handlers so that this DeviceServer is logged to a separate
298 # file and the messages are signed with the device name.
299 root_logger = logging.getLogger()
300 # Get a new list of handlers because otherwise we are
301 # iterating over the same list as removeHandler().
302 for handler in list(root_logger.handlers):
303 root_logger.removeHandler(handler)
304
305 root_logger.setLevel(self._options.logging_level)
306
307 # Later, we'll log to one file per server, with a filename
308 # based on a unique identifier for the device. Some devices
309 # don't have UIDs available until after initialization, so
310 # log to stderr until then.
311 stderr_handler = StreamHandler(sys.stderr)
312 stderr_handler.setFormatter(_create_log_formatter(cls_name))
313 root_logger.addHandler(stderr_handler)
314 root_logger.debug("Debugging messages on.")
315
316 root_logger.addFilter(Filter())
317
318 # The cls argument can either be a Device subclass, or it can
319 # be a function that returns a map of names to devices.
320 cls_is_type = isinstance(cls, type)
321
322 if not cls_is_type:
323 self._devices = cls(**self._device_def["conf"])
324 else:
325 while not self.exit_event.is_set():
326 try:
327 device = cls(**self._device_def["conf"])
328 except Exception as e:
329 _logger.info(
330 "Failed to start device. Retrying in 5s.", exc_info=e
331 )
332 time.sleep(5)
333 else:
334 break
335 self._devices = {cls_name: device}
336
337 if cls_is_type and issubclass(cls, FloatingDeviceMixin):
338 uid = str(list(self._devices.values())[0].get_id())
339 if uid not in self._id_to_host or uid not in self._id_to_port:
340 raise Exception(
341 "Host or port not found for device %s" % (uid,)
342 )
343 host = self._id_to_host[uid]
344 port = self._id_to_port[uid]
345 else:
346 host = self._device_def["host"]
347 port = self._device_def["port"]
348
349 pyro_daemon = Pyro4.Daemon(port=port, host=host)
350
351 log_handler = RotatingFileHandler(
352 "%s_%s_%s.log" % (cls_name, host, port)
353 )
354 log_handler.setFormatter(_create_log_formatter(cls_name))
355 root_logger.addHandler(log_handler)
356
357 _logger.info("Device initialized; starting daemon.")
358 for obj_id, device in self._devices.items():
359 _register_device(pyro_daemon, device, obj_id=obj_id)
360
361 # Run the Pyro daemon in a separate thread so that we can do
362 # clean shutdown under Windows.
363 pyro_thread = Thread(target=pyro_daemon.requestLoop)
364 pyro_thread.daemon = True
365 pyro_thread.start()
366 for device in self._devices.values():
367 _logger.info("Serving %s", pyro_daemon.uriFor(device))
368 if isinstance(device, FloatingDeviceMixin):
369 _logger.info(
370 "Device UID on port %s is %s", port, device.get_id()
371 )
372
373 # Wait for termination event. We should just be able to call
374 # wait() on the exit_event, but this causes issues with locks
375 # in multiprocessing - see http://bugs.python.org/issue30975 .
376 while self.exit_event and not self.exit_event.is_set():
377 # This tread waits for the termination event.
378 try:
379 time.sleep(5)
380 except (KeyboardInterrupt, IOError):
381 pass
382 pyro_daemon.shutdown()
383 pyro_thread.join()
384 for device in self._devices.values():
385 try:
386 device.shutdown()
387 except Exception as ex:
388 # Catch errors so we get a chance of shutting down the
389 # other devices.
390 _logger.error("Failure to shutdown device %s", device, ex)
391
392

Member Data Documentation

◆ daemon

microscope.device_server.DeviceServer.daemon

Definition at line 273 of file device_server.py.

◆ exit_event

microscope.device_server.DeviceServer.exit_event

Definition at line 271 of file device_server.py.

Referenced by microscope.device_server.DeviceServer.clone().


The documentation for this class was generated from the following file: