diff options
author | Diego Elio Pettenò <flameeyes@flameeyes.eu> | 2018-12-12 23:53:49 +0100 |
---|---|---|
committer | Diego Elio Pettenò <flameeyes@flameeyes.eu> | 2018-12-12 23:53:49 +0100 |
commit | 2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c (patch) | |
tree | edc6805eae41aed89613d87e3d85b48099141627 | |
parent | Simplify exceptions hierarchy. (diff) | |
download | glucometerutils-2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c.tar glucometerutils-2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c.tar.gz glucometerutils-2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c.tar.bz2 glucometerutils-2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c.tar.lz glucometerutils-2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c.tar.xz glucometerutils-2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c.tar.zst glucometerutils-2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c.zip |
-rw-r--r-- | .pylintrc | 12 | ||||
-rw-r--r-- | glucometerutils/common.py | 9 | ||||
-rw-r--r-- | glucometerutils/drivers/accuchek_reports.py | 57 | ||||
-rw-r--r-- | glucometerutils/drivers/fsinsulinx.py | 2 | ||||
-rw-r--r-- | glucometerutils/drivers/fslibre.py | 2 | ||||
-rw-r--r-- | glucometerutils/drivers/fsoptium.py | 101 | ||||
-rw-r--r-- | glucometerutils/drivers/fsprecisionneo.py | 10 | ||||
-rw-r--r-- | glucometerutils/drivers/otultra2.py | 100 | ||||
-rw-r--r-- | glucometerutils/drivers/otverio2015.py | 6 | ||||
-rw-r--r-- | glucometerutils/drivers/otverioiq.py | 2 | ||||
-rw-r--r-- | glucometerutils/drivers/sdcodefree.py | 21 | ||||
-rwxr-xr-x | glucometerutils/glucometer.py | 57 | ||||
-rw-r--r-- | glucometerutils/support/freestyle.py | 5 | ||||
-rw-r--r-- | glucometerutils/support/hiddevice.py | 10 | ||||
-rw-r--r-- | glucometerutils/support/lifescan.py | 12 | ||||
-rw-r--r-- | glucometerutils/support/lifescan_binary_protocol.py | 20 | ||||
-rw-r--r-- | glucometerutils/support/serial.py | 4 |
17 files changed, 228 insertions, 202 deletions
diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..34485a1 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,12 @@ +[MESSAGE CONTROL] +disable= + duplicate-code, + too-few-public-methods, + too-many-branches, + too-many-locals, + too-many-nested-blocks, + too-many-return-statements, + too-many-statements, + +[BASIC] +good-names = i, j, k, e, _ diff --git a/glucometerutils/common.py b/glucometerutils/common.py index 8ffa724..7d7f0db 100644 --- a/glucometerutils/common.py +++ b/glucometerutils/common.py @@ -6,20 +6,17 @@ __email__ = 'flameeyes@flameeyes.eu' __copyright__ = 'Copyright © 2013, Diego Elio Pettenò' __license__ = 'MIT' -import collections import datetime import enum import textwrap try: from typing import Sequence, Text -except: +except ImportError: pass import attr -from glucometerutils import exceptions - class Unit(enum.Enum): MG_DL = 'mg/dL' MMOL_L = 'mmol/L' @@ -56,8 +53,8 @@ def convert_glucose_unit(value, from_unit, to_unit): if from_unit == Unit.MG_DL: return round(value / 18.0, 2) - else: - return round(value * 18.0, 0) + + return round(value * 18.0, 0) @attr.s class GlucoseReading: diff --git a/glucometerutils/drivers/accuchek_reports.py b/glucometerutils/drivers/accuchek_reports.py index 49c698d..a29f0c6 100644 --- a/glucometerutils/drivers/accuchek_reports.py +++ b/glucometerutils/drivers/accuchek_reports.py @@ -26,8 +26,8 @@ from glucometerutils import common from glucometerutils import exceptions _UNIT_MAP = { - 'mmol/l': common.Unit.MMOL_L, - 'mg/dl': common.Unit.MG_DL, + 'mmol/l': common.Unit.MMOL_L, + 'mg/dl': common.Unit.MG_DL, } _DATE_CSV_KEY = 'Date' @@ -47,17 +47,18 @@ _TIME_FORMAT = '%H:%M' _DATETIME_FORMAT = ' '.join((_DATE_FORMAT, _TIME_FORMAT)) -class Device(object): +class Device: def __init__(self, device): if not device or not os.path.isdir(device): raise exceptions.CommandLineError( - '--device parameter is required, should point to mount path for the ' - 'meter.') + '--device parameter is required, should point to mount path ' + 'for the meter.') - report_files = glob.glob(os.path.join(device, '*', 'Reports', '*.csv')) + reports_path = os.path.join(device, '*', 'Reports', '*.csv') + report_files = glob.glob(reports_path) if not report_files: raise exceptions.ConnectionFailed( - 'No report file found in path "%s".' % reports_path) + 'No report file found in path "%s".' % reports_path) self.report_file = report_files[0] @@ -68,23 +69,28 @@ class Device(object): next(self.report) return csv.DictReader( - self.report, delimiter=';', skipinitialspace=True, quoting=csv.QUOTE_NONE) + self.report, + delimiter=';', + skipinitialspace=True, + quoting=csv.QUOTE_NONE) def connect(self): - self.report = open(self.report_file, 'r', newline='\r\n', encoding='utf-8') + self.report = open( + self.report_file, 'r', newline='\r\n', encoding='utf-8') def disconnect(self): self.report.close() def get_meter_info(self): return common.MeterInfo( - '%s glucometer' % self.get_model(), - serial_number=self.get_serial_number(), - native_unit=self.get_glucose_unit()) + '%s glucometer' % self.get_model(), + serial_number=self.get_serial_number(), + native_unit=self.get_glucose_unit()) def get_model(self): # $device/MODEL/Reports/*.csv - return os.path.basename(os.path.dirname(os.path.dirname(self.report_file))) + return os.path.basename( + os.path.dirname(os.path.dirname(self.report_file))) def get_serial_number(self): self.report.seek(0) @@ -99,23 +105,24 @@ class Device(object): return _UNIT_MAP[record[_UNIT_CSV_KEY]] def get_datetime(self): - raise NotImplemented + raise NotImplementedError def set_datetime(self, date=None): - raise NotImplemented + raise NotImplementedError def zero_log(self): - raise NotImplemented + raise NotImplementedError - def _extract_datetime(self, record): + def _extract_datetime(self, record): # pylint: disable=no-self-use # Date and time are in separate column, but we want to parse them # together. date_and_time = ' '.join((record[_DATE_CSV_KEY], record[_TIME_CSV_KEY])) return datetime.datetime.strptime(date_and_time, _DATETIME_FORMAT) - def _extract_meal(self, record): + def _extract_meal(self, record): # pylint: disable=no-self-use if record[_AFTER_MEAL_CSV_KEY] and record[_BEFORE_MEAL_CSV_KEY]: - raise InvalidResponse('Reading cannot be before and after meal.') + raise exceptions.InvalidResponse( + 'Reading cannot be before and after meal.') elif record[_AFTER_MEAL_CSV_KEY]: return common.Meal.AFTER elif record[_BEFORE_MEAL_CSV_KEY]: @@ -129,9 +136,9 @@ class Device(object): continue yield common.GlucoseReading( - self._extract_datetime(record), - common.convert_glucose_unit( - float(record[_RESULT_CSV_KEY]), - _UNIT_MAP[record[_UNIT_CSV_KEY]], - common.Unit.MG_DL), - meal=self._extract_meal(record)) + self._extract_datetime(record), + common.convert_glucose_unit( + float(record[_RESULT_CSV_KEY]), + _UNIT_MAP[record[_UNIT_CSV_KEY]], + common.Unit.MG_DL), + meal=self._extract_meal(record)) diff --git a/glucometerutils/drivers/fsinsulinx.py b/glucometerutils/drivers/fsinsulinx.py index 15bc131..fbde9ba 100644 --- a/glucometerutils/drivers/fsinsulinx.py +++ b/glucometerutils/drivers/fsinsulinx.py @@ -55,7 +55,7 @@ class Device(freestyle.FreeStyleHidDevice): 'Software version: ' + self._get_version(),), native_unit=self.get_glucose_unit()) - def get_glucose_unit(self): + def get_glucose_unit(self): # pylint: disable=no-self-use """Returns the glucose unit of the device.""" return common.Unit.MG_DL diff --git a/glucometerutils/drivers/fslibre.py b/glucometerutils/drivers/fslibre.py index 6e3988c..5341573 100644 --- a/glucometerutils/drivers/fslibre.py +++ b/glucometerutils/drivers/fslibre.py @@ -205,7 +205,7 @@ class Device(freestyle.FreeStyleHidDevice): """Overridden function as the command is not compatible.""" return self._send_text_command(b'$sn?').rstrip('\r\n') - def get_glucose_unit(self): + def get_glucose_unit(self): # pylint: disable=no-self-use """Returns the glucose unit of the device.""" # TODO(Flameeyes): figure out how to identify the actual unit on the # device. diff --git a/glucometerutils/drivers/fsoptium.py b/glucometerutils/drivers/fsoptium.py index 395494c..618fffa 100644 --- a/glucometerutils/drivers/fsoptium.py +++ b/glucometerutils/drivers/fsoptium.py @@ -29,8 +29,8 @@ from glucometerutils.support import serial _CLOCK_RE = re.compile( - r'^Clock:\t(?P<month>[A-Z][a-z]{2}) (?P<day>[0-9]{2}) (?P<year>[0-9]{4})\t' - r'(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2})$') + r'^Clock:\t(?P<month>[A-Z][a-z]{2}) (?P<day>[0-9]{2}) (?P<year>[0-9]{4})\t' + r'(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2})$') # The reading can be HI (padded to three-characters by a space) if the value was # over what the meter was supposed to read. Unlike the "Clock:" line, the months @@ -38,29 +38,33 @@ _CLOCK_RE = re.compile( # characters, so accept a space or 'e'/'y' at the end of the month name. Also, # the time does *not* include seconds. _READING_RE = re.compile( - r'^(?P<reading>HI |[0-9]{3}) (?P<month>[A-Z][a-z]{2})[ ey] (?P<day>[0-9]{2}) ' - r'(?P<year>[0-9]{4}) (?P<time>[0-9]{2}:[0-9]{2}) (?P<type>[GK]) 0x00$') + r'^(?P<reading>HI |[0-9]{3}) ' + r'(?P<month>[A-Z][a-z]{2})[ ey] ' + r'(?P<day>[0-9]{2}) ' + r'(?P<year>[0-9]{4}) ' + r'(?P<time>[0-9]{2}:[0-9]{2}) ' + r'(?P<type>[GK]) 0x00$') _CHECKSUM_RE = re.compile( - r'^(?P<checksum>0x[0-9A-F]{4}) END$') + r'^(?P<checksum>0x[0-9A-F]{4}) END$') # There are two date format used by the device. One uses three-letters month # names, and that's easy enough. The other uses three-letters month names, # except for (at least) July. So ignore the fourth character. # explicit mapping. Note that the mapping *requires* a trailing whitespace. _MONTH_MATCHES = { - 'Jan': 1, - 'Feb': 2, - 'Mar': 3, - 'Apr': 4, - 'May': 5, - 'Jun': 6, - 'Jul': 7, - 'Aug': 8, - 'Sep': 9, - 'Oct': 10, - 'Nov': 11, - 'Dec': 12 + 'Jan': 1, + 'Feb': 2, + 'Mar': 3, + 'Apr': 4, + 'May': 5, + 'Jun': 6, + 'Jul': 7, + 'Aug': 8, + 'Sep': 9, + 'Oct': 10, + 'Nov': 11, + 'Dec': 12 } @@ -99,8 +103,8 @@ class Device(serial.SerialDevice): logging.debug('Received response: %r', response) - # We always want to decode the output, and remove stray \r\n. Any failure in - # decoding means the output is invalid anyway. + # We always want to decode the output, and remove stray \r\n. Any + # failure in decoding means the output is invalid anyway. decoded_response = [line.decode('ascii').rstrip('\r\n') for line in response] return decoded_response @@ -109,7 +113,7 @@ class Device(serial.SerialDevice): self._send_command('xmem') # ignore output this time self._fetch_device_information() - def disconnect(self): + def disconnect(self): # pylint: disable=no-self-use return def _fetch_device_information(self): @@ -126,13 +130,13 @@ class Device(serial.SerialDevice): self.device_glucose_unit_ = common.Unit.MMOL_L else: # I only have a mmol/l device, so I can't be sure. self.device_glucose_unit_ = common.Unit.MG_DL - # There are more entries: Clock, Market, ROM and Usage, but we don't care - # for those here. + # There are more entries: Clock, Market, ROM and Usage, but we don't + # care for those here. elif parsed_line[0] == 'CMD OK': return - # I have not figured out why this happens, but sometimes it's echoing back - # the commands and not replying to them. + # I have not figured out why this happens, but sometimes it's echoing + # back the commands and not replying to them. raise exceptions.ConnectionFailed() def get_meter_info(self): @@ -142,11 +146,11 @@ class Device(serial.SerialDevice): A common.MeterInfo object. """ return common.MeterInfo( - 'Freestyle Optium glucometer', - serial_number=self.get_serial_number(), - version_info=( - 'Software version: ' + self.get_version(),), - native_unit=self.get_glucose_unit()) + 'Freestyle Optium glucometer', + serial_number=self.get_serial_number(), + version_info=( + 'Software version: ' + self.get_version(),), + native_unit=self.get_glucose_unit()) def get_version(self): """Returns an identifier of the firmware version of the glucometer. @@ -208,11 +212,6 @@ class Device(serial.SerialDevice): return self.get_datetime() def zero_log(self): - """Zeros out the data log of the device. - - This function will clear the memory of the device deleting all the readings - in an irrecoverable way. - """ raise NotImplementedError def get_readings(self): @@ -221,19 +220,20 @@ class Device(serial.SerialDevice): Args: unit: The glucose unit to use for the output. - Yields: - A tuple (date, value) of the readings in the glucometer. The value is a - floating point in the unit specified; if no unit is specified, the default - unit in the glucometer will be used. + Yields: A tuple (date, value) of the readings in the glucometer. The + value is a floating point in the unit specified; if no unit is + specified, the default unit in the glucometer will be used. Raises: - exceptions.InvalidResponse: if the response does not match what expected. + exceptions.InvalidResponse: if the response does not match what ' + expected. + """ data = self._send_command('xmem') - # The first line is empty, the second is the serial number, the third the - # version, the fourth the current time, and the fifth the record count.. The - # last line has a checksum and the end. + # The first line is empty, the second is the serial number, the third + # the version, the fourth the current time, and the fifth the record + # count.. The last line has a checksum and the end. count = int(data[4]) if count != (len(data) - 6): raise exceptions.InvalidResponse('\n'.join(data)) @@ -244,12 +244,14 @@ class Device(serial.SerialDevice): raise exceptions.InvalidResponse('\n'.join(data)) expected_checksum = int(checksum_match.group('checksum'), 16) - # exclude the last line in the checksum calculation, as that's the checksum - # itself. The final \r\n is added separately. - calculated_checksum = sum(ord(c) for c in '\r\n'.join(data[:-1])) + 0xd + 0xa + # exclude the last line in the checksum calculation, as that's the + # checksum itself. The final \r\n is added separately. + calculated_checksum = sum( + ord(c) for c in '\r\n'.join(data[:-1])) + 0xd + 0xa if expected_checksum != calculated_checksum: - raise exceptions.InvalidChecksum(expected_checksum, calculated_checksum) + raise exceptions.InvalidChecksum( + expected_checksum, calculated_checksum) for line in data[5:-1]: match = _READING_RE.match(line) @@ -257,7 +259,8 @@ class Device(serial.SerialDevice): raise exceptions.InvalidResponse(line) if match.group('type') != 'G': - logging.warning('Non-glucose readings are not supported, ignoring.') + logging.warning( + 'Non-glucose readings are not supported, ignoring.') continue if match.group('reading') == 'HI ': @@ -273,6 +276,6 @@ class Device(serial.SerialDevice): timestamp = datetime.datetime(year, month, day, hour, minute) - # The reading, if present, is always in mg/dL even if the glucometer is - # set to mmol/L. + # The reading, if present, is always in mg/dL even if the glucometer + # is set to mmol/L. yield common.GlucoseReading(timestamp, value) diff --git a/glucometerutils/drivers/fsprecisionneo.py b/glucometerutils/drivers/fsprecisionneo.py index 1153908..87076c2 100644 --- a/glucometerutils/drivers/fsprecisionneo.py +++ b/glucometerutils/drivers/fsprecisionneo.py @@ -64,7 +64,7 @@ class Device(freestyle.FreeStyleHidDevice): 'Software version: ' + self._get_version(),), native_unit=self.get_glucose_unit()) - def get_glucose_unit(self): + def get_glucose_unit(self): # pylint: disable=no-self-use """Returns the glucose unit of the device.""" return common.Unit.MG_DL @@ -82,10 +82,10 @@ class Device(freestyle.FreeStyleHidDevice): # Build a _reading object by parsing each of the entries in the raw # record values = [] - for v in record: - if v == "HI": - v = float("inf") - values.append(int(v)) + for value in record: + if value == "HI": + value = float("inf") + values.append(int(value)) raw_reading = _NeoReading._make(values[:len(_NeoReading._fields)]) timestamp = datetime.datetime( diff --git a/glucometerutils/drivers/otultra2.py b/glucometerutils/drivers/otultra2.py index a27d333..f26fc45 100644 --- a/glucometerutils/drivers/otultra2.py +++ b/glucometerutils/drivers/otultra2.py @@ -17,7 +17,6 @@ __copyright__ = 'Copyright © 2013-2017, Diego Elio Pettenò' __license__ = 'MIT' import datetime -import logging import re from glucometerutils import common @@ -27,32 +26,32 @@ from glucometerutils.support import serial # The following two hashes are taken directly from LifeScan's documentation _MEAL_CODES = { - 'N': common.Meal.NONE, - 'B': common.Meal.BEFORE, - 'A': common.Meal.AFTER, + 'N': common.Meal.NONE, + 'B': common.Meal.BEFORE, + 'A': common.Meal.AFTER, } _COMMENT_CODES = { - '00': '', # would be 'No Comment' - '01': 'Not Enough Food', - '02': 'Too Much Food', - '03': 'Mild Exercise', - '04': 'Hard Exercise', - '05': 'Medication', - '06': 'Stress', - '07': 'Illness', - '08': 'Feel Hypo', - '09': 'Menses', - '10': 'Vacation', - '11': 'Other', + '00': '', # would be 'No Comment' + '01': 'Not Enough Food', + '02': 'Too Much Food', + '03': 'Mild Exercise', + '04': 'Hard Exercise', + '05': 'Medication', + '06': 'Stress', + '07': 'Illness', + '08': 'Feel Hypo', + '09': 'Menses', + '10': 'Vacation', + '11': 'Other', } _DUMP_HEADER_RE = re.compile( - r'P ([0-9]{3}),"[0-9A-Z]{9}","(?:MG/DL |MMOL/L)"') + r'P ([0-9]{3}),"[0-9A-Z]{9}","(?:MG/DL |MMOL/L)"') _DUMP_LINE_RE = re.compile( - r'P (?P<datetime>"[A-Z]{3}","[0-9/]{8}","[0-9:]{8} "),' - r'"(?P<control>[C ]) (?P<value>[0-9]{3})(?P<parityerror>[\? ])",' - r'"(?P<meal>[NBA])","(?P<comment>0[0-9]|1[01])", 00') + r'P (?P<datetime>"[A-Z]{3}","[0-9/]{8}","[0-9:]{8} "),' + r'"(?P<control>[C ]) (?P<value>[0-9]{3})(?P<parityerror>[\? ])",' + r'"(?P<meal>[NBA])","(?P<comment>0[0-9]|1[01])", 00') _RESPONSE_MATCH = re.compile(r'^(.+) ([0-9A-F]{4})\r$') @@ -94,7 +93,7 @@ def _validate_and_strip_checksum(line): try: checksum_given = int(checksum_string, 16) checksum_calculated = _calculate_checksum( - bytes(response, 'ascii')) + bytes(response, 'ascii')) if checksum_given != checksum_calculated: raise exceptions.InvalidChecksum(checksum_given, @@ -105,7 +104,8 @@ def _validate_and_strip_checksum(line): return response _DATETIME_RE = re.compile( - r'^"[A-Z]{3}","([0-9]{2}/[0-9]{2}/[0-9]{2})","([0-9]{2}:[0-9]{2}:[0-9]{2}) "$') + r'^"[A-Z]{3}",' + r'"([0-9]{2}/[0-9]{2}/[0-9]{2})","([0-9]{2}:[0-9]{2}:[0-9]{2}) "$') def _parse_datetime(response): @@ -136,10 +136,10 @@ class Device(serial.SerialDevice): BAUDRATE = 9600 DEFAULT_CABLE_ID = '067b:2303' # Generic PL2303 cable. - def connect(self): + def connect(self): # pylint: disable=no-self-use return - def disconnect(self): + def disconnect(self): # pylint: disable=no-self-use return def _send_command(self, cmd): @@ -159,7 +159,8 @@ class Device(serial.SerialDevice): cmd: command and parameters to send (without newline) Returns: - A single line of text that the glucometer responds, without the checksum. + A single line of text that the glucometer responds, without the + checksum. """ self._send_command(cmd) @@ -173,11 +174,11 @@ class Device(serial.SerialDevice): A common.MeterInfo object. """ return common.MeterInfo( - 'OneTouch Ultra 2 glucometer', - serial_number=self.get_serial_number(), - version_info=( - 'Software version: ' + self.get_version(),), - native_unit=self.get_glucose_unit()) + 'OneTouch Ultra 2 glucometer', + serial_number=self.get_serial_number(), + version_info=( + 'Software version: ' + self.get_version(),), + native_unit=self.get_glucose_unit()) def get_version(self): """Returns an identifier of the firmware version of the glucometer. @@ -215,8 +216,8 @@ class Device(serial.SerialDevice): serial_number = match.group(1) - # 'Y' at the far right of the serial number is the indication of a OneTouch - # Ultra2 device, as per specs. + # 'Y' at the far right of the serial number is the indication of a + # OneTouch Ultra2 device, as per specs. if serial_number[-1] != 'Y': raise lifescan.InvalidSerialNumber(serial_number) @@ -242,15 +243,15 @@ class Device(serial.SerialDevice): A datetime object built according to the returned response. """ response = self._send_oneliner_command( - 'DMT' + date.strftime('%m/%d/%y %H:%M:%S')) + 'DMT' + date.strftime('%m/%d/%y %H:%M:%S')) return _parse_datetime(response[2:]) def zero_log(self): """Zeros out the data log of the device. - This function will clear the memory of the device deleting all the readings - in an irrecoverable way. + This function will clear the memory of the device deleting all the + readings in an irrecoverable way. """ response = self._send_oneliner_command('DMZ') if response != 'Z': @@ -268,10 +269,10 @@ class Device(serial.SerialDevice): Raises: exceptions.InvalidGlucoseUnit: if the unit is not recognized - OneTouch meters will always dump data in mg/dL because that's their internal - storage. They will then provide a separate method to read the unit used for - display. This is not settable by the user in all modern meters. - + OneTouch meters will always dump data in mg/dL because that's their + internal storage. They will then provide a separate method to read the + unit used for display. This is not settable by the user in all modern + meters. """ response = self._send_oneliner_command('DMSU?') @@ -280,10 +281,11 @@ class Device(serial.SerialDevice): if unit == 'MG/DL ': return common.Unit.MG_DL - elif unit == 'MMOL/L': + + if unit == 'MMOL/L': return common.Unit.MMOL_L - else: - raise exceptions.InvalidGlucoseUnit(string) + + raise exceptions.InvalidGlucoseUnit(response) def get_readings(self): """Iterates over the reading values stored in the glucometer. @@ -292,12 +294,12 @@ class Device(serial.SerialDevice): unit: The glucose unit to use for the output. Yields: - A tuple (date, value) of the readings in the glucometer. The value is a - floating point in the unit specified; if no unit is specified, the default - unit in the glucometer will be used. + A GlucoseReading object representing the read value. Raises: - exceptions.InvalidResponse: if the response does not match what expected. + exceptions.InvalidResponse: if the response does not match what + expected. + """ self._send_command('DMP') data = self.serial_.readlines() @@ -323,7 +325,7 @@ class Device(serial.SerialDevice): meal = _MEAL_CODES[line_data['meal']] comment = _COMMENT_CODES[line_data['comment']] - # OneTouch2 always returns the data in mg/dL even if the glucometer is set - # to mmol/L, so there is no conversion required. + # OneTouch2 always returns the data in mg/dL even if the glucometer + # is set to mmol/L, so there is no conversion required. yield common.GlucoseReading( - date, float(line_data['value']), meal=meal, comment=comment) + date, float(line_data['value']), meal=meal, comment=comment) diff --git a/glucometerutils/drivers/otverio2015.py b/glucometerutils/drivers/otverio2015.py index efd4114..3a73e20 100644 --- a/glucometerutils/drivers/otverio2015.py +++ b/glucometerutils/drivers/otverio2015.py @@ -43,7 +43,7 @@ _REGISTER_SIZE = 512 _PACKET = construct.Padded( _REGISTER_SIZE, - lifescan_binary_protocol.LifeScanPacket(False)) + lifescan_binary_protocol.LifeScanPacket(False)) _COMMAND_SUCCESS = construct.Const(b'\x03\x06') @@ -115,7 +115,7 @@ _READ_RECORD_RESPONSE = construct.Struct( construct.Padding(4), ) -class Device(object): +class Device: def __init__(self, device): if not device: raise exceptions.CommandLineError( @@ -135,7 +135,7 @@ class Device(object): raise exceptions.ConnectionFailed( 'Device %s is not a LifeScan glucometer.' % self.device_name_) - def disconnect(self): + def disconnect(self): # pylint: disable=no-self-use return def _send_request(self, lba, request_format, request_obj, response_format): diff --git a/glucometerutils/drivers/otverioiq.py b/glucometerutils/drivers/otverioiq.py index deafed4..67781a7 100644 --- a/glucometerutils/drivers/otverioiq.py +++ b/glucometerutils/drivers/otverioiq.py @@ -176,7 +176,7 @@ class Device(serial.SerialDevice): return response.timestamp def set_datetime(self, date=datetime.datetime.now()): - response = self._send_request( + self._send_request( _WRITE_RTC_REQUEST, { 'timestamp': date, }, _COMMAND_SUCCESS) diff --git a/glucometerutils/drivers/sdcodefree.py b/glucometerutils/drivers/sdcodefree.py index 1eba6e6..8e7b29c 100644 --- a/glucometerutils/drivers/sdcodefree.py +++ b/glucometerutils/drivers/sdcodefree.py @@ -139,7 +139,7 @@ class Device(serial.SerialDevice): logging.debug('sending packet: %s', binascii.hexlify(pkt)) self.serial_.write(pkt) - def connect(self): + def connect(self): # pylint: disable=no-self-use print("Please connect and turn on the device.") def disconnect(self): @@ -148,20 +148,20 @@ class Device(serial.SerialDevice): if response != _DISCONNECTED_MESSAGE: raise exceptions.InvalidResponse(response=response) - def get_meter_info(self): + def get_meter_info(self): # pylint: disable=no-self-use return common.MeterInfo('SD CodeFree glucometer') - def get_version(self): + def get_version(self): # pylint: disable=no-self-use raise NotImplementedError - def get_serial_number(self): + def get_serial_number(self): # pylint: disable=no-self-use raise NotImplementedError - def get_glucose_unit(self): + def get_glucose_unit(self): # pylint: disable=no-self-use # Device does not provide information on glucose unit. return common.Unit.MG_DL - def get_datetime(self): + def get_datetime(self): # pylint: disable=no-self-use raise NotImplementedError def set_datetime(self, date=datetime.datetime.now()): @@ -189,10 +189,11 @@ class Device(serial.SerialDevice): self.send_message(_FETCH_MESSAGE) message = self.read_message() - r = _READING.parse(message) - logging.debug('received reading: %r', r) + reading = _READING.parse(message) + logging.debug('received reading: %r', reading) yield common.GlucoseReading( datetime.datetime( - 2000 + r.year, r.month, r.day, r.hour, r.minute), - r.value, meal=r.meal) + 2000 + reading.year, reading.month, + reading.day, reading.hour, reading.minute), + reading.value, meal=reading.meal) diff --git a/glucometerutils/glucometer.py b/glucometerutils/glucometer.py index 97fe80e..49569b0 100755 --- a/glucometerutils/glucometer.py +++ b/glucometerutils/glucometer.py @@ -19,58 +19,59 @@ from glucometerutils import exceptions def main(): if sys.version_info < (3, 4): raise Exception( - 'Unsupported Python version, please use at least Python 3.4') + 'Unsupported Python version, please use at least Python 3.4') parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest="action") parser.add_argument( - '--driver', action='store', required=True, - help='Select the driver to use for connecting to the glucometer.') + '--driver', action='store', required=True, + help='Select the driver to use for connecting to the glucometer.') parser.add_argument( - '--device', action='store', required=False, - help=('Select the path to the glucometer device. Some devices require this ' - 'argument, others will try autodetection.')) + '--device', action='store', required=False, + help=('Select the path to the glucometer device. Some devices require ' + 'this argument, others will try autodetection.')) parser.add_argument( - '--vlog', action='store', required=False, type=int, - help=('Python logging level. See the levels at ' - 'https://docs.python.org/3/library/logging.html#logging-levels')) + '--vlog', action='store', required=False, type=int, + help=('Python logging level. See the levels at ' + 'https://docs.python.org/3/library/logging.html#logging-levels')) subparsers.add_parser( - 'help', help=('Display a description of the driver, including supported ' - 'features and known quirks.')) + 'help', help=('Display a description of the driver, including ' + 'supported features and known quirks.')) subparsers.add_parser( - 'info', help='Display information about the meter.') + 'info', help='Display information about the meter.') subparsers.add_parser( - 'zero', help='Zero out the data log of the meter.') + 'zero', help='Zero out the data log of the meter.') parser_dump = subparsers.add_parser( - 'dump', help='Dump the readings stored in the device.') + 'dump', help='Dump the readings stored in the device.') parser_dump.add_argument( - '--unit', action='store', - choices=[unit.value for unit in common.Unit], - help='Select the unit to use for the dumped data.') + '--unit', action='store', + choices=[unit.value for unit in common.Unit], + help='Select the unit to use for the dumped data.') parser_dump.add_argument( - '--with-ketone', action='store_true', default=False, - help='Enable ketone reading if available on the glucometer.') + '--with-ketone', action='store_true', default=False, + help='Enable ketone reading if available on the glucometer.') parser_date = subparsers.add_parser( - 'datetime', help='Reads or sets the date and time of the glucometer.') + 'datetime', help='Reads or sets the date and time of the glucometer.') parser_date.add_argument( - '--set', action='store', nargs='?', const='now', default=None, - help='Set the date rather than just reading it from the device.') + '--set', action='store', nargs='?', const='now', default=None, + help='Set the date rather than just reading it from the device.') args = parser.parse_args() logging.basicConfig(level=args.vlog) try: - driver = importlib.import_module('glucometerutils.drivers.' + args.driver) + driver = importlib.import_module( + 'glucometerutils.drivers.' + args.driver) except ImportError as e: logging.error( - 'Error importing driver "%s", please check your --driver parameter:\n%s', - args.driver, e) + 'Error importing driver "%s", please check your --driver ' + 'parameter:\n%s', args.driver, e) return 1 # This check needs to happen before we try to initialize the device, as the @@ -91,7 +92,7 @@ def main(): except NotImplementedError: time_str = 'N/A' print("{device_info}Time: {time}".format( - device_info=str(device_info), time=time_str)) + device_info=str(device_info), time=time_str)) elif args.action == 'dump': unit = args.unit if unit is None: @@ -114,7 +115,8 @@ def main(): new_date = date_parser.parse(args.set) except ImportError: logging.error( - 'Unable to import module "dateutil", please install it.') + 'Unable to import module "dateutil", ' + 'please install it.') return 1 except ValueError: logging.error('%s: not a valid date', args.set) @@ -137,3 +139,4 @@ def main(): return 1 device.disconnect() + return 0 diff --git a/glucometerutils/support/freestyle.py b/glucometerutils/support/freestyle.py index 5822d18..2206821 100644 --- a/glucometerutils/support/freestyle.py +++ b/glucometerutils/support/freestyle.py @@ -18,7 +18,7 @@ import re try: from typing import Iterator, List, Text, Tuple -except: +except ImportError: pass import construct @@ -110,8 +110,7 @@ class FreeStyleHidDevice(hiddevice.HidDevice): usb_packet = _FREESTYLE_MESSAGE.build( {'message_type': message_type, 'command': command}) - logging.debug('Sending packet: %r', usb_packet -) + logging.debug('Sending packet: %r', usb_packet) self._write(usb_packet) def _read_response(self): diff --git a/glucometerutils/support/hiddevice.py b/glucometerutils/support/hiddevice.py index 1c5b58d..12debf8 100644 --- a/glucometerutils/support/hiddevice.py +++ b/glucometerutils/support/hiddevice.py @@ -11,13 +11,13 @@ import os try: from typing import BinaryIO, Optional, Text -except: +except ImportError: pass from glucometerutils import exceptions -class HidDevice(object): +class HidDevice: """A device speaking USB HID protocol driver base. This class does not implement an actual driver by itself, but provides an @@ -100,6 +100,6 @@ class HidDevice(object): """ if self.handle_: return bytes(self.handle_.read(size)) - else: - return bytes(self.hidapi_handle_.read( - size, timeout_ms=self.TIMEOUT_MS)) + + return bytes(self.hidapi_handle_.read( + size, timeout_ms=self.TIMEOUT_MS)) diff --git a/glucometerutils/support/lifescan.py b/glucometerutils/support/lifescan.py index 13529ec..1b5cb2d 100644 --- a/glucometerutils/support/lifescan.py +++ b/glucometerutils/support/lifescan.py @@ -12,19 +12,21 @@ from glucometerutils import exceptions class MissingChecksum(exceptions.InvalidResponse): """The response misses the expected 4-digits checksum.""" def __init__(self, response): - self.message = 'Response is missing checksum: %s' % response + super(MissingChecksum, self).__init__( + 'Response is missing checksum: %s' % response) class InvalidSerialNumber(exceptions.Error): """The serial number is not as expected.""" def __init__(self, serial_number): - self.message = 'Serial number %s is invalid.' % serial_number + super(InvalidSerialNumber, self).__init__( + 'Serial number %s is invalid.' % serial_number) class MalformedCommand(exceptions.InvalidResponse): def __init__(self, message): - exceptions.InvalidResponse.__init__( - self, 'Malformed command: %s' % message) + super(MalformedCommand, self).__init__( + 'Malformed command: %s' % message) def crc_ccitt(data): @@ -49,4 +51,4 @@ def crc_ccitt(data): crc ^= (((crc << 8) & 0xffff) << 4) & 0xffff crc ^= (crc & 0xff) << 5 - return (crc & 0xffff) + return crc & 0xffff diff --git a/glucometerutils/support/lifescan_binary_protocol.py b/glucometerutils/support/lifescan_binary_protocol.py index 8b37726..e08d39f 100644 --- a/glucometerutils/support/lifescan_binary_protocol.py +++ b/glucometerutils/support/lifescan_binary_protocol.py @@ -27,7 +27,7 @@ _LINK_CONTROL = construct.BitStruct( 'sequence_number' / construct.Default(construct.Flag, False), ) -def LifeScanPacket(include_link_control): +def LifeScanPacket(include_link_control): # pylint: disable=invalid-name # type: (bool) -> construct.Struct if include_link_control: link_control_construct = _LINK_CONTROL @@ -36,15 +36,15 @@ def LifeScanPacket(include_link_control): return construct.Struct( 'data' / construct.RawCopy( - construct.Struct( - construct.Const(b'\x02'), # stx - 'length' / construct.Rebuild( - construct.Byte, lambda this: len(this.message) + 6), - 'link_control' / link_control_construct, - 'message' / construct.Bytes( - lambda this: this.length - 6), - construct.Const(b'\x03'), # etx - ), + construct.Struct( + construct.Const(b'\x02'), # stx + 'length' / construct.Rebuild( + construct.Byte, lambda this: len(this.message) + 6), + 'link_control' / link_control_construct, + 'message' / construct.Bytes( + lambda this: this.length - 6), + construct.Const(b'\x03'), # etx + ), ), 'checksum' / construct.Checksum( construct.Int16ul, lifescan.crc_ccitt, construct.this.data.data), diff --git a/glucometerutils/support/serial.py b/glucometerutils/support/serial.py index c46d819..8dfe297 100644 --- a/glucometerutils/support/serial.py +++ b/glucometerutils/support/serial.py @@ -11,7 +11,7 @@ import logging try: from typing import Optional, Text -except: +except ImportError: pass import serial @@ -19,7 +19,7 @@ import serial from glucometerutils import exceptions -class SerialDevice(object): +class SerialDevice: """A Serial-connected glucometer driver base. This class does not implement an actual driver by itself, but provides an |