Skip to content

Commit 86ca27f

Browse files
committed
Ran isort, black and flake8 on digital sensors
There is still a large amount of work to do on documentation and cleanup.
1 parent e64e020 commit 86ca27f

4 files changed

Lines changed: 927 additions & 712 deletions

File tree

.pre-commit-config.yaml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,10 @@ repos:
1515
rev: 23.1.0
1616
hooks:
1717
- id: black
18-
# Exclude files not cleaned up yet.
19-
exclude: |
20-
(?x)^(
21-
nxt/sensor/digital\.py|
22-
nxt/sensor/hitechnic\.py|
23-
nxt/sensor/mindsensors\.py|
24-
)$
2518
- repo: https://github.com/pycqa/flake8
2619
rev: 5.0.4
2720
hooks:
2821
- id: flake8
29-
# Exclude files not cleaned up yet.
30-
exclude: |
31-
(?x)^(
32-
nxt/sensor/digital\.py|
33-
nxt/sensor/hitechnic\.py|
34-
nxt/sensor/mindsensors\.py|
35-
)$
3622
- repo: local
3723
hooks:
3824
- id: pytest

nxt/sensor/digital.py

Lines changed: 112 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Copyright (C) 2006,2007 Douglas P Lau
33
# Copyright (C) 2009 Marcus Wanner, Paulo Vieira, rhn
44
# Copyright (C) 2010,2011,2012 Marcus Wanner
5+
# Copyright (C) 2023 Nicolas Schodet
56
#
67
# This program is free software: you can redistribute it and/or modify
78
# it under the terms of the GNU General Public License as published by
@@ -30,51 +31,58 @@ def __init__(self, version, product_id, sensor_type):
3031
self.sensor_type = sensor_type
3132

3233
def clarifybinary(self, instr, label):
33-
outstr = ''
34-
outstr += (label + ': `' + instr + '`\n')
34+
outstr = ""
35+
outstr += label + ": `" + instr + "`\n"
3536
for char in instr:
36-
outstr += (hex(ord(char))+', ')
37-
outstr += ('\n')
37+
outstr += hex(ord(char)) + ", "
38+
outstr += "\n"
3839
return outstr
3940

4041
def __str__(self):
41-
outstr = ''
42-
outstr += (self.clarifybinary(str(self.version), 'Version'))
43-
outstr += (self.clarifybinary(str(self.product_id), 'Product ID'))
44-
outstr += (self.clarifybinary(str(self.sensor_type), 'Type'))
42+
outstr = ""
43+
outstr += self.clarifybinary(str(self.version), "Version")
44+
outstr += self.clarifybinary(str(self.product_id), "Product ID")
45+
outstr += self.clarifybinary(str(self.sensor_type), "Type")
4546
return outstr
4647

