Skip to content

Commit 62d7655

Browse files
committed
Linting devices.py.
1 parent 78366c8 commit 62d7655

File tree

1 file changed

+66
-59
lines changed

1 file changed

+66
-59
lines changed

microscope/devices.py

Lines changed: 66 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33

4-
## Copyright (C) 2017 David Pinto <[email protected]>
5-
## Copyright (C) 2016 Mick Phillips <[email protected]>
6-
##
7-
## Microscope is free software: you can redistribute it and/or modify
8-
## it under the terms of the GNU General Public License as published by
9-
## the Free Software Foundation, either version 3 of the License, or
10-
## (at your option) any later version.
11-
##
12-
## Microscope is distributed in the hope that it will be useful,
13-
## but WITHOUT ANY WARRANTY; without even the implied warranty of
14-
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15-
## GNU General Public License for more details.
16-
##
17-
## You should have received a copy of the GNU General Public License
18-
## along with Microscope. If not, see <http://www.gnu.org/licenses/>.
4+
# Copyright (C) 2017-2020 David Pinto <[email protected]>
5+
# Copyright (C) 2016-2020 Mick Phillips <[email protected]>
6+
#
7+
# Microscope is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation, either version 3 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# Microscope is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with Microscope. If not, see <http://www.gnu.org/licenses/>.
1919

