diff --git a/.pylintrc b/.pylintrc index 60b70871..a6518171 100644 --- a/.pylintrc +++ b/.pylintrc @@ -9,4 +9,6 @@ disable= too-many-locals, too-many-nested-blocks, too-many-public-methods, - too-many-statements + too-many-return-statements, + too-many-statements, + unspecified-encoding diff --git a/pyftdi/bin/ftconf.py b/pyftdi/bin/ftconf.py index bbe88fc9..1fb36a7d 100755 --- a/pyftdi/bin/ftconf.py +++ b/pyftdi/bin/ftconf.py @@ -3,7 +3,7 @@ """Simple FTDI EEPROM configurator. """ -# Copyright (c) 2019-2022, Emmanuel Blot +# Copyright (c) 2019-2024, Emmanuel Blot # All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause @@ -11,7 +11,7 @@ from argparse import ArgumentParser, FileType from io import StringIO from logging import Formatter, StreamHandler, DEBUG, ERROR -from sys import modules, stderr, stdout +from sys import exit as sys_exit, modules, stderr, stdout from textwrap import fill from traceback import format_exc from pyftdi import FtdiLogger @@ -86,9 +86,9 @@ def main(): extra = argparser.add_argument_group(title='Extras') extra.add_argument('-v', '--verbose', action='count', default=0, - help='increase verbosity') + help='increase verbosity') extra.add_argument('-d', '--debug', action='store_true', - help='enable debug mode') + help='enable debug mode') args = argparser.parse_args() debug = args.debug @@ -138,13 +138,12 @@ def main(): helpstr = ', '.join(sorted(eeprom.properties)) print(fill(helpstr, initial_indent=' ', subsequent_indent=' ')) - exit(1) + sys_exit(1) for sep in ':=': if sep in conf: name, value = conf.split(sep, 1) if not value: - argparser.error('Configuration %s without value' % - conf) + argparser.error(f'Configuration {conf} without value') if value == 'help': value = '?' helpio = StringIO() @@ -153,10 +152,10 @@ def main(): if helpstr: print(fill(helpstr, initial_indent=' ', subsequent_indent=' ')) - exit(1) + sys_exit(1) break else: - argparser.error('Missing name:value separator in %s' % conf) + argparser.error(f'Missing name:value separator in {conf}') if args.vid: eeprom.set_property('vendor_id', args.vid) if args.pid: @@ -166,7 +165,7 @@ def main(): if args.hexblock is not None: indent = ' ' * args.hexblock for pos in range(0, len(eeprom.data), 16): - hexa = ' '.join(['%02x' % x for x in eeprom.data[pos:pos+16]]) + hexa = ' '.join([f'{x:02x}' for x in eeprom.data[pos:pos+16]]) print(indent, hexa, sep='') if args.update: if eeprom.commit(False, no_crc=args.full_erase): @@ -181,12 +180,12 @@ def main(): eeprom.save_config(ofp) except (ImportError, IOError, NotImplementedError, ValueError) as exc: - print('\nError: %s' % exc, file=stderr) + print(f'\nError: {exc}', file=stderr) if debug: print(format_exc(chain=False), file=stderr) - exit(1) + sys_exit(1) except KeyboardInterrupt: - exit(2) + sys_exit(2) if __name__ == '__main__': diff --git a/pyftdi/bin/ftdi_urls.py b/pyftdi/bin/ftdi_urls.py index eccb9bbb..b5993a08 100755 --- a/pyftdi/bin/ftdi_urls.py +++ b/pyftdi/bin/ftdi_urls.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2022, Emmanuel Blot +# Copyright (c) 2019-2024, Emmanuel Blot # All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause @@ -9,7 +9,7 @@ from argparse import ArgumentParser, FileType from logging import Formatter, StreamHandler, DEBUG, ERROR -from sys import modules, stderr +from sys import exit as sys_exit, modules, stderr from traceback import format_exc from pyftdi import FtdiLogger from pyftdi.ftdi import Ftdi @@ -62,12 +62,12 @@ def main(): Ftdi.show_devices() except (ImportError, IOError, NotImplementedError, ValueError) as exc: - print('\nError: %s' % exc, file=stderr) + print(f'\nError: {exc}', file=stderr) if debug: print(format_exc(chain=False), file=stderr) - exit(1) + sys_exit(1) except KeyboardInterrupt: - exit(2) + sys_exit(2) if __name__ == '__main__': diff --git a/pyftdi/bin/i2cscan.py b/pyftdi/bin/i2cscan.py index e062b42f..41f3dbcd 100755 --- a/pyftdi/bin/i2cscan.py +++ b/pyftdi/bin/i2cscan.py @@ -12,7 +12,7 @@ from argparse import ArgumentParser, FileType from logging import Formatter, StreamHandler, getLogger, DEBUG, ERROR -from sys import modules, stderr +from sys import exit as sys_exit, modules, stderr from traceback import format_exc from pyftdi import FtdiLogger from pyftdi.ftdi import Ftdi @@ -75,12 +75,12 @@ def scan(cls, url: str, smb_mode: bool = True, force: bool = False) \ i2c.terminate() columns = 16 row = 0 - print(' %s' % ''.join(' %01X ' % col for col in range(columns))) + print(' ', ''.join(f' {col:01X} ' for col in range(columns))) while True: chunk = slaves[row:row+columns] if not chunk: break - print(' %1X:' % (row//columns), ' '.join(chunk)) + print(f' {row//columns:01X}:', ' '.join(chunk)) row += columns @@ -140,16 +140,16 @@ def main(): I2cBusScanner.scan(args.device, not args.no_smb, args.force) except (ImportError, IOError, NotImplementedError, ValueError) as exc: - print('\nError: %s' % exc, file=stderr) + print(f'\nError: {exc}', file=stderr) if debug: print(format_exc(chain=False), file=stderr) - exit(1) + sys_exit(1) except KeyboardInterrupt: - exit(2) + sys_exit(2) if __name__ == '__main__': try: main() - except Exception as exc: - print(str(exc), file=stderr) + except Exception as _exc: + print(str(_exc), file=stderr) diff --git a/pyftdi/bin/pyterm.py b/pyftdi/bin/pyterm.py index d9fa3c85..90bfa264 100755 --- a/pyftdi/bin/pyterm.py +++ b/pyftdi/bin/pyterm.py @@ -18,7 +18,7 @@ from logging import Formatter, StreamHandler, DEBUG, ERROR from os import environ, linesep, stat from re import search -from sys import exit as sysexit, modules, platform, stderr, stdout +from sys import exit as sys_exit, modules, platform, stderr, stdout from time import sleep from threading import Event, Thread from traceback import format_exc @@ -57,7 +57,7 @@ def run(self, fullmode=False, loopback=False, silent=False, """Switch to a pure serial terminal application""" self._terminal.init(fullmode) - print('Entering minicom mode @ %d bps' % self._port.baudrate) + print(f'Entering minicom mode @ { self._port.baudrate} bps') stdout.flush() self._resume = True # start the reader (target to host direction) within a dedicated thread @@ -132,7 +132,7 @@ def _reader(self, loopback, getfunc): except KeyboardInterrupt: return except Exception as exc: - print("Exception: %s" % exc) + print(f'Exception: {exc}') if self._debug: print(format_exc(chain=False), file=stderr) interrupt_main() @@ -182,7 +182,7 @@ def _writer(self, fullmode, silent, localecho, crlf=0): def _cleanup(self, *args): """Cleanup resource before exiting""" if args and args[0]: - print('%sAborting...' % linesep) + print(f'{linesep}Aborting...') try: self._resume = False if self._port: @@ -222,7 +222,7 @@ def _open_port(device, baudrate, parity, rtscts, debug=False): if not vmo: # unable to parse version raise ValueError() - if tuple([int(x) for x in vmo.groups()]) < (3, 0): + if tuple(int(x) for x in vmo.groups()) < (3, 0): # pysrial version is too old raise ValueError() except (ValueError, IndexError, ImportError) as exc: @@ -243,10 +243,10 @@ def _open_port(device, baudrate, parity, rtscts, debug=False): if not port.is_open: port.open() if not port.is_open: - raise IOError('Cannot open port "%s"' % device) + raise IOError(f"Cannot open port '{device}'") if debug: backend = port.BACKEND if hasattr(port, 'BACKEND') else '?' - print("Using serial backend '%s'" % backend) + print(f"Using serial backend '{backend}'") return port except SerialException as exc: raise IOError(str(exc)) from exc @@ -272,7 +272,6 @@ def get_default_device() -> str: return device - def main(): """Main routine""" debug = False @@ -280,16 +279,16 @@ def main(): default_device = get_default_device() argparser = ArgumentParser(description=modules[__name__].__doc__) argparser.add_argument('-f', '--fullmode', dest='fullmode', - action='store_true', - help='use full terminal mode, exit with ' - '[Ctrl]+B') + action='store_true', + help='use full terminal mode, exit with ' + '[Ctrl]+B') argparser.add_argument('device', nargs='?', default=default_device, - help='serial port device name (default: %s)' % - default_device) + help=f'serial port device name ' + f'(default: {default_device}') argparser.add_argument('-b', '--baudrate', - help='serial port baudrate (default: %d)' % - MiniTerm.DEFAULT_BAUDRATE, - default='%s' % MiniTerm.DEFAULT_BAUDRATE) + help=f'serial port baudrate ', + f'(default: MiniTerm.DEFAULT_BAUDRATE)', + default=str(MiniTerm.DEFAULT_BAUDRATE)) argparser.add_argument('-w', '--hwflow', action='store_true', help='hardware flow control') @@ -355,12 +354,12 @@ def main(): args.crlf) except (IOError, ValueError) as exc: - print('\nError: %s' % exc, file=stderr) + print(f'\nError: {exc}', file=stderr) if debug: print(format_exc(chain=False), file=stderr) - sysexit(1) + sys_exit(1) except KeyboardInterrupt: - sysexit(2) + sys_exit(2) if __name__ == '__main__': diff --git a/pyftdi/eeprom.py b/pyftdi/eeprom.py index c894c15f..7e692504 100644 --- a/pyftdi/eeprom.py +++ b/pyftdi/eeprom.py @@ -12,16 +12,12 @@ from binascii import hexlify, unhexlify from collections import OrderedDict, namedtuple from configparser import ConfigParser -from enum import IntEnum -if sys.version_info[:2] > (3, 5): - from enum import IntFlag +from enum import IntEnum, IntFlag from logging import getLogger from random import randint from re import match from struct import calcsize as scalc, pack as spack, unpack as sunpack from typing import BinaryIO, List, Optional, Set, TextIO, Union, Tuple -if sys.version_info[:2] == (3, 5): - from aenum import IntFlag from usb.core import Device as UsbDevice from .ftdi import Ftdi, FtdiError from .misc import classproperty, to_bool, to_int @@ -69,7 +65,6 @@ class FtdiEeprom: } """EEPROM properties.""" - CBUS = IntEnum('CBus', 'TXDEN PWREN TXLED RXLED TXRXLED SLEEP CLK48 CLK24 CLK12 ' 'CLK6 GPIO BB_WR BB_RD', start=0) @@ -125,6 +120,7 @@ def __getattr__(self, name): @classproperty def eeprom_sizes(cls) -> List[int]: + # pylint: disable=no-self-argument """Return a list of supported EEPROM sizes. :return: the supported EEPROM sizes @@ -248,8 +244,8 @@ def storage_size(self) -> int: eeprom_storage_size = self.size if self.is_mirroring_enabled: eeprom_storage_size = self.mirror_sector - except FtdiError as fe: - raise fe + except FtdiError as exc: + raise exc return eeprom_storage_size @property @@ -262,7 +258,7 @@ def data(self) -> bytes: return bytes(self._eeprom) @property - def properties(self) -> Set[str]: + def properties(self) -> Set[str]: """Returns the supported properties for the current device. :return: the supported properies. @@ -342,7 +338,7 @@ def is_mirroring_enabled(self) -> bool: """ return self.has_mirroring and self._mirror - def enable_mirroring(self, enable : bool) -> None: + def enable_mirroring(self, enable: bool) -> None: """Enable EEPROM write mirroring. When enabled, this divides the EEPROM into 2 sectors and mirrors configuration data between them. @@ -625,7 +621,7 @@ def set_property(self, name: str, value: Union[str, int, bool], self._dirty.add(name) return if name.startswith('invert_'): - if not self.device_version in (0x600, 0x1000): + if self.device_version not in (0x600, 0x1000): raise ValueError('UART control line inversion not available ' 'with this device') self._set_invert(name[len('invert_'):], value, out) @@ -834,7 +830,7 @@ def _sync_eeprom(self, no_crc: bool = False): self.log.debug('No change detected for EEPROM content') return if not no_crc: - if any([x in self._dirty for x in self.VAR_STRINGS]): + if any(x in self._dirty for x in self.VAR_STRINGS): self._generate_var_strings() for varstr in self.VAR_STRINGS: self._dirty.discard(varstr) @@ -864,7 +860,7 @@ def _compute_crc(self, eeprom: Union[bytes, bytearray], check=False): if check: self._valid = not bool(crc) if not self._valid: - self.log.debug(f'CRC is now 0x{crc:04x}') + self.log.debug('CRC is now 0x%04x', crc) else: self.log.debug('CRC OK') return crc, crc_pos, crc_size @@ -878,8 +874,8 @@ def _update_crc(self): crc_s1_start = self.mirror_sector - crc_size self._eeprom[crc_s1_start:crc_s1_start+crc_size] = spack(' Tuple[int, bool]: + def _compute_size(self, eeprom: Union[bytes, bytearray]) \ + -> Tuple[int, bool]: """ :return: Tuple of: - int of usable size of the eeprom @@ -887,7 +883,7 @@ def _compute_size(self, """ if self._ftdi.is_eeprom_internal: return self._ftdi.max_eeprom_size, False - if all([x == 0xFF for x in eeprom]): + if all(x == 0xFF for x in eeprom): # erased EEPROM, size is unknown return self._ftdi.max_eeprom_size, False if eeprom[0:0x80] == eeprom[0x80:0x100]: @@ -989,8 +985,8 @@ def _set_cbus_func(self, cpin: int, value: str, try: code = cbus[value.upper()].value except KeyError as exc: - raise ValueError(f"CBUS pin '{cpin}'' does not have function " - f"{value}'") from exc + raise ValueError(f"CBUS pin '{cpin}' does not have function " + f"{value}'") from exc if pin_filter and not pin_filter(cpin, value.upper()): raise ValueError(f"Unsupported CBUS function '{value}' for pin " f"'{cpin}'") diff --git a/pyftdi/tests/bits.py b/pyftdi/tests/bits.py index 9764c48b..f275aa54 100755 --- a/pyftdi/tests/bits.py +++ b/pyftdi/tests/bits.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +"""BitSequence unit tests.""" + # Copyright (c) 2010-2016 Emmanuel Blot # Copyright (c) 2010-2016, Neotion # All rights reserved. diff --git a/pyftdi/tests/cbus.py b/pyftdi/tests/cbus.py index 726f47d5..e6679d16 100755 --- a/pyftdi/tests/cbus.py +++ b/pyftdi/tests/cbus.py @@ -1,7 +1,9 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2020, Emmanuel Blot +"""CBUS unit tests.""" + +# Copyright (c) 2020-2024, Emmanuel Blot # All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause diff --git a/pyftdi/tests/eeprom.py b/pyftdi/tests/eeprom.py index cd3e6e0d..670c584e 100755 --- a/pyftdi/tests/eeprom.py +++ b/pyftdi/tests/eeprom.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +"""EEPROM unit tests.""" + # Copyright (c) 2018, Stephen Goadhouse # Copyright (c) 2019-2024, Emmanuel Blot # All rights reserved. @@ -42,7 +44,7 @@ def setUp(self): ftdi.open_bitbang_from_url(self.url, direction=out_pins) self.ftdi = ftdi except IOError as exc: - raise IOError('Unable to open USB port: %s' % str(exc)) from exc + raise IOError(f'Unable to open USB port: {exc}') from exc def tearDown(self): """Close the FTDI connection""" @@ -106,7 +108,7 @@ def main(): try: loglevel = getattr(logging, level) except AttributeError as exc: - raise ValueError('Invalid log level: %s' % level) from exc + raise ValueError(f'Invalid log level: {level}') from exc FtdiLogger.set_level(loglevel) testmod(modules[__name__]) unittest.main(defaultTest='suite') diff --git a/pyftdi/tests/eeprom_mock.py b/pyftdi/tests/eeprom_mock.py index a5b73cee..d14602ea 100644 --- a/pyftdi/tests/eeprom_mock.py +++ b/pyftdi/tests/eeprom_mock.py @@ -8,11 +8,11 @@ import logging from os import environ from sys import modules, stdout -from unittest import TestCase, TestSuite, SkipTest, makeSuite, main as ut_main +from unittest import TestCase, TestSuite, makeSuite, main as ut_main from pyftdi import FtdiLogger from pyftdi.ftdi import Ftdi from pyftdi.eeprom import FtdiEeprom -from pyftdi.misc import to_bool, hexdump +from pyftdi.misc import to_bool from pyftdi.ftdi import FtdiError VirtLoader = None