48+
4749
class BaseDigitalSensor(nxt.sensor.Sensor):
48-
"""Object for digital sensors. I2C_ADDRESS is the dictionary storing name
49-
to i2c address mappings. It should be updated in every subclass. When
50-
subclassing this class, make sure to call add_compatible_sensor to add
51-
compatible sensor data.
50+
"""Object for digital sensors.
51+
52+
:param bool check_compatible: Check sensor class match the connected sensor.
53+
54+
If `check_compatible` is ``True``, queries the sensor for its name and print
55+
a warning if the wrong sensor class is used.
56+
57+
`I2C_ADDRESS` is the dictionary storing name to I2C address mappings. It should be
58+
updated in every subclass. When subclassing this class, make sure to call
59+
:func:`add_compatible_sensor` to add compatible sensor data.
5260
"""
61+
5362
I2C_DEV = 0x02
54-
I2C_ADDRESS = {'version': (0x00, '8s'),
55-
'product_id': (0x08, '8s'),
56-
'sensor_type': (0x10, '8s'),
57-
# 'factory_zero': (0x11, 1), # is this really correct?
58-
'factory_scale_factor': (0x12, 'B'),
59-
'factory_scale_divisor': (0x13, 'B'),
63+
I2C_ADDRESS = {
64+
"version": (0x00, "8s"),
65+
"product_id": (0x08, "8s"),
66+
"sensor_type": (0x10, "8s"),
67+
# "factory_zero": (0x11, 1), # is this really correct?
68+
"factory_scale_factor": (0x12, "B"),
69+
"factory_scale_divisor": (0x13, "B"),
6070
}
6171

6272
def __init__(self, brick, port, check_compatible=True):
63-
"""Creates a BaseDigitalSensor. If check_compatible is True, queries
64-
the sensor for its name, and if a wrong sensor class was used, prints
65-
a warning.
66-
"""
6773
super().__init__(brick, port)
6874
self.set_input_mode(nxt.sensor.Type.LOW_SPEED_9V, nxt.sensor.Mode.RAW)
6975
self.last_poll = time.time()
7076
self.poll_delay = 0.01
7177
time.sleep(0.1) # Give I2C time to initialize
72-
#Don't do type checking if this class has no compatible sensors listed.
73-
try: self.compatible_sensors
74-
except AttributeError: check_compatible = False
78+
# Don't do type checking if this class has no compatible sensors listed.
79+
try:
80+
self.compatible_sensors
81+
except AttributeError:
82+
check_compatible = False
7583
if check_compatible:
7684
sensor = self.get_sensor_info()
77-
if not sensor in self.compatible_sensors:
85+
if sensor not in self.compatible_sensors:
7886
logger.warning(
7987
"wrong sensor class chosen for sensor %s on port %s",
8088
sensor.product_id,
@@ -91,57 +99,66 @@ def __init__(self, brick, port, check_compatible=True):
9199
)
92100

93101
def _ls_get_status(self, size):
94-
for n in range(30): #https://code.google.com/p/nxt-python/issues/detail?id=35
102+
for n in range(30): # https://code.google.com/p/nxt-python/issues/detail?id=35
95103
try:
96104
b = self._brick.ls_get_status(self._port)
97105
if b >= size:
98106
return b
99107
except I2CPendingError:
100108
pass
101-
raise I2CError('ls_get_status timeout')
109+
raise I2CError("ls_get_status timeout")
102110

103111
def _i2c_command(self, address, value, format):
104-
"""Writes an i2c value to the given address. value must be a string. value is
105-
a tuple of values corresponding to the given format.
112+
"""Write one or several values to an I2C register.
113+
114+
:param int address: I2C register address.
115+
:param tuple value: Tuple of values to write.
116+
:param str format: Format string using :mod:`struct` syntax.
106117
"""
107118
value = struct.pack(format, *value)
108119
msg = bytes((self.I2C_DEV, address)) + value
109120
now = time.time()
110-
if self.last_poll+self.poll_delay > now:
121+
if self.last_poll + self.poll_delay > now:
111122
diff = now - self.last_poll
112123
time.sleep(self.poll_delay - diff)
113124
self.last_poll = time.time()
114125
self._brick.ls_write(self._port, msg, 0)
115126

116127
def _i2c_query(self, address, format):
117-
"""Reads an i2c value from given address, and returns a value unpacked
118-
according to the given format. Format is the same as in the struct
119-
module. See http://docs.python.org/library/struct.html#format-strings
128+
"""Read one or several values from an I2C register.
129+
130+
:param int address: I2C register address.
131+
:param str format: Format string using :mod:`struct` syntax.
132+
:return: Read values in a tuple.
133+
:rtype: tuple
120134
"""
121135
size = struct.calcsize(format)
122136
msg = bytes((self.I2C_DEV, address))
123137
now = time.time()
124-
if self.last_poll+self.poll_delay > now:
138+
if self.last_poll + self.poll_delay > now:
125139
diff = now - self.last_poll
126140
time.sleep(self.poll_delay - diff)
127141
self.last_poll = time.time()
128142
self._brick.ls_write(self._port, msg, size)
129143
try:
130144
self._ls_get_status(size)
131145
finally:
132-
#we should clear the buffer no matter what happens
146+
# we should clear the buffer no matter what happens
133147
data = self._brick.ls_read(self._port)
134148
if len(data) < size:
135-
raise I2CError('Read failure: Not enough bytes')
149+
raise I2CError("Read failure: Not enough bytes")
136150
data = struct.unpack(format, data[-size:])
137151
return data
138152

139153
def read_value(self, name):
140-
"""Reads a value from the sensor. Name must be a string found in
141-
self.I2C_ADDRESS dictionary. Entries in self.I2C_ADDRESS are in the
142-
name: (address, format) form, with format as in the struct module.
143-
Be careful on unpacking single variables - struct module puts them in
144-
tuples containing only one element.
154+
"""Read one or several values from the sensor.
155+
156+
:param str name: Name of the values to read.
157+
:return: Read values in a tuple.
158+
:rtype: tuple
159+
160+
The `name` parameter is an index inside `I2C_ADDRESS` dictionary, which gives
161+
the corresponding I2C register address and format string.
145162
"""
146163
address, fmt = self.I2C_ADDRESS[name]
147164
for n in range(3):
@@ -152,62 +169,78 @@ def read_value(self, name):
152169
raise I2CError("read_value timeout")
153170