2020
"""Classes for control of microscope components.
2121
@@ -55,9 +55,9 @@
5555
(TRIGGER_AFTER, TRIGGER_BEFORE, TRIGGER_DURATION, TRIGGER_SOFT) = range(4)
5656

5757
# Mapping of setting data types to descriptors allowed-value description types.
58-
# For python 2 and 3 compatibility, we convert the type into a descriptor string.
59-
# This avoids problems with, say a python 2 client recognising a python 3
60-
# <class 'int'> as a python 2 <type 'int'>.
58+
# For python 2 and 3 compatibility, we convert the type into a descriptor
59+
# string. This avoids problems with, say a python 2 client recognising a
60+
# python 3 <class 'int'> as a python 2 <type 'int'>.
6161
DTYPES = {'int': ('int', tuple),
6262
'float': ('float', tuple),
6363
'bool': ('bool', type(None)),
@@ -70,16 +70,19 @@
7070
str: ('str', int),
7171
tuple: ('tuple', type(None))}
7272

73-
# A utility function to call callables or return value of non-callables.
74-
# noinspection PyPep8
75-
_call_if_callable = lambda f: f() if callable(f) else f
73+
74+
def call_if_callable(f):
75+
"""Call callables, or return value of non-callables."""
76+
return f() if callable(f) else f
7677

7778

7879
class _Setting():
7980
# TODO: refactor into subclasses to avoid if isinstance .. elif .. else.
8081
# Settings classes should be private: devices should use a factory method
81-
# rather than instantiate settings directly; most already use add_setting for this.
82-
def __init__(self, name, dtype, get_func, set_func=None, values=None, readonly=False):
82+
# rather than instantiate settings directly; most already use add_setting
83+
# for this.
84+
def __init__(self, name, dtype, get_func, set_func=None, values=None,
85+
readonly=False):
8386
"""Create a setting.
8487
8588
:param name: the setting's name
@@ -102,7 +105,8 @@ def __init__(self, name, dtype, get_func, set_func=None, values=None, readonly=F
102105
if dtype not in DTYPES:
103106
raise Exception('Unsupported dtype.')
104107
elif not (isinstance(values, DTYPES[dtype][1:]) or callable(values)):
105-
raise Exception("Invalid values type for %s '%s': expected function or %s" %
108+
raise Exception("Invalid values type for %s '%s':"
109+
"expected function or %s" %
106110
(dtype, name, DTYPES[dtype][1:]))
107111
self.dtype = DTYPES[dtype][0]
108112
self._get = get_func
@@ -211,11 +215,9 @@ def __init__(self, index=None):
211215
def __del__(self):
212216
self.shutdown()
213217

214-
215218
def get_is_enabled(self):
216219
return self.enabled
217220

218-
219221
def _on_disable(self):
220222
"""Do any device-specific work on disable.
221223
@@ -268,7 +270,8 @@ def make_safe(self):
268270
"""Put the device into a safe state."""
269271
pass
270272

271-
def add_setting(self, name, dtype, get_func, set_func, values, readonly=False):
273+
def add_setting(self, name, dtype, get_func, set_func, values,
274+
readonly=False):
272275
"""Add a setting definition.
273276
274277
:param name: the setting's name
@@ -291,7 +294,8 @@ class with getter, setter, etc., and adding Setting instances as
291294
if dtype not in DTYPES:
292295
raise Exception('Unsupported dtype.')
293296
elif not (isinstance(values, DTYPES[dtype][1:]) or callable(values)):
294-
raise Exception("Invalid values type for %s '%s': expected function or %s" %
297+
raise Exception("Invalid values type for %s '%s':"
298+
"expected function or %s" %
295299
(dtype, name, DTYPES[dtype][1:]))
296300
else:
297301
self._settings[name] = _Setting(name, dtype, get_func, set_func,
@@ -465,7 +469,6 @@ def enable(self):
465469
_logger.debug("... enabled.")
466470
return self.enabled
467471

468-
469472
def disable(self):
470473
"""Disable the data capture device.
471474
@@ -501,13 +504,14 @@ def _send_data(self, client, data, timestamp):
501504
# this function name as an argument to set_client, but
502505
# not sure how to subsequently resolve this over Pyro.
503506
client.receiveData(data, timestamp)
504-
except (Pyro4.errors.ConnectionClosedError, Pyro4.errors.CommunicationError):
507+
except (Pyro4.errors.ConnectionClosedError,
508+
Pyro4.errors.CommunicationError):
505509
# Client not listening
506510
_logger.info("Removing %s from client stack: disconnected.",
507511
client._pyroUri)
508512
self._clientStack = list(filter(client.__ne__, self._clientStack))
509513
self._liveClients = self._liveClients.difference([client])
510-
except:
514+
except Exception:
511515
raise
512516

513517
def _dispatch_loop(self):
@@ -525,12 +529,13 @@ def _dispatch_loop(self):
525529
err = e
526530
else:
527531
try:
528-
self._send_data(client, self._process_data(data), timestamp)
532+
self._send_data(client, self._process_data(data),
533+
timestamp)
529534
except Exception as e:
530535
err = e
531536
if err:
532-
# Raising an exception will kill the dispatch loop. We need another
533-
# way to notify the client that there was a problem.
537+
# Raising an exception will kill the dispatch loop. We need
538+
# another way to notify the client that there was a problem.
534539
_logger.error("in _dispatch_loop:", exc_info=err)
535540
self._dispatch_buffer.task_done()
536541

@@ -543,13 +548,13 @@ def _fetch_loop(self):
543548
data = self._fetch_data()
544549
except Exception as e:
545550
_logger.error("in _fetch_loop:", exc_info=e)
546-
# Raising an exception will kill the fetch loop. We need another
547-
# way to notify the client that there was a problem.
551+
# Raising an exception will kill the fetch loop. We need
552+
# another way to notify the client that there was a problem.
548553
timestamp = time.time()
549554
self._put(e, timestamp)
550555
data = None
551556
if data is not None:
552-
# ***TODO*** Add support for timestamp from hardware.
557+
# TODO Add support for timestamp from hardware.
553558
timestamp = time.time()
554559
self._put(data, timestamp)
555560
else:
@@ -602,7 +607,6 @@ def set_client(self, new_client):
602607
else:
603608
_logger.info("Current client is %s.", str(self._client))
604609

605-
606610
@keep_acquiring
607611
def update_settings(self, settings, init=False):
608612
"""Update settings, toggling acquisition if necessary."""
@@ -679,6 +683,7 @@ def __init__(self, **kwargs):
679683
self.get_roi,
680684
self.set_roi,
681685
None)
686+
682687
def _process_data(self, data):
683688
"""Apply self._transform to data."""
684689
flips = (self._transform[0], self._transform[1])
@@ -708,7 +713,8 @@ def set_transform(self, transform):
708713
if isinstance(transform, str):
709714
transform = literal_eval(transform)
710715
self._client_transform = transform
711-
lr, ud, rot = (self._readout_transform[i] ^ transform[i] for i in range(3))
716+
lr, ud, rot = (self._readout_transform[i] ^ transform[i]
717+
for i in range(3))
712718
if self._readout_transform[2] and self._client_transform[2]:
713719
lr = not lr
714720
ud = not ud
@@ -758,7 +764,7 @@ def _get_binning(self):
758764
pass
759765

760766
def get_binning(self):
761-
"""Return a tuple of (horizontal, vertical), corrected for transform."""
767+
"""Return a tuple of (horizontal, vertical) corrected for transform."""
762768
binning = self._get_binning()
763769
if self._transform[2]:
764770
# 90 degree rotation
@@ -808,9 +814,9 @@ def set_roi(self, roi):
808814
maxw, maxh = self.get_sensor_shape()
809815
binning = self.get_binning()
810816
left, top, width, height = roi
811-
if not width: # 0 or None
817+
if not width: # 0 or None
812818
width = maxw // binning.h
813-
if not height: # 0 o rNone
819+
if not height: # 0 o rNone
814820
height = maxh // binning.v
815821
if self._transform[2]:
816822
roi = ROI(left, top, height, width)
@@ -843,6 +849,7 @@ class TriggerType(Enum):
843849
FALLING_EDGE = 2
844850
PULSE = 3
845851

852+
846853
class TriggerMode(Enum):
847854
ONCE = 1
848855
BULB = 2
@@ -866,6 +873,7 @@ class TriggerTargetMixIn(metaclass=abc.ABCMeta):
866873
@property
867874
def trigger_mode(self) -> TriggerMode:
868875
return self._trigger_mode
876+
869877
@property
870878
def trigger_type(self) -> TriggerType:
871879
return self._trigger_type
@@ -889,11 +897,11 @@ class SerialDeviceMixIn(metaclass=abc.ABCMeta):
889897
"""
890898
def __init__(self, **kwargs):
891899
super().__init__(**kwargs)
892-
## TODO: We should probably construct the connection here but
893-
## the Serial constructor takes a lot of arguments, and
894-
## it becomes tricky to separate those from arguments to
895-
## the constructor of other parent classes.
896-
self.connection = None # serial.Serial (to be constructed by child)
900+
# TODO: We should probably construct the connection here but
901+
# the Serial constructor takes a lot of arguments, and
902+
# it becomes tricky to separate those from arguments to
903+
# the constructor of other parent classes.
904+
self.connection = None # serial.Serial (to be constructed by child)
897905
self._comms_lock = threading.RLock()
898906

899907
def _readline(self):
@@ -962,8 +970,8 @@ def __init__(self, **kwargs) -> None:
962970
"""
963971
super().__init__(**kwargs)
964972

965-
self._patterns = None # type: typing.Optional[numpy.ndarray]
966-
self._pattern_idx = -1 # type: int
973+
self._patterns = None # type: typing.Optional[numpy.ndarray]
974+
self._pattern_idx = -1 # type: int
967975

968976
@property
969977
@abc.abstractmethod
@@ -1008,7 +1016,7 @@ def queue_patterns(self, patterns: numpy.ndarray) -> None:
10081016
"""
10091017
self._validate_patterns(patterns)
10101018
self._patterns = patterns
1011-
self._pattern_idx = -1 # none is applied yet
1019+
self._pattern_idx = -1 # none is applied yet
10121020

10131021
def next_pattern(self) -> None:
10141022
"""Apply the next pattern in the queue.
@@ -1018,7 +1026,7 @@ def next_pattern(self) -> None:
10181026
if self._patterns is None:
10191027
raise Exception("no pattern queued to apply")
10201028
self._pattern_idx += 1
1021-
self.apply_pattern(self._patterns[self._pattern_idx,:])
1029+
self.apply_pattern(self._patterns[self._pattern_idx, :])
10221030

10231031
def initialize(self) -> None:
10241032
pass
@@ -1087,29 +1095,28 @@ def set_power_mw(self, mw):
10871095

10881096

10891097
class FilterWheelBase(Device, metaclass=abc.ABCMeta):
1090-
def __init__(self, filters: typing.Union[typing.Mapping[int, str], typing.Iterable] = [],
1091-
positions: int = 0, **kwargs) -> None:
1098+
def __init__(self, filters: typing.Union[typing.Mapping[int, str],
1099+
typing.Iterable] = [], positions: int = 0, **kwargs) -> None:
10921100
super().__init__(**kwargs)
10931101
if isinstance(filters, dict):
10941102
self._filters = filters
10951103
else:
1096-
self._filters = {i:f for (i, f) in enumerate(filters)}
1104+
self._filters = {i: f for (i, f) in enumerate(filters)}
10971105
self._inv_filters = {val: key for key, val in self._filters.items()}
10981106
if not hasattr(self, '_positions'):
1099-
self._positions = positions # type: int
1107+
self._positions = positions # type: int
11001108
# The position as an integer.
11011109
# Deprecated: clients should call get_position and set_position;
11021110
# still exposed as a setting until cockpit uses set_position.
11031111
self.add_setting('position',
11041112
'int',
11051113
self.get_position,
11061114
self.set_position,
1107-
lambda: (0, self.get_num_positions()) )
1108-
1115+
lambda: (0, self.get_num_positions()))
11091116

11101117
def get_num_positions(self) -> int:
11111118
"""Returns the number of wheel positions."""
1112-
return(max( self._positions, len(self._filters)))
1119+
return(max(self._positions, len(self._filters)))
11131120

11141121
@abc.abstractmethod
11151122
def get_position(self) -> int:
@@ -1122,7 +1129,7 @@ def set_position(self, position: int) -> None:
11221129
pass
11231130

11241131
def get_filters(self) -> typing.List[typing.Tuple[int, str]]:
1125-
return [(k,v) for k,v in self._filters.items()]
1132+
return [(k, v) for k, v in self._filters.items()]
11261133

11271134

11281135
class ControllerDevice(Device, metaclass=abc.ABCMeta):

0 commit comments

Comments
 (0)