Skip to content
Permalink
Browse files

Fix most of the pylint output, and hide away some that is not needed.

Again, this is not ready for CI yet unfortunately :(
  • Loading branch information...
Flameeyes committed Dec 12, 2018
1 parent 457a733 commit 2dcbe101b49dd942adbc78e61bf8011d3e8e1d5c
@@ -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, _
@@ -6,20 +6,17 @@
__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:
@@ -26,8 +26,8 @@
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 @@

_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 @@ def _get_records_reader(self):
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 @@ def get_glucose_unit(self):
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 @@ def get_readings(self):
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))
@@ -55,7 +55,7 @@ def get_meter_info(self):
'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

@@ -205,7 +205,7 @@ def get_serial_number(self):
"""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.
@@ -29,38 +29,42 @@


_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
# of June and July are written in full, everything else is truncated to three
# 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 @@ def _send_command(self, command):

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 @@ def connect(self):
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 @@ def _fetch_device_information(self):
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 @@ def get_meter_info(self):
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 @@ def set_datetime(self, date=datetime.datetime.now()):
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 @@ def get_readings(self):
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,20 +244,23 @@ def get_readings(self):
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)
if not match:
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 @@ def get_readings(self):

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)
@@ -64,7 +64,7 @@ def get_meter_info(self):
'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 @@ def get_readings(self):
# 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(

0 comments on commit 2dcbe10

Please sign in to comment.
You can’t perform that action at this time.