diff --git a/.flake8 b/.flake8 index d1b156813..a3c0629ce 100644 --- a/.flake8 +++ b/.flake8 @@ -1,12 +1,33 @@ [flake8] -max-line-length = 120 +max-line-length = 127 ignore = + # continuation line over-indented for hanging indent + E126, # continuation line over-indented for visual indent E127, # continuation line under-indented for visual indent - E128 + E128, + # line break before binary operator + W503, + # We don't always want periods at the end of the first docstring line + D400, + # We dont rephrase to imperative mood + D401 per-file-ignores = # Only in __init__files ignore imported but unused # Not necessary, if __all__ is declared in __init__ file # https://www.python.org/dev/peps/pep-0008/#id48 - __init__.py:F401 + __init__.py:F401, + components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py:W605, + components/controls/buttons_usb_encoder/*.py:E402 +count = True +max-complexity = 12 +statistics = True +show-source = True +filename = *.py,*.py.* +extend-exclude = + # Ignore dirs and files, which are from external sources + components/displays/HD44780-i2c/ + scripts/Reader.py.pcsc + # Ignore helper scripts + scripts/helperscripts/ diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 6cb871112..b7eab32ef 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -30,13 +30,12 @@ jobs: pip install spidev pip install -r requirements.txt pip install -r requirements-GPIO.txt + - name: Setup flake8 annotations + uses: rbialon/flake8-annotations@v1 - name: Lint with flake8 run: | pip install flake8 - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --filename=*.py,*.py.* - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --filename=*.py,*.py.* + flake8 --config .flake8 - name: Test with pytest run: | pytest --cov --cov-config=.coveragerc --cov-report xml diff --git a/components/bluetooth-sink-switch/bt-sink-switch.py b/components/bluetooth-sink-switch/bt-sink-switch.py index a107703a7..7fe2d918f 100755 --- a/components/bluetooth-sink-switch/bt-sink-switch.py +++ b/components/bluetooth-sink-switch/bt-sink-switch.py @@ -47,13 +47,15 @@ def bt_check_mpc_err() -> None: logger.debug(mpcplay) -def bt_switch(cmd, led_pin=None): +def bt_switch(cmd, led_pin=None): # noqa C901 """ - Set/Toggle between regular speakers and headphone output. If no bluetooth device is connected, always defaults to mpc output 1 + Set/Toggle between regular speakers and headphone output. If no bluetooth device is connected, + always defaults to mpc output 1 To be precise: toggle between mpc output 1 and mpc output 2. - So, set up your /etc/mpd.conf correctly: first audio_output section should be speakers, second audio_output section should be headphones + So, set up your /etc/mpd.conf correctly: first audio_output section should be speakers, + second audio_output section should be headphones To set up bluetooth headphones, follow the wiki Short guide to connect bluetooth (without audio setup) sudo bluetoothctl @@ -71,13 +73,16 @@ def bt_switch(cmd, led_pin=None): sudo apt install bluetooth Attention - The user to runs this script (precisly who runs bluetoothctl) needs proper access rights. Otherwise bluetoothctl will always return "no default controller found" + The user to runs this script (precisly who runs bluetoothctl) needs proper access rights. + Otherwise bluetoothctl will always return "no default controller found" The superuser and users of group "bluetooth" have these. You can check the policy here /etc/dbus-1/system.d/bluetooth.conf Best to check first if the user which later runs this script can execute bluetoothctl and get meaningful results sudo -u www-data bluetoothctl show - E.g. if you want to do bluetooth manipulation from the web interface, you will most likely need to add www-data to the group bluetooth - if you want to test this script from the command line, you will most likely need to add user pi (or whoever you are) to the group bluetooth or run it as superuser + E.g. if you want to do bluetooth manipulation from the web interface, you will most likely need to add www-data + to the group bluetooth + if you want to test this script from the command line, you will most likely need to add user pi + (or whoever you are) to the group bluetooth or run it as superuser sudo usermod -G bluetooth -a www-data Don't forget to reboot for group changes to take effect here @@ -86,14 +91,17 @@ def bt_switch(cmd, led_pin=None): off = speakers, on = headphones LED blinks if no bluetooth device is connected and bluetooth sink is requested, before script default to output 1 - A note for developers: This script is not persistent and only gets called (from various sources) when the output sink is changed/toggled and exits. + A note for developers: This script is not persistent and only gets called (from various sources) + when the output sink is changed/toggled and exits. This is done to make is callable from button press (gpio button handler), rfid card number, web interface - The LED state however should be persistent. With GPIOZero, the LED state gets reset at the end of the script. For that reason GPIO state is manipulated through shell commands + The LED state however should be persistent. With GPIOZero, the LED state gets reset at the end of the script. + For that reason GPIO state is manipulated through shell commands Parameters ---------- :param cmd: string is "toggle" | "speakers" | "headphones" - :param led_pin: integer with GPIO pin number of LED to reflect output status. If None, LED support is disabled (and no GPIO pin is blocked) + :param led_pin: integer with GPIO pin number of LED to reflect output status. If None, LED support is disabled + (and no GPIO pin is blocked) """ # Check for valid command if cmd != "toggle" and cmd != "speakers" and cmd != "headphones": @@ -127,14 +135,15 @@ def bt_switch(cmd, led_pin=None): logger.debug(isSpeakerOn_console.stdout) isSpeakerOn = re.search(b"^Output 1.*enabled", isSpeakerOn_console.stdout) - # Figure out if a bluetooth device is connected (any device will do). Assume here that only speakers/headsets will be connected + # Figure out if a bluetooth device is connected (any device will do). Assume here that only speakers/headsets + # will be connected # -> No need for user to adapt MAC address # -> will actually support multiple speakers/headsets paired to the phoniebox # Alternative: Check for specific bluetooth device only with "bluetoothctl info MACADDRESS" isBtConnected_console = subprocess.run("bluetoothctl info", shell=True, check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.debug(isBtConnected_console.stdout) - isBtConnected = re.search(b"Connected:\s+yes", isBtConnected_console.stdout) + isBtConnected = re.search(b"Connected:\s+yes", isBtConnected_console.stdout) # noqa W605 if (cmd == "toggle" and isSpeakerOn) or (cmd == "headphones"): # Only switch to BT headphones if they are actually connected @@ -207,7 +216,7 @@ def get_led_pin_config(cfg_file): if cfg[section_name].getboolean('enabled', fallback=False): led_pin = cfg[section_name].getint('led_pin', fallback=None) if not led_pin: - logger.warning(f"Could not find 'led_pin' or could not read integer value") + logger.warning("Could not find 'led_pin' or could not read integer value") elif not 1 <= led_pin <= 27: logger.warning(f"Ignoring out of range pin number: {led_pin}.") led_pin = None diff --git a/components/controls/buttons-bluetooth-headphone/bt-buttons.py b/components/controls/buttons-bluetooth-headphone/bt-buttons.py index d079ae510..09dfaf25a 100755 --- a/components/controls/buttons-bluetooth-headphone/bt-buttons.py +++ b/components/controls/buttons-bluetooth-headphone/bt-buttons.py @@ -56,7 +56,7 @@ def bt_on_disconnect(mpd_support=0) -> None: """ logger.info("on disconnect") if mpd_support: - pctproc = subprocess.run(f"{os.path.dirname(os.path.realpath(__file__))}/../../../scripts/playout_controls.sh -c=bluetoothtoggle -v=speakers", shell=True, check=False, + pctproc = subprocess.run(f"{os.path.dirname(os.path.realpath(__file__))}/../../../scripts/playout_controls.sh -c=bluetoothtoggle -v=speakers", shell=True, check=False, # noqa: E501 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.debug(pctproc.stdout) @@ -71,7 +71,7 @@ def bt_on_connect(mpd_support=0) -> None: """ logger.info("on connect") if mpd_support: - pctproc = subprocess.run(f"{os.path.dirname(os.path.realpath(__file__))}/../../../scripts/playout_controls.sh -c=bluetoothtoggle -v=headphones", shell=True, check=False, + pctproc = subprocess.run(f"{os.path.dirname(os.path.realpath(__file__))}/../../../scripts/playout_controls.sh -c=bluetoothtoggle -v=headphones", shell=True, check=False, # noqa: E501 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.debug(pctproc.stdout) @@ -139,17 +139,17 @@ def bt_key_handler(name, mpd_support=0) -> None: # Only act on button press, not button release if event.value == 1: if event.code == bt_keycode_play: - proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerpause", shell=True, check=False, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerpause", shell=True, + check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) elif event.code == bt_keycode_pause: - proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerpause", shell=True, check=False, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerpause", shell=True, + check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) elif event.code == bt_keycode_next: - proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playernext", shell=True, check=False, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playernext", shell=True, + check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) elif event.code == bt_keycode_prev: - proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerprev", shell=True, check=False, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + proc = subprocess.run(f"{path}/../../../scripts/playout_controls.sh -c=playerprev", shell=True, + check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) logger.debug(proc.stdout) if proc.returncode != 0: logger.error("#" * 60) diff --git a/components/controls/buttons_usb_encoder/buttons_usb_encoder.py b/components/controls/buttons_usb_encoder/buttons_usb_encoder.py index e8fa807a9..777278467 100644 --- a/components/controls/buttons_usb_encoder/buttons_usb_encoder.py +++ b/components/controls/buttons_usb_encoder/buttons_usb_encoder.py @@ -28,10 +28,11 @@ function_args = button_map[button_string + "_args"] try: getattr(function_calls, function_name)(function_args) - except: + except Exception: logger.warning( - "Function " + function_name + " not found in function_calls.py (mapped from button: " + button_string + ")") + "Function " + function_name + + " not found in function_calls.py (mapped from button: " + button_string + ")") except KeyError: logger.warning("Button " + button_string + " not mapped to any function.") -except: +except Exception: logger.error("An error with Buttons USB Encoder occurred.") diff --git a/components/controls/buttons_usb_encoder/io_buttons_usb_encoder.py b/components/controls/buttons_usb_encoder/io_buttons_usb_encoder.py index c20e5c366..2f03f8191 100644 --- a/components/controls/buttons_usb_encoder/io_buttons_usb_encoder.py +++ b/components/controls/buttons_usb_encoder/io_buttons_usb_encoder.py @@ -28,7 +28,7 @@ def current_device(): break try: _current_device - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure it is connected' % device_name) return _current_device diff --git a/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py b/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py index 394564de6..e832e1c52 100644 --- a/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py +++ b/components/controls/buttons_usb_encoder/map_buttons_usb_encoder.py @@ -11,7 +11,7 @@ sys.path.append(".") -try: +try: # noqa C901 functions = list( filter(lambda function_name: function_name.startswith("functionCall"), dir(components.gpio_control.function_calls.phoniebox_function_calls))) @@ -43,7 +43,8 @@ button_map[button_string] = function_name button_map[button_string + "_args"] = function_args - print("Button '" + button_string + "' is now mapped to '" + function_name_short + "' with argument '" + str(function_args) + "'") + print("Button '" + button_string + "' is now mapped to '" + function_name_short + + "' with argument '" + str(function_args) + "'") break except KeyboardInterrupt: continue diff --git a/components/gpio_control/config_compatibility.py b/components/gpio_control/config_compatibility.py index 9c2e92f5d..59a32f18d 100644 --- a/components/gpio_control/config_compatibility.py +++ b/components/gpio_control/config_compatibility.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -import configparser + import os from shutil import copyfile -def Ini_CheckAndUpgrade(config): +def Ini_CheckAndUpgrade(config): # noqa C901 has_changed = False for section in config.sections(): # enable: True --> enabled: True diff --git a/components/gpio_control/function_calls.py b/components/gpio_control/function_calls.py index c3eda5913..9978a7695 100644 --- a/components/gpio_control/function_calls.py +++ b/components/gpio_control/function_calls.py @@ -100,10 +100,10 @@ def functionCallBluetoothToggle(self, mode=None, *args): function_call("{command} -c=bluetoothtoggle -v={value}".format(command=self.playout_control, value=mode), shell=True) def functionCallTriggerPlayCardId(self, cardid, *args): - function_call("{command} --cardid={value}".format(command=self.rfid_trigger, value = cardid), shell=True) + function_call("{command} --cardid={value}".format(command=self.rfid_trigger, value=cardid), shell=True) def functionCallTriggerPlayFolder(self, folder, *args): - function_call("{command} --dir={value}".format(command=self.rfid_trigger, value = folder), shell=True) + function_call("{command} --dir={value}".format(command=self.rfid_trigger, value=folder), shell=True) def getFunctionCall(self, functionName): self.logger.error('Get FunctionCall: {} {}'.format(functionName, functionName in locals())) diff --git a/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py b/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py index 583ad0c9b..87a5d070f 100644 --- a/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py +++ b/components/smart-home-automation/MQTT-protocol/daemon_mqtt_client.py @@ -3,10 +3,9 @@ import datetime import os import re -import ssl import subprocess import time -from threading import * +from threading import Thread import inotify.adapters import paho.mqtt.client as mqtt diff --git a/scripts/Reader.py b/scripts/Reader.py index d3c09f2b6..b6ec9a4ba 100755 --- a/scripts/Reader.py +++ b/scripts/Reader.py @@ -45,7 +45,7 @@ def __init__(self): break try: self.dev - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure is connected' % deviceName) def readCard(self): diff --git a/scripts/Reader.py.Multi b/scripts/Reader.py.Multi index 5e98b4d0f..1b2ac3d3d 100644 --- a/scripts/Reader.py.Multi +++ b/scripts/Reader.py.Multi @@ -49,7 +49,7 @@ class Reader: for dev in devs: try: dev - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure is connected' % dev.name) str_devs = ','.join([str(x) for x in devs]) diff --git a/scripts/Reader.py.experimental b/scripts/Reader.py.experimental index e3854f629..36429314c 100755 --- a/scripts/Reader.py.experimental +++ b/scripts/Reader.py.experimental @@ -11,7 +11,7 @@ import sys import RPi.GPIO as GPIO import logging -from evdev import InputDevice, categorize, ecodes, list_devices +from evdev import InputDevice, ecodes, list_devices logger = logging.getLogger(__name__) @@ -131,7 +131,7 @@ class Rdm6300Reader: else: return None - def readCard(self): + def readCard(self): # noqa C901 byte_card_id = bytearray() try: @@ -188,7 +188,7 @@ class Pn532Reader: from py532lib.i2c import Pn532_i2c from py532lib.mifare import Mifare from py532lib.mifare import MIFARE_WAIT_FOR_ENTRY - pn532 = Pn532_i2c() + pn532 = Pn532_i2c() # noqa F841 self.device = Mifare() self.device.SAMconfigure() self.device.set_max_retries(MIFARE_WAIT_FOR_ENTRY) @@ -213,7 +213,8 @@ class Reader(object): if device_name == 'MFRC522': self.reader = Mfrc522Reader() elif device_name == 'RDM6300': - # The Rdm6300Reader supports 2 Additional Number Formats which can bee choosen by an optional parameter dictionary: + # The Rdm6300Reader supports 2 Additional Number Formats which can be choosen + # by an optional parameter dictionary: # {'numberformat':'card_id_float'} or {'numberformat':'card_id_dec'} self.reader = Rdm6300Reader() elif device_name == 'PN532': diff --git a/scripts/Reader.py.experimental.Multi b/scripts/Reader.py.experimental.Multi index b7c4fcb5f..a0d518ff7 100644 --- a/scripts/Reader.py.experimental.Multi +++ b/scripts/Reader.py.experimental.Multi @@ -17,13 +17,6 @@ import RPi.GPIO as GPIO import logging from enum import Enum from evdev import InputDevice, ecodes, list_devices -# Workaround: when using RC522 reader with pirc522 pkg the py532lib pkg may not be installed and vice-versa -try: - import pirc522 - from py532lib.i2c import * - from py532lib.mifare import * -except ImportError: - pass logger = logging.getLogger(__name__) @@ -165,7 +158,10 @@ class Rdm6300Reader: class Pn532Reader: def __init__(self): - pn532 = Pn532_i2c() + from py532lib.i2c import Pn532_i2c + from py532lib.mifare import Mifare + from py532lib.mifare import MIFARE_WAIT_FOR_ENTRY + pn532 = Pn532_i2c() # noqa F841 self.device = Mifare() self.device.SAMconfigure() self.device.set_max_retries(MIFARE_WAIT_FOR_ENTRY) diff --git a/scripts/Reader.py.kkmoonRFIDreader b/scripts/Reader.py.kkmoonRFIDreader index 10853b41b..0c55ec060 100755 --- a/scripts/Reader.py.kkmoonRFIDreader +++ b/scripts/Reader.py.kkmoonRFIDreader @@ -9,7 +9,7 @@ import os.path import sys -from evdev import InputDevice, categorize, ecodes, list_devices +from evdev import InputDevice, ecodes, list_devices from select import select @@ -44,7 +44,7 @@ class Reader: break try: self.dev - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure is connected' % deviceName) def readCard(self): diff --git a/scripts/Reader.py.original b/scripts/Reader.py.original index 80a4fabf3..1212155b3 100755 --- a/scripts/Reader.py.original +++ b/scripts/Reader.py.original @@ -19,7 +19,7 @@ import os.path import sys -from evdev import InputDevice, categorize, ecodes, list_devices +from evdev import InputDevice, ecodes, list_devices from select import select import logging logger = logging.getLogger(__name__) @@ -51,7 +51,7 @@ class Reader: break try: self.dev - except: + except Exception: sys.exit('Could not find the device %s\n. Make sure is connected' % deviceName) def readCard(self): diff --git a/scripts/Reader.py.pcsc b/scripts/Reader.py.pcsc index 792b29f01..0cc50cd77 100644 --- a/scripts/Reader.py.pcsc +++ b/scripts/Reader.py.pcsc @@ -22,16 +22,12 @@ class Reader: try: hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER) if hresult != SCARD_S_SUCCESS: - raise error( - 'Failed to establish context: ' + \ - SCardGetErrorMessage(hresult)) + raise error('Failed to establish context: ' + SCardGetErrorMessage(hresult)) try: hresult, readers = SCardListReaders(hcontext, []) if hresult != SCARD_S_SUCCESS: - raise error( - 'Failed to list readers: ' + \ - SCardGetErrorMessage(hresult)) + raise error('Failed to list readers: ' + SCardGetErrorMessage(hresult)) readerstates = [] for i in range(len(readers)): @@ -57,9 +53,7 @@ class Reader: finally: hresult = SCardReleaseContext(hcontext) if hresult != SCARD_S_SUCCESS: - raise error( - 'Failed to release context: ' + \ - SCardGetErrorMessage(hresult)) + raise error('Failed to release context: ' + SCardGetErrorMessage(hresult)) return (toHexString(response, PACK)) diff --git a/scripts/RegisterDevice.py.Multi b/scripts/RegisterDevice.py.Multi index 008121496..9e9e40143 100644 --- a/scripts/RegisterDevice.py.Multi +++ b/scripts/RegisterDevice.py.Multi @@ -51,7 +51,7 @@ def setupMFRC522(): runCmd("cp {0}/scripts/Reader.py.experimental.Multi {1}/scripts/Reader.py".format(JUKEBOX_HOME_DIR, JUKEBOX_HOME_DIR)) -from Reader import get_devices, EDevices +from Reader import get_devices, EDevices # noqa E402 list_dev_ids = list() devices = get_devices() diff --git a/scripts/daemon_rfid_reader.py b/scripts/daemon_rfid_reader.py index b37c96bba..a7e5cf78f 100755 --- a/scripts/daemon_rfid_reader.py +++ b/scripts/daemon_rfid_reader.py @@ -57,7 +57,7 @@ # if controlcards delay is deactivated, let the cards pass, otherwise, they have to wait... if sspc_nodelay == "ON": - ids = re.findall("(\d+)", string) + ids = re.findall("(\d+)", string) # noqa W605 else: ids = "" @@ -69,7 +69,7 @@ def handler(signum, frame): # force pause the player script logger.info('Trigger Pause Force') subprocess.call([dir_path + '/playout_controls.sh -c=playerpauseforce -v=0.1'], shell=True) - except OSError as e: + except OSError: logger.info('Execution of Pause failed.') diff --git a/scripts/helperscripts/organizeFiles.py b/scripts/helperscripts/organizeFiles.py index 06c372633..7c387ec0f 100644 --- a/scripts/helperscripts/organizeFiles.py +++ b/scripts/helperscripts/organizeFiles.py @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- -import sys import os import argparse