154171
def write_value(self, name, value):
155-
"""Writes value to the sensor. Name must be a string found in
156-
self.I2C_ADDRESS dictionary. Entries in self.I2C_ADDRESS are in the
157-
name: (address, format) form, with format as in the struct module.
158-
value is a tuple of values corresponding to the format from
159-
self.I2C_ADDRESS dictionary.
172+
"""Write one or several values to the sensor.
173+
174+
:param str name: Name of the values to write.
175+
:param tuple value: Tuple of values to write.
176+
177+
The `name` parameter is an index inside `I2C_ADDRESS` dictionary, which gives
178+
the corresponding I2C register address and format string.
160179
"""
161180
address, fmt = self.I2C_ADDRESS[name]
162181
self._i2c_command(address, value, fmt)
163182

164183
def get_sensor_info(self):
165-
version = self.read_value('version')[0].decode('windows-1252').split('\0')[0]
166-
product_id = self.read_value('product_id')[0].decode('windows-1252').split('\0')[0]
167-
sensor_type = self.read_value('sensor_type')[0].decode('windows-1252').split('\0')[0]
184+
version = self.read_value("version")[0].decode("windows-1252").split("\0")[0]
185+
product_id = (
186+
self.read_value("product_id")[0].decode("windows-1252").split("\0")[0]
187+
)
188+
sensor_type = (
189+
self.read_value("sensor_type")[0].decode("windows-1252").split("\0")[0]
190+
)
168191
return SensorInfo(version, product_id, sensor_type)
169192

170193
@classmethod
171194
def add_compatible_sensor(cls, version, product_id, sensor_type):
172-
"""Adds an entry in the compatibility table for the sensor. If version
173-
is None, then it's the default class for this model. If product_id is
174-
None, then this is the default class for this vendor.
195+
"""Adds an entry in the compatibility table for the sensor.
196+
197+
:param version: Sensor version, or ``None`` for default class.
198+
:type version: str or None
199+
:param product_id: Product identifier, or ``None`` for default class.
200+
:type product_id: str or None
201+
:param str sensor_type: Sensor type
175202
"""
176203
try:
177204
cls.compatible_sensors
178205
except AttributeError:
179206
cls.compatible_sensors = []
180207
finally:
181-
cls.compatible_sensors.append(SCompatibility(version, product_id,
182-
sensor_type))
183-
add_mapping(cls, version, product_id, sensor_type)
208+
cls.compatible_sensors.append(
209+
_SCompatibility(version, product_id, sensor_type)
210+
)
211+
_add_mapping(cls, version, product_id, sensor_type)
184212

185213

186-
class SCompatibility(SensorInfo):
187-
"""An object that helps manage the sensor mappings"""
214+
class _SCompatibility(SensorInfo):
215+
"""An object that helps manage the sensor mappings."""
216+
188217
def __eq__(self, other):
189218
if self.product_id is None:
190219
return self.product_id == other.product_id
191220
elif self.version is None:
192-
return (self.product_id == other.product_id and
193-
self.sensor_type == other.sensor_type)
221+
return (
222+
self.product_id == other.product_id
223+
and self.sensor_type == other.sensor_type
224+
)
194225
else:
195-
return (self.version == other.version and
196-
self.product_id == other.product_id and
197-
self.sensor_type == other.sensor_type)
226+
return (
227+
self.version == other.version
228+
and self.product_id == other.product_id
229+
and self.sensor_type == other.sensor_type
230+
)
231+
198232

199233
sensor_mappings = {}
200234

201235

202-
def add_mapping(cls, version, product_id, sensor_type):
203-
"None means any other value"
236+
def _add_mapping(cls, version, product_id, sensor_type):
204237
if product_id not in sensor_mappings:
205238
sensor_mappings[product_id] = {}
206239
models = sensor_mappings[product_id]
207240

208241
if sensor_type is None:
209242
if sensor_type in models:
210-
raise ValueError('Already registered!')
243+
raise ValueError("Already registered!")
211244
models[sensor_type] = cls
212245
return
213246

@@ -216,7 +249,7 @@ def add_mapping(cls, version, product_id, sensor_type):
216249
versions = models[sensor_type]
217250

218251
if version in versions:
219-
raise ValueError('Already registered!')
252+
raise ValueError("Already registered!")
220253
else:
221254
versions[version] = cls
222255

@@ -226,14 +259,22 @@ class SearchError(Exception):
226259

227260

228261
def find_class(info):
229-
"""Returns an appropriate class for the given SensorInfo"""
262+
"""Returns an appropriate class.
263+
264+
:param SensorInfo info: Information read from the sensor.
265+
:return: Class corresponding to sensor.
266+
:rtype: BaseDigitalSensor
267+
:raises SearchError: When no class found.
268+
"""
230269
dic = sensor_mappings
231-
for val, msg in zip((info.product_id, info.sensor_type, info.version),
232-
('Vendor', 'Model', 'Version')):
270+
for val, msg in zip(
271+
(info.product_id, info.sensor_type, info.version),
272+
("Vendor", "Model", "Version"),
273+
):
233274
if val in dic:
234275
dic = dic[val]
235276
elif None in dic:
236277
dic = dic[None]
237278
else:
238-
raise SearchError(msg + ' not found')
279+
raise SearchError(msg + " not found")
239280
return dic[info.sensor_type][None]

0 commit comments

Comments
 (0)