From a5160a59cf3c3883083f0285b0661955be5e065f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 15 May 2025 21:01:50 +0000 Subject: [PATCH] change to ruff --- .gitattributes | 11 + .pre-commit-config.yaml | 43 +- .pylintrc | 400 ------------------ README.rst | 6 +- adafruit_ble/__init__.py | 25 +- adafruit_ble/advertising/__init__.py | 53 +-- adafruit_ble/advertising/adafruit.py | 1 + adafruit_ble/advertising/standard.py | 55 +-- adafruit_ble/attributes/__init__.py | 2 +- adafruit_ble/characteristics/__init__.py | 12 +- adafruit_ble/characteristics/float.py | 10 +- adafruit_ble/characteristics/int.py | 32 +- adafruit_ble/characteristics/json.py | 13 +- adafruit_ble/characteristics/stream.py | 17 +- adafruit_ble/characteristics/string.py | 16 +- adafruit_ble/services/__init__.py | 5 +- adafruit_ble/services/circuitpython.py | 4 +- adafruit_ble/services/nordic.py | 13 +- adafruit_ble/services/sphero.py | 2 +- adafruit_ble/services/standard/__init__.py | 14 +- adafruit_ble/services/standard/device_info.py | 12 +- adafruit_ble/services/standard/hid.py | 57 +-- adafruit_ble/uuid/__init__.py | 1 - docs/api.rst | 3 + docs/conf.py | 8 +- examples/ble_advertising_simpletest.py | 1 - examples/ble_bluefruit_color_picker.py | 3 +- examples/ble_bluefruit_connect_plotter.py | 8 +- examples/ble_color_proximity.py | 4 +- examples/ble_current_time_service.py | 1 + examples/ble_demo_central.py | 5 +- examples/ble_demo_periph.py | 2 +- examples/ble_detailed_scan.py | 1 - examples/ble_device_info_service.py | 1 + examples/ble_hid_periph.py | 3 +- examples/ble_json_central.py | 2 +- examples/ble_json_peripheral.py | 5 +- examples/ble_json_service.py | 6 +- examples/ble_packet_buffer_service.py | 12 +- examples/ble_packet_buffer_test.py | 1 - examples/ble_uart_echo_client.py | 4 +- ruff.toml | 116 +++++ 42 files changed, 301 insertions(+), 689 deletions(-) create mode 100644 .gitattributes delete mode 100644 .pylintrc create mode 100644 ruff.toml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..21c125c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +.py text eol=lf +.rst text eol=lf +.txt text eol=lf +.yaml text eol=lf +.toml text eol=lf +.license text eol=lf +.md text eol=lf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 374676d..ff19dde 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,42 +1,21 @@ -# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò +# SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries # # SPDX-License-Identifier: Unlicense repos: - - repo: https://github.com/python/black - rev: 23.3.0 - hooks: - - id: black - - repo: https://github.com/fsfe/reuse-tool - rev: v1.1.2 - hooks: - - id: reuse - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/pycqa/pylint - rev: v3.3.1 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.4 hooks: - - id: pylint - name: pylint (library code) - types: [python] - args: - - --disable=consider-using-f-string - exclude: "^(docs/|examples/|tests/|setup.py$)" - - id: pylint - name: pylint (example code) - description: Run pylint rules on "examples/*.py" files - types: [python] - files: "^examples/" - args: - - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code - - id: pylint - name: pylint (test code) - description: Run pylint rules on "tests/*.py" files - types: [python] - files: "^tests/" - args: - - --disable=missing-docstring,consider-using-f-string,duplicate-code + - id: ruff-format + - id: ruff + args: ["--fix"] + - repo: https://github.com/fsfe/reuse-tool + rev: v3.0.1 + hooks: + - id: reuse diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 82b04fe..0000000 --- a/.pylintrc +++ /dev/null @@ -1,400 +0,0 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries -# -# SPDX-License-Identifier: Unlicense - -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Add files or directories to the ignore-list. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the ignore-list. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins=pylint.extensions.no_self_use - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -# disable=import-error,raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,deprecated-str-translate-call -disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable= - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio).You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -# notes=FIXME,XXX,TODO -notes=FIXME,XXX - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules=board - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -# expected-line-ending-format= -expected-line-ending-format=LF - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=100 - -# Maximum number of lines in a module -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=yes - -# Minimum lines number of a similarity. -min-similarity-lines=12 - - -[BASIC] - -# Regular expression matching correct argument names -argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct attribute names -attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct class names -# class-rgx=[A-Z_][a-zA-Z0-9]+$ -class-rgx=[A-Z_][a-zA-Z0-9_]+$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Regular expression matching correct function names -function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Good variable names which should always be accepted, separated by a comma -# good-names=i,j,k,ex,Run,_ -good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_ - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct method names -method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Regular expression matching correct variable names -variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=optparse,tkinter.tix - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# Maximum number of arguments for function / method -# Changed for this library, Adafruit_CircuitPython_BLE -max-args=9 - -# Maximum number of attributes for a class (see R0902). -# max-attributes=7 -max-attributes=11 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of statements in function / method body -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=1 - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=builtins.Exception diff --git a/README.rst b/README.rst index 8d50913..f426b6a 100644 --- a/README.rst +++ b/README.rst @@ -13,9 +13,9 @@ Introduction :target: https://github.com/adafruit/Adafruit_CircuitPython_ble/actions :alt: Build Status -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code Style: Black +.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json + :target: https://github.com/astral-sh/ruff + :alt: Code Style: Ruff This module provides higher-level BLE (Bluetooth Low Energy) functionality, building on the native `_bleio` module. diff --git a/adafruit_ble/__init__.py b/adafruit_ble/__init__.py index 693a47f..69f7d5d 100755 --- a/adafruit_ble/__init__.py +++ b/adafruit_ble/__init__.py @@ -12,29 +12,28 @@ from __future__ import annotations -# pylint: disable=wrong-import-position - import sys if sys.implementation.name == "circuitpython" and sys.implementation.version[0] <= 4: raise ImportError( "This release is not compatible with CircuitPython 4.x; use library release 1.x.x" ) -# pylint: enable=wrong-import-position import _bleio -from .services import Service from .advertising import Advertisement +from .services import Service try: - from typing import Iterator, NoReturn, Optional, Tuple, Type, TYPE_CHECKING, Union + from typing import TYPE_CHECKING, Iterator, NoReturn, Optional, Tuple, Type, Union + from typing_extensions import Literal if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer - from adafruit_ble.uuid import UUID + from adafruit_ble.characteristics import Characteristic + from adafruit_ble.uuid import UUID except ImportError: pass @@ -64,9 +63,7 @@ def _discover_remote(self, uuid: UUID) -> Optional[_bleio.Service]: if uuid in self._discovered_bleio_services: remote_service = self._discovered_bleio_services[uuid] else: - results = self._bleio_connection.discover_remote_services( - (uuid.bleio_uuid,) - ) + results = self._bleio_connection.discover_remote_services((uuid.bleio_uuid,)) if results: remote_service = results[0] self._discovered_bleio_services[uuid] = remote_service @@ -109,7 +106,7 @@ def __getitem__(self, key: Union[UUID, Type[Service]]) -> Optional[Service]: self._constructed_services[uuid] = constructed_service return constructed_service - raise KeyError("{!r} object has no service {}".format(self, key)) + raise KeyError(f"{self!r} object has no service {key}") @property def connected(self) -> bool: @@ -196,12 +193,8 @@ def start_advertising( if scan_response: scan_response_bytes = bytes(scan_response) - # pylint: disable=unexpected-keyword-arg # Remove after 5.x is no longer supported. - if ( - sys.implementation.name == "circuitpython" - and sys.implementation.version[0] <= 5 - ): + if sys.implementation.name == "circuitpython" and sys.implementation.version[0] <= 5: if timeout is not None: raise NotImplementedError("timeout not available for CircuitPython 5.x") self._adapter.start_advertising( @@ -364,7 +357,7 @@ def address_bytes(self) -> bytes: @property def advertising(self) -> bool: """The advertising state""" - return self._adapter.advertising # pylint: disable=no-member + return self._adapter.advertising def _clean_connection_cache(self) -> None: """Remove cached connections that have disconnected.""" diff --git a/adafruit_ble/advertising/__init__.py b/adafruit_ble/advertising/__init__.py index 02324d3..562bd86 100644 --- a/adafruit_ble/advertising/__init__.py +++ b/adafruit_ble/advertising/__init__.py @@ -11,15 +11,14 @@ import struct try: - from typing import Dict, Any, Union, List, Optional, Type, TypeVar, TYPE_CHECKING + from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, TypeVar, Union + from typing_extensions import Literal if TYPE_CHECKING: from _bleio import ScanEntry - LazyObjectField_GivenClass = TypeVar( # pylint: disable=invalid-name - "LazyObjectField_GivenClass" - ) + LazyObjectField_GivenClass = TypeVar("LazyObjectField_GivenClass") except ImportError: pass @@ -27,17 +26,15 @@ def to_hex(seq: bytes) -> str: """Pretty prints a byte sequence as hex values.""" - return " ".join("{:02x}".format(v) for v in seq) + return " ".join(f"{v:02x}" for v in seq) def to_bytes_literal(seq: bytes) -> str: """Prints a byte sequence as a Python bytes literal that only uses hex encoding.""" - return 'b"' + "".join("\\x{:02x}".format(v) for v in seq) + '"' + return 'b"' + "".join(f"\\x{v:02x}" for v in seq) + '"' -def decode_data( - data: bytes, *, key_encoding: str = "B" -) -> Dict[Any, Union[bytes, List[bytes]]]: +def decode_data(data: bytes, *, key_encoding: str = "B") -> Dict[Any, Union[bytes, List[bytes]]]: """Helper which decodes length encoded structures into a dictionary with the given key encoding.""" i = 0 @@ -94,7 +91,6 @@ def encode_data( return bytes(data) -# pylint: disable=too-few-public-methods class AdvertisingDataField: """Top level class for any descriptor classes that live in Advertisement or its subclasses.""" @@ -106,13 +102,13 @@ def __init__(self, bit_position: int) -> None: self._bitmask = 1 << bit_position def __get__( - self, obj: Optional["AdvertisingFlags"], cls: Type["AdvertisingFlags"] - ) -> Union[bool, "AdvertisingFlag"]: + self, obj: Optional[AdvertisingFlags], cls: Type[AdvertisingFlags] + ) -> Union[bool, AdvertisingFlag]: if obj is None: return self return (obj.flags & self._bitmask) != 0 - def __set__(self, obj: "AdvertisingFlags", value: bool) -> None: + def __set__(self, obj: AdvertisingFlags, value: bool) -> None: if value: obj.flags |= self._bitmask else: @@ -130,9 +126,7 @@ class AdvertisingFlags(AdvertisingDataField): """BR/EDR not supported.""" # BR/EDR flags not included here, since we don't support BR/EDR. - def __init__( - self, advertisement: "Advertisement", advertising_data_type: int - ) -> None: + def __init__(self, advertisement: Advertisement, advertising_data_type: int) -> None: self._advertisement = advertisement self._adt = advertising_data_type self.flags = 0 @@ -164,15 +158,15 @@ def __init__(self, *, advertising_data_type: int) -> None: self._adt = advertising_data_type def __get__( - self, obj: Optional["Advertisement"], cls: Type["Advertisement"] - ) -> Optional[Union[str, "String"]]: + self, obj: Optional[Advertisement], cls: Type[Advertisement] + ) -> Optional[Union[str, String]]: if obj is None: return self if self._adt not in obj.data_dict: return None return str(obj.data_dict[self._adt], "utf-8") - def __set__(self, obj: "Advertisement", value: str) -> None: + def __set__(self, obj: Advertisement, value: str) -> None: obj.data_dict[self._adt] = value.encode("utf-8") @@ -184,15 +178,15 @@ def __init__(self, struct_format: str, *, advertising_data_type: int) -> None: self._adt = advertising_data_type def __get__( - self, obj: Optional["Advertisement"], cls: Type["Advertisement"] - ) -> Optional[Union[Any, "Struct"]]: + self, obj: Optional[Advertisement], cls: Type[Advertisement] + ) -> Optional[Union[Any, Struct]]: if obj is None: return self if self._adt not in obj.data_dict: return None return struct.unpack(self._format, obj.data_dict[self._adt])[0] - def __set__(self, obj: "Advertisement", value: Any) -> None: + def __set__(self, obj: Advertisement, value: Any) -> None: obj.data_dict[self._adt] = struct.pack(self._format, value) @@ -207,9 +201,7 @@ def __init__( self._adt = advertising_data_type self._kwargs = kwargs - def __get__( - self, obj: Optional["Advertisement"], cls: Type["Advertisement"] - ) -> Any: + def __get__(self, obj: Optional[Advertisement], cls: Type[Advertisement]) -> Any: if obj is None: return self # Return None if our object is immutable and the data is not present. @@ -274,7 +266,7 @@ def __init__(self, *, entry: Optional[ScanEntry] = None) -> None: if entry: self.data_dict = decode_data(entry.advertisement_bytes) self.address = entry.address - self._rssi = entry.rssi # pylint: disable=protected-access + self._rssi = entry.rssi self.connectable = entry.connectable self.scan_response = entry.scan_response self.mutable = False @@ -305,8 +297,7 @@ def get_prefix_bytes(cls) -> Optional[bytes]: b"" if cls.match_prefixes is None else b"".join( - len(prefix).to_bytes(1, "little") + prefix - for prefix in cls.match_prefixes + len(prefix).to_bytes(1, "little") + prefix for prefix in cls.match_prefixes ) ) @@ -353,13 +344,11 @@ def __str__(self) -> str: continue value = getattr(self, attr) if value is not None: - parts.append("{}={}".format(attr, str(value))) + parts.append(f"{attr}={str(value)}") return "<{} {} >".format(self.__class__.__name__, " ".join(parts)) def __len__(self) -> int: return compute_length(self.data_dict) def __repr__(self) -> str: - return "Advertisement(data={})".format( - to_bytes_literal(encode_data(self.data_dict)) - ) + return f"Advertisement(data={to_bytes_literal(encode_data(self.data_dict))})" diff --git a/adafruit_ble/advertising/adafruit.py b/adafruit_ble/advertising/adafruit.py index ad3285b..4f30c56 100755 --- a/adafruit_ble/advertising/adafruit.py +++ b/adafruit_ble/advertising/adafruit.py @@ -15,6 +15,7 @@ """ import struct + from micropython import const from . import Advertisement, LazyObjectField diff --git a/adafruit_ble/advertising/standard.py b/adafruit_ble/advertising/standard.py index 3bfc1a1..7d22363 100644 --- a/adafruit_ble/advertising/standard.py +++ b/adafruit_ble/advertising/standard.py @@ -14,22 +14,24 @@ import struct from collections import OrderedDict, namedtuple +from ..uuid import StandardUUID, VendorUUID from . import ( Advertisement, AdvertisingDataField, - encode_data, + compute_length, decode_data, + encode_data, to_hex, - compute_length, ) -from ..uuid import StandardUUID, VendorUUID try: - from typing import Optional, List, Tuple, Union, Type, Iterator, Iterable, Any - from adafruit_ble.uuid import UUID - from adafruit_ble.services import Service + from typing import Any, Iterable, Iterator, List, Optional, Tuple, Type, Union + from _bleio import ScanEntry + from adafruit_ble.services import Service + from adafruit_ble.uuid import UUID + UsesServicesAdvertisement = Union[ "ProvideServicesAdvertisement", "SolicitServicesAdvertisement" ] @@ -50,7 +52,7 @@ def __init__( advertisement: UsesServicesAdvertisement, *, standard_services: List[int], - vendor_services: List[int] + vendor_services: List[int], ) -> None: self._advertisement = advertisement self._standard_service_fields = standard_services @@ -96,16 +98,10 @@ def __iter__(self) -> Iterator[UUID]: # TODO: Differentiate between complete and incomplete lists. def append(self, service: Service) -> None: """Append a service to the list.""" - if ( - isinstance(service.uuid, StandardUUID) - and service not in self._standard_services - ): + if isinstance(service.uuid, StandardUUID) and service not in self._standard_services: self._standard_services.append(service.uuid) self._update(self._standard_service_fields[0], self._standard_services) - elif ( - isinstance(service.uuid, VendorUUID) - and service not in self._vendor_services - ): + elif isinstance(service.uuid, VendorUUID) and service not in self._vendor_services: self._vendor_services.append(service.uuid) self._update(self._vendor_service_fields[0], self._vendor_services) @@ -121,10 +117,7 @@ def extend(self, services: Iterable[Service]) -> None: ): self._standard_services.append(service.uuid) standard = True - elif ( - isinstance(service.uuid, VendorUUID) - and service.uuid not in self._vendor_services - ): + elif isinstance(service.uuid, VendorUUID) and service.uuid not in self._vendor_services: self._vendor_services.append(service.uuid) vendor = True @@ -145,9 +138,7 @@ def __str__(self) -> str: class ServiceList(AdvertisingDataField): """Descriptor for a list of Service UUIDs that lazily binds a corresponding BoundServiceList.""" - def __init__( - self, *, standard_services: List[int], vendor_services: List[int] - ) -> None: + def __init__(self, *, standard_services: List[int], vendor_services: List[int]) -> None: self.standard_services = standard_services self.vendor_services = vendor_services @@ -243,7 +234,7 @@ def __init__( *, advertising_data_type: int = 0xFF, company_id: int, - key_encoding: str = "B" + key_encoding: str = "B", ) -> None: self._obj = obj self._company_id = company_id @@ -272,9 +263,7 @@ def __bytes__(self) -> bytes: def __str__(self) -> str: hex_data = to_hex(encode_data(self.data, key_encoding=self._key_encoding)) - return "".format( - self.company_id, hex_data - ) + return f"" class ManufacturerDataField: @@ -288,12 +277,8 @@ def __init__( # TODO: Support format strings that use numbers to repeat a given type. For now, we strip # numbers because Radio specifies string length with it. self.element_count = len(value_format.strip("> 1 and ( - not field_names or len(field_names) != self.element_count - ): - raise ValueError( - "Provide field_names when multiple values are in the format" - ) + if self.element_count > 1 and (not field_names or len(field_names) != self.element_count): + raise ValueError("Provide field_names when multiple values are in the format") self._entry_length = struct.calcsize(value_format) self.field_names = field_names if field_names: @@ -331,9 +316,7 @@ def __get__( def __set__(self, obj: "Advertisement", value: Any) -> None: if not obj.mutable: raise AttributeError() - if isinstance(value, tuple) and ( - self.element_count == 1 or isinstance(value[0], tuple) - ): + if isinstance(value, tuple) and (self.element_count == 1 or isinstance(value[0], tuple)): packed = bytearray(self._entry_length * len(value)) for i, entry in enumerate(value): offset = i * self._entry_length @@ -359,7 +342,7 @@ def __init__(self, service: Service) -> None: self._adt = 0x21 self._prefix = bytes(service.uuid) - def __get__( # pylint: disable=too-many-return-statements,too-many-branches + def __get__( self, obj: Optional[Service], cls: Type[Service] ) -> Optional[Union["ServiceData", memoryview]]: if obj is None: diff --git a/adafruit_ble/attributes/__init__.py b/adafruit_ble/attributes/__init__.py index 1f10dbd..77a77fd 100644 --- a/adafruit_ble/attributes/__init__.py +++ b/adafruit_ble/attributes/__init__.py @@ -10,6 +10,7 @@ specifically characteristics and descriptors. """ + import _bleio __version__ = "0.0.0+auto.0" @@ -48,7 +49,6 @@ class Attribute: security_mode: authenticated data signing, without man-in-the-middle protection """ - # pylint: disable=too-few-public-methods NO_ACCESS = _bleio.Attribute.NO_ACCESS OPEN = _bleio.Attribute.OPEN ENCRYPT_NO_MITM = _bleio.Attribute.ENCRYPT_NO_MITM diff --git a/adafruit_ble/characteristics/__init__.py b/adafruit_ble/characteristics/__init__.py index 42a5868..b212875 100644 --- a/adafruit_ble/characteristics/__init__.py +++ b/adafruit_ble/characteristics/__init__.py @@ -11,17 +11,19 @@ from __future__ import annotations import struct + import _bleio from ..attributes import Attribute try: - from typing import Optional, Type, Union, Tuple, Iterable, TYPE_CHECKING + from typing import TYPE_CHECKING, Iterable, Optional, Tuple, Type, Union if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer - from adafruit_ble.uuid import UUID + from adafruit_ble.services import Service + from adafruit_ble.uuid import UUID except ImportError: pass @@ -107,9 +109,7 @@ def __init__( self.fixed_length = fixed_length self.initial_value = initial_value - def _ensure_bound( - self, service: Service, initial_value: Optional[bytes] = None - ) -> None: + def _ensure_bound(self, service: Service, initial_value: Optional[bytes] = None) -> None: """Binds the characteristic to the local Service or remote Characteristic object given.""" if self.field_name in service.bleio_characteristics: return @@ -263,7 +263,7 @@ def __init__( def __get__( self, obj: Optional[Service], cls: Optional[Type[Service]] = None - ) -> Optional[Union[Tuple, "StructCharacteristic"]]: + ) -> Optional[Union[Tuple, StructCharacteristic]]: if obj is None: return self raw_data = super().__get__(obj, cls) diff --git a/adafruit_ble/characteristics/float.py b/adafruit_ble/characteristics/float.py index 69915eb..bd01033 100644 --- a/adafruit_ble/characteristics/float.py +++ b/adafruit_ble/characteristics/float.py @@ -12,16 +12,16 @@ from __future__ import annotations -from . import Attribute -from . import StructCharacteristic +from . import Attribute, StructCharacteristic try: - from typing import Optional, Type, Union, TYPE_CHECKING + from typing import TYPE_CHECKING, Optional, Type, Union if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer - from adafruit_ble.uuid import UUID + from adafruit_ble.services import Service + from adafruit_ble.uuid import UUID except ImportError: pass @@ -55,7 +55,7 @@ def __init__( def __get__( self, obj: Optional[Service], cls: Optional[Type[Service]] = None - ) -> Union[float, "FloatCharacteristic"]: + ) -> Union[float, FloatCharacteristic]: if obj is None: return self return super().__get__(obj)[0] diff --git a/adafruit_ble/characteristics/int.py b/adafruit_ble/characteristics/int.py index 52dbd80..3773bd6 100755 --- a/adafruit_ble/characteristics/int.py +++ b/adafruit_ble/characteristics/int.py @@ -12,16 +12,16 @@ from __future__ import annotations -from . import Attribute -from . import StructCharacteristic +from . import Attribute, StructCharacteristic try: - from typing import Optional, Type, Union, TYPE_CHECKING + from typing import TYPE_CHECKING, Optional, Type, Union if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer - from adafruit_ble.uuid import UUID + from adafruit_ble.services import Service + from adafruit_ble.uuid import UUID except ImportError: pass @@ -63,7 +63,7 @@ def __init__( def __get__( self, obj: Optional[Service], cls: Optional[Type[Service]] = None - ) -> Union[int, "IntCharacteristic"]: + ) -> Union[int, IntCharacteristic]: if obj is None: return self return super().__get__(obj)[0] @@ -77,17 +77,13 @@ def __set__(self, obj: Service, value: int) -> None: class Int8Characteristic(IntCharacteristic): """Int8 number.""" - # pylint: disable=too-few-public-methods - def __init__( - self, *, min_value: int = -128, max_value: int = 127, **kwargs - ) -> None: + def __init__(self, *, min_value: int = -128, max_value: int = 127, **kwargs) -> None: super().__init__(" None: super().__init__(" No class Int16Characteristic(IntCharacteristic): """Int16 number.""" - # pylint: disable=too-few-public-methods - def __init__( - self, *, min_value: int = -32768, max_value: int = 32767, **kwargs - ) -> None: + def __init__(self, *, min_value: int = -32768, max_value: int = 32767, **kwargs) -> None: super().__init__(" None: + def __init__(self, *, min_value: int = 0, max_value: int = 0xFFFF, **kwargs) -> None: super().__init__(" None: @@ -125,8 +114,5 @@ def __init__( class Uint32Characteristic(IntCharacteristic): """Uint32 number.""" - # pylint: disable=too-few-public-methods - def __init__( - self, *, min_value: int = 0, max_value: int = 0xFFFFFFFF, **kwargs - ) -> None: + def __init__(self, *, min_value: int = 0, max_value: int = 0xFFFFFFFF, **kwargs) -> None: super().__init__(" Any: """Converts a utf-8 encoded JSON string into a python value.""" return json.loads(str(value, "utf-8")) - def __get__( - self, obj: Optional[Service], cls: Optional[Type[Service]] = None - ) -> Any: + def __get__(self, obj: Optional[Service], cls: Optional[Type[Service]] = None) -> Any: if obj is None: return self return self.unpack(super().__get__(obj, cls)) diff --git a/adafruit_ble/characteristics/stream.py b/adafruit_ble/characteristics/stream.py index 1582e9d..c3a75ef 100755 --- a/adafruit_ble/characteristics/stream.py +++ b/adafruit_ble/characteristics/stream.py @@ -15,18 +15,17 @@ import _bleio -from . import Attribute -from . import Characteristic -from . import ComplexCharacteristic +from . import Attribute, Characteristic, ComplexCharacteristic try: - from typing import Optional, Union, TYPE_CHECKING + from typing import TYPE_CHECKING, Optional, Union if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer + from adafruit_ble.characteristics import Characteristic - from adafruit_ble.uuid import UUID from adafruit_ble.services import Service + from adafruit_ble.uuid import UUID except ImportError: pass @@ -73,9 +72,7 @@ def __init__( max_length=buffer_size, ) - def bind( - self, service: Service - ) -> Union[_bleio.CharacteristicBuffer, BoundWriteStream]: + def bind(self, service: Service) -> Union[_bleio.CharacteristicBuffer, BoundWriteStream]: """Binds the characteristic to the given Service.""" bound_characteristic = super().bind(service) # If we're given a remote service then we're the client and need to buffer in. @@ -111,9 +108,7 @@ def __init__( max_length=buffer_size, ) - def bind( - self, service: Service - ) -> Union[_bleio.CharacteristicBuffer, BoundWriteStream]: + def bind(self, service: Service) -> Union[_bleio.CharacteristicBuffer, BoundWriteStream]: """Binds the characteristic to the given Service.""" bound_characteristic = super().bind(service) # If the service is remote need to write out. diff --git a/adafruit_ble/characteristics/string.py b/adafruit_ble/characteristics/string.py index 7326bc7..de9d33a 100755 --- a/adafruit_ble/characteristics/string.py +++ b/adafruit_ble/characteristics/string.py @@ -12,16 +12,16 @@ from __future__ import annotations -from . import Attribute -from . import Characteristic +from . import Attribute, Characteristic try: - from typing import Optional, Type, Union, TYPE_CHECKING + from typing import TYPE_CHECKING, Optional, Type, Union if TYPE_CHECKING: from circuitpython_typing import ReadableBuffer - from adafruit_ble.uuid import UUID + from adafruit_ble.services import Service + from adafruit_ble.uuid import UUID except ImportError: pass @@ -54,7 +54,7 @@ def __init__( def __get__( self, obj: Optional[Service], cls: Optional[Type[Service]] = None - ) -> Union[str, "StringCharacteristic"]: + ) -> Union[str, StringCharacteristic]: if obj is None: return self return str(super().__get__(obj, cls), "utf-8") @@ -66,9 +66,7 @@ def __set__(self, obj: Service, value: str) -> None: class FixedStringCharacteristic(Characteristic): """Fixed strings are set once when bound and unchanged after.""" - def __init__( - self, *, uuid: Optional[UUID] = None, read_perm: int = Attribute.OPEN - ) -> None: + def __init__(self, *, uuid: Optional[UUID] = None, read_perm: int = Attribute.OPEN) -> None: super().__init__( uuid=uuid, properties=Characteristic.READ, @@ -79,7 +77,7 @@ def __init__( def __get__( self, obj: Service, cls: Optional[Type[Service]] = None - ) -> Union[str, "FixedStringCharacteristic"]: + ) -> Union[str, FixedStringCharacteristic]: if obj is None: return self return str(super().__get__(obj, cls), "utf-8") diff --git a/adafruit_ble/services/__init__.py b/adafruit_ble/services/__init__.py index 2fd0789..cebaeb7 100644 --- a/adafruit_ble/services/__init__.py +++ b/adafruit_ble/services/__init__.py @@ -44,10 +44,7 @@ def __init__( **initial_values, ) -> None: if service is None: - # pylint: disable=no-member - self.bleio_service = _bleio.Service( - self.uuid.bleio_uuid, secondary=secondary - ) + self.bleio_service = _bleio.Service(self.uuid.bleio_uuid, secondary=secondary) elif not service.remote: raise ValueError("Can only create services with a remote service or None") else: diff --git a/adafruit_ble/services/circuitpython.py b/adafruit_ble/services/circuitpython.py index 3d58b88..bc9079f 100755 --- a/adafruit_ble/services/circuitpython.py +++ b/adafruit_ble/services/circuitpython.py @@ -10,11 +10,11 @@ """ -from . import Service from ..characteristics import Characteristic from ..characteristics.stream import StreamOut from ..characteristics.string import StringCharacteristic from ..uuid import VendorUUID +from . import Service __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git" @@ -24,7 +24,7 @@ class CircuitPythonUUID(VendorUUID): """UUIDs with the CircuitPython base UUID.""" def __init__(self, uuid16: int) -> None: - uuid128 = bytearray("nhtyPtiucriC".encode("utf-8") + b"\x00\x00\xaf\xad") + uuid128 = bytearray(b"nhtyPtiucriC" + b"\x00\x00\xaf\xad") uuid128[-3] = uuid16 >> 8 uuid128[-4] = uuid16 & 0xFF super().__init__(uuid128) diff --git a/adafruit_ble/services/nordic.py b/adafruit_ble/services/nordic.py index f71e761..cdbf0e0 100755 --- a/adafruit_ble/services/nordic.py +++ b/adafruit_ble/services/nordic.py @@ -13,16 +13,16 @@ from __future__ import annotations -from . import Service +from ..characteristics.stream import StreamIn, StreamOut from ..uuid import VendorUUID -from ..characteristics.stream import StreamOut, StreamIn +from . import Service try: - from typing import Optional, TYPE_CHECKING + from typing import TYPE_CHECKING, Optional if TYPE_CHECKING: - from circuitpython_typing import WriteableBuffer, ReadableBuffer import _bleio + from circuitpython_typing import ReadableBuffer, WriteableBuffer except ImportError: pass @@ -38,7 +38,6 @@ class UARTService(Service): See ``examples/ble_uart_echo_test.py`` for a usage example. """ - # pylint: disable=no-member uuid = VendorUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E") _server_tx = StreamOut( uuid=VendorUUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"), @@ -83,9 +82,7 @@ def read(self, nbytes: Optional[int] = None) -> Optional[bytes]: """ return self._rx.read(nbytes) - def readinto( - self, buf: WriteableBuffer, nbytes: Optional[int] = None - ) -> Optional[int]: + def readinto(self, buf: WriteableBuffer, nbytes: Optional[int] = None) -> Optional[int]: """ Read bytes into the ``buf``. If ``nbytes`` is specified then read at most that many bytes. Otherwise, read at most ``len(buf)`` bytes. diff --git a/adafruit_ble/services/sphero.py b/adafruit_ble/services/sphero.py index 2c34d6f..0fa3337 100644 --- a/adafruit_ble/services/sphero.py +++ b/adafruit_ble/services/sphero.py @@ -10,8 +10,8 @@ """ -from . import Service from ..uuid import VendorUUID +from . import Service __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git" diff --git a/adafruit_ble/services/standard/__init__.py b/adafruit_ble/services/standard/__init__.py index 91fe0bb..f00ba56 100644 --- a/adafruit_ble/services/standard/__init__.py +++ b/adafruit_ble/services/standard/__init__.py @@ -12,12 +12,11 @@ import time -from .. import Service -from ...uuid import StandardUUID -from ...characteristics import Characteristic -from ...characteristics.string import StringCharacteristic -from ...characteristics import StructCharacteristic +from ...characteristics import Characteristic, StructCharacteristic from ...characteristics.int import Uint8Characteristic +from ...characteristics.string import StringCharacteristic +from ...uuid import StandardUUID +from .. import Service __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE.git" @@ -26,7 +25,6 @@ class AppearanceCharacteristic(StructCharacteristic): """What type of device it is""" - # pylint: disable=too-few-public-methods uuid = StandardUUID(0x2A01) def __init__(self, **kwargs) -> None: @@ -80,6 +78,4 @@ def struct_time(self) -> time.struct_time: """ year, month, day, hour, minute, second, weekday, _, _ = self.current_time # Bluetooth weekdays count from 1. struct_time counts from 0. - return time.struct_time( - (year, month, day, hour, minute, second, weekday - 1, -1, -1) - ) + return time.struct_time((year, month, day, hour, minute, second, weekday - 1, -1, -1)) diff --git a/adafruit_ble/services/standard/device_info.py b/adafruit_ble/services/standard/device_info.py index ebed6a7..65813cc 100644 --- a/adafruit_ble/services/standard/device_info.py +++ b/adafruit_ble/services/standard/device_info.py @@ -15,13 +15,13 @@ import os import sys -from .. import Service -from ...uuid import StandardUUID from ...characteristics import StructCharacteristic from ...characteristics.string import FixedStringCharacteristic +from ...uuid import StandardUUID +from .. import Service try: - from typing import Iterable, Optional, TYPE_CHECKING + from typing import TYPE_CHECKING, Iterable, Optional if TYPE_CHECKING: import _bleio @@ -62,11 +62,9 @@ def __init__( model_number = sys.platform if serial_number is None: try: - import microcontroller # pylint: disable=import-outside-toplevel + import microcontroller - serial_number = binascii.hexlify( - microcontroller.cpu.uid # pylint: disable=no-member - ).decode("utf-8") + serial_number = binascii.hexlify(microcontroller.cpu.uid).decode("utf-8") except ImportError: pass if firmware_revision is None: diff --git a/adafruit_ble/services/standard/hid.py b/adafruit_ble/services/standard/hid.py index e8e6aa9..03f4dcf 100755 --- a/adafruit_ble/services/standard/hid.py +++ b/adafruit_ble/services/standard/hid.py @@ -16,11 +16,10 @@ import struct -from micropython import const import _bleio +from micropython import const -from adafruit_ble.characteristics import Attribute -from adafruit_ble.characteristics import Characteristic +from adafruit_ble.characteristics import Attribute, Characteristic from adafruit_ble.characteristics.int import Uint8Characteristic from adafruit_ble.uuid import StandardUUID @@ -48,15 +47,14 @@ _APPEARANCE_HID_JOYSTICK = const(963) _APPEARANCE_HID_GAMEPAD = const(964) -# pylint: disable=line-too-long DEFAULT_HID_DESCRIPTOR = ( b"\x05\x01" # Usage Page (Generic Desktop Ctrls) b"\x09\x06" # Usage (Keyboard) - b"\xA1\x01" # Collection (Application) + b"\xa1\x01" # Collection (Application) b"\x85\x01" # Report ID (1) b"\x05\x07" # Usage Page (Kbrd/Keypad) - b"\x19\xE0" # Usage Minimum (\xE0) - b"\x29\xE7" # Usage Maximum (\xE7) + b"\x19\xe0" # Usage Minimum (\xE0) + b"\x29\xe7" # Usage Maximum (\xE7) b"\x15\x00" # Logical Minimum (0) b"\x25\x01" # Logical Maximum (1) b"\x75\x01" # Report Size (1) @@ -80,12 +78,12 @@ b"\x91\x02" # Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) b"\x95\x03" # Report Count (3) b"\x91\x01" # Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - b"\xC0" # End Collection + b"\xc0" # End Collection b"\x05\x01" # Usage Page (Generic Desktop Ctrls) b"\x09\x02" # Usage (Mouse) - b"\xA1\x01" # Collection (Application) + b"\xa1\x01" # Collection (Application) b"\x09\x01" # Usage (Pointer) - b"\xA1\x00" # Collection (Physical) + b"\xa1\x00" # Collection (Physical) b"\x85\x02" # Report ID (2) b"\x05\x09" # Usage Page (Button) b"\x19\x01" # Usage Minimum (\x01) @@ -102,30 +100,30 @@ b"\x09\x30" # Usage (X) b"\x09\x31" # Usage (Y) b"\x15\x81" # Logical Minimum (-127) - b"\x25\x7F" # Logical Maximum (127) + b"\x25\x7f" # Logical Maximum (127) b"\x75\x08" # Report Size (8) b"\x95\x02" # Report Count (2) b"\x81\x06" # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) b"\x09\x38" # Usage (Wheel) b"\x15\x81" # Logical Minimum (-127) - b"\x25\x7F" # Logical Maximum (127) + b"\x25\x7f" # Logical Maximum (127) b"\x75\x08" # Report Size (8) b"\x95\x01" # Report Count (1) b"\x81\x06" # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - b"\xC0" # End Collection - b"\xC0" # End Collection - b"\x05\x0C" # Usage Page (Consumer) + b"\xc0" # End Collection + b"\xc0" # End Collection + b"\x05\x0c" # Usage Page (Consumer) b"\x09\x01" # Usage (Consumer Control) - b"\xA1\x01" # Collection (Application) + b"\xa1\x01" # Collection (Application) b"\x85\x03" # Report ID (3) b"\x75\x10" # Report Size (16) b"\x95\x01" # Report Count (1) b"\x15\x01" # Logical Minimum (1) - b"\x26\x8C\x02" # Logical Maximum (652) + b"\x26\x8c\x02" # Logical Maximum (652) b"\x19\x01" # Usage Minimum (Consumer Control) - b"\x2A\x8C\x02" # Usage Maximum (AC Send) + b"\x2a\x8c\x02" # Usage Maximum (AC Send) b"\x81\x00" # Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - b"\xC0" # End Collection + b"\xc0" # End Collection # b'\x05\x01' # Usage Page (Generic Desktop Ctrls) # b'\x09\x05' # Usage (Game Pad) # b'\xA1\x01' # Collection (Application) @@ -151,7 +149,6 @@ # b'\xC0' # End Collection ) """Default HID descriptor: provides mouse, keyboard, and consumer control devices.""" -# pylint: enable=line-too-long # Boot keyboard and mouse not currently supported. @@ -211,7 +208,6 @@ def send_report(self, report: Dict) -> None: class ReportOut: """A single HID report that receives HID data from a client.""" - # pylint: disable=too-few-public-methods uuid = StandardUUID(_REPORT_UUID_NUM) def __init__( @@ -229,9 +225,7 @@ def __init__( max_length=max_length, fixed_length=True, properties=( - Characteristic.READ - | Characteristic.WRITE - | Characteristic.WRITE_NO_RESPONSE + Characteristic.READ | Characteristic.WRITE | Characteristic.WRITE_NO_RESPONSE ), read_perm=Attribute.ENCRYPT_NO_MITM, write_perm=Attribute.ENCRYPT_NO_MITM, @@ -292,11 +286,7 @@ class HIDService(Service): boot_keyboard_out = Characteristic( uuid=StandardUUID(0x2A32), - properties=( - Characteristic.READ - | Characteristic.WRITE - | Characteristic.WRITE_NO_RESPONSE - ), + properties=(Characteristic.READ | Characteristic.WRITE | Characteristic.WRITE_NO_RESPONSE), read_perm=Attribute.ENCRYPT_NO_MITM, write_perm=Attribute.ENCRYPT_NO_MITM, max_length=1, @@ -356,7 +346,6 @@ def __init__( self._init_devices() def _init_devices(self) -> None: - # pylint: disable=too-many-branches,too-many-statements,too-many-locals self.devices = [] hid_descriptor = self.report_map @@ -423,9 +412,7 @@ def get_report_info(collection: Dict, reports: Dict) -> None: if "type" in main: get_report_info(main, reports) else: - report_size, report_id, report_count = [ - x[0] for x in main["globals"][7:10] - ] + report_size, report_id, report_count = (x[0] for x in main["globals"][7:10]) if report_id not in reports: reports[report_id] = {"input_size": 0, "output_size": 0} if main["tag"] == "input": @@ -435,9 +422,7 @@ def get_report_info(collection: Dict, reports: Dict) -> None: for collection in top_level_collections: if collection["type"][0] != 1: - raise NotImplementedError( - "Only Application top level collections supported." - ) + raise NotImplementedError("Only Application top level collections supported.") usage_page = collection["globals"][0][0] usage = collection["locals"][0][0] reports = {} diff --git a/adafruit_ble/uuid/__init__.py b/adafruit_ble/uuid/__init__.py index 4459c6f..c0218cf 100644 --- a/adafruit_ble/uuid/__init__.py +++ b/adafruit_ble/uuid/__init__.py @@ -20,7 +20,6 @@ class UUID: """Top level UUID""" # TODO: Make subclassing _bleio.UUID work so we can just use it directly. - # pylint: disable=no-member def __hash__(self): return hash(self.bleio_uuid) diff --git a/docs/api.rst b/docs/api.rst index 20b685d..088eade 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,3 +1,6 @@ +API Reference +############# + :py:mod:`~adafruit_ble` ======================= diff --git a/docs/conf.py b/docs/conf.py index 930e065..7ddbfe4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,12 +1,10 @@ -# -*- coding: utf-8 -*- - # SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries # # SPDX-License-Identifier: MIT +import datetime import os import sys -import datetime sys.path.insert(0, os.path.abspath("..")) @@ -49,9 +47,7 @@ creation_year = "2019" current_year = str(datetime.datetime.now().year) year_duration = ( - current_year - if current_year == creation_year - else creation_year + " - " + current_year + current_year if current_year == creation_year else creation_year + " - " + current_year ) copyright = year_duration + " Dan Halbert for Adafruit Industries" author = "Dan Halbert" diff --git a/examples/ble_advertising_simpletest.py b/examples/ble_advertising_simpletest.py index 2c2815e..7a98199 100644 --- a/examples/ble_advertising_simpletest.py +++ b/examples/ble_advertising_simpletest.py @@ -6,7 +6,6 @@ """ from adafruit_ble import BLERadio - from adafruit_ble.advertising import Advertisement ble = BLERadio() diff --git a/examples/ble_bluefruit_color_picker.py b/examples/ble_bluefruit_color_picker.py index 4facbae..4cf7fdc 100755 --- a/examples/ble_bluefruit_color_picker.py +++ b/examples/ble_bluefruit_color_picker.py @@ -5,9 +5,8 @@ import board import neopixel - -from adafruit_bluefruit_connect.packet import Packet from adafruit_bluefruit_connect.color_packet import ColorPacket +from adafruit_bluefruit_connect.packet import Packet from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement diff --git a/examples/ble_bluefruit_connect_plotter.py b/examples/ble_bluefruit_connect_plotter.py index 542c714..e737ea2 100755 --- a/examples/ble_bluefruit_connect_plotter.py +++ b/examples/ble_bluefruit_connect_plotter.py @@ -4,9 +4,11 @@ # CircuitPython Bluefruit LE Connect Plotter Example import time -import board -import analogio + import adafruit_thermistor +import analogio +import board + from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement from adafruit_ble.services.nordic import UARTService @@ -34,5 +36,5 @@ def scale(value): while ble.connected: print((scale(light.value), thermistor.temperature)) - uart_server.write("{},{}\n".format(scale(light.value), thermistor.temperature)) + uart_server.write(f"{scale(light.value)},{thermistor.temperature}\n") time.sleep(0.1) diff --git a/examples/ble_color_proximity.py b/examples/ble_color_proximity.py index 31c56d3..7fa99e2 100644 --- a/examples/ble_color_proximity.py +++ b/examples/ble_color_proximity.py @@ -8,9 +8,9 @@ """ import time + import board import digitalio - import neopixel from adafruit_ble import BLERadio @@ -63,7 +63,7 @@ if last_i != i: color = color_options[i] neopixels.fill(color) - print("New color {:06x}".format(color)) + print(f"New color {color:06x}") advertisement.color = color ble.stop_advertising() ble.start_advertising(advertisement) diff --git a/examples/ble_current_time_service.py b/examples/ble_current_time_service.py index a62dfd0..6747c0c 100644 --- a/examples/ble_current_time_service.py +++ b/examples/ble_current_time_service.py @@ -7,6 +7,7 @@ """ import time + import adafruit_ble from adafruit_ble.advertising.standard import SolicitServicesAdvertisement from adafruit_ble.services.standard import CurrentTimeService diff --git a/examples/ble_demo_central.py b/examples/ble_demo_central.py index b7510ac..8ccda04 100644 --- a/examples/ble_demo_central.py +++ b/examples/ble_demo_central.py @@ -9,12 +9,11 @@ import time +import adafruit_lis3dh import board import busio import digitalio -import adafruit_lis3dh import neopixel - from adafruit_bluefruit_connect.color_packet import ColorPacket from adafruit_ble import BLERadio @@ -68,7 +67,7 @@ def scale(value): except OSError: try: uart_connection.disconnect() - except: # pylint: disable=bare-except + except: pass uart_connection = None time.sleep(0.3) diff --git a/examples/ble_demo_periph.py b/examples/ble_demo_periph.py index a9b5f92..bc45e7b 100644 --- a/examples/ble_demo_periph.py +++ b/examples/ble_demo_periph.py @@ -8,10 +8,10 @@ import board import neopixel +from adafruit_bluefruit_connect.color_packet import ColorPacket # Only the packet classes that are imported will be known to Packet. from adafruit_bluefruit_connect.packet import Packet -from adafruit_bluefruit_connect.color_packet import ColorPacket from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement diff --git a/examples/ble_detailed_scan.py b/examples/ble_detailed_scan.py index 7f5dfeb..cad9a3a 100644 --- a/examples/ble_detailed_scan.py +++ b/examples/ble_detailed_scan.py @@ -6,7 +6,6 @@ # specialty advertising types. from adafruit_ble import BLERadio - from adafruit_ble.advertising import Advertisement from adafruit_ble.advertising.standard import ProvideServicesAdvertisement diff --git a/examples/ble_device_info_service.py b/examples/ble_device_info_service.py index 34ac32b..32086c2 100644 --- a/examples/ble_device_info_service.py +++ b/examples/ble_device_info_service.py @@ -7,6 +7,7 @@ """ import time + import adafruit_ble from adafruit_ble.advertising.standard import Advertisement from adafruit_ble.services.standard.device_info import DeviceInfoService diff --git a/examples/ble_hid_periph.py b/examples/ble_hid_periph.py index 6b8053a..6224a95 100644 --- a/examples/ble_hid_periph.py +++ b/examples/ble_hid_periph.py @@ -15,9 +15,8 @@ import adafruit_ble from adafruit_ble.advertising import Advertisement from adafruit_ble.advertising.standard import ProvideServicesAdvertisement -from adafruit_ble.services.standard.hid import HIDService from adafruit_ble.services.standard.device_info import DeviceInfoService - +from adafruit_ble.services.standard.hid import HIDService # Use default HID descriptor hid = HIDService() diff --git a/examples/ble_json_central.py b/examples/ble_json_central.py index 654f7f4..557b183 100644 --- a/examples/ble_json_central.py +++ b/examples/ble_json_central.py @@ -5,10 +5,10 @@ # Read sensor readings from peripheral BLE device using a JSON characteristic. from ble_json_service import SensorService + from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement - ble = BLERadio() connection = None diff --git a/examples/ble_json_peripheral.py b/examples/ble_json_peripheral.py index e079a8a..14d13fb 100644 --- a/examples/ble_json_peripheral.py +++ b/examples/ble_json_peripheral.py @@ -4,13 +4,14 @@ # Provide readable sensor values and writable settings to connected devices via JSON characteristic. -import time import random +import time + from ble_json_service import SensorService + from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement - # Create BLE radio, custom service, and advertisement. ble = BLERadio() service = SensorService() diff --git a/examples/ble_json_service.py b/examples/ble_json_service.py index 6351564..eaf8ec1 100644 --- a/examples/ble_json_service.py +++ b/examples/ble_json_service.py @@ -4,10 +4,10 @@ # Read sensor readings from peripheral BLE device using a JSON characteristic. -from adafruit_ble.uuid import VendorUUID -from adafruit_ble.services import Service from adafruit_ble.characteristics import Characteristic from adafruit_ble.characteristics.json import JSONCharacteristic +from adafruit_ble.services import Service +from adafruit_ble.uuid import VendorUUID # A custom service with two JSON characteristics for this device. The "sensors" characteristic @@ -16,8 +16,6 @@ # service can be any valid random uuid (some BLE UUID's are reserved). # NOTE: JSON data is limited by characteristic max_length of 512 byes. class SensorService(Service): - # pylint: disable=too-few-public-methods - uuid = VendorUUID("51ad213f-e568-4e35-84e4-67af89c79ef0") settings = JSONCharacteristic( diff --git a/examples/ble_packet_buffer_service.py b/examples/ble_packet_buffer_service.py index 510e4f0..486ee3d 100644 --- a/examples/ble_packet_buffer_service.py +++ b/examples/ble_packet_buffer_service.py @@ -8,22 +8,20 @@ import _bleio -from adafruit_ble.services import Service from adafruit_ble.characteristics import ( Attribute, Characteristic, ComplexCharacteristic, ) +from adafruit_ble.services import Service from adafruit_ble.uuid import VendorUUID class PacketBufferUUID(VendorUUID): """UUIDs with the PacketBuffer base UUID.""" - # pylint: disable=too-few-public-methods - def __init__(self, uuid16): - uuid128 = bytearray("reffuBtekcaP".encode("utf-8") + b"\x00\x00\xaf\xad") + uuid128 = bytearray(b"reffuBtekcaP" + b"\x00\x00\xaf\xad") uuid128[-3] = uuid16 >> 8 uuid128[-4] = uuid16 & 0xFF super().__init__(uuid128) @@ -35,11 +33,9 @@ def __init__( *, uuid=None, buffer_size=4, - properties=Characteristic.WRITE_NO_RESPONSE - | Characteristic.NOTIFY - | Characteristic.READ, + properties=Characteristic.WRITE_NO_RESPONSE | Characteristic.NOTIFY | Characteristic.READ, read_perm=Attribute.OPEN, - write_perm=Attribute.OPEN + write_perm=Attribute.OPEN, ): self.buffer_size = buffer_size super().__init__( diff --git a/examples/ble_packet_buffer_test.py b/examples/ble_packet_buffer_test.py index 66c986f..3326ec5 100644 --- a/examples/ble_packet_buffer_test.py +++ b/examples/ble_packet_buffer_test.py @@ -11,7 +11,6 @@ from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ProvideServicesAdvertisement - ble = BLERadio() pbs = PacketBufferService() advertisement = ProvideServicesAdvertisement(pbs) diff --git a/examples/ble_uart_echo_client.py b/examples/ble_uart_echo_client.py index 48a0f23..28fc5ba 100644 --- a/examples/ble_uart_echo_client.py +++ b/examples/ble_uart_echo_client.py @@ -13,9 +13,7 @@ ble = BLERadio() while True: - while ble.connected and any( - UARTService in connection for connection in ble.connections - ): + while ble.connected and any(UARTService in connection for connection in ble.connections): for connection in ble.connections: if UARTService not in connection: continue diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..61f9966 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,116 @@ +# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +target-version = "py38" +line-length = 100 + +[lint] +preview = true +select = ["I", "PL", "UP"] + +extend-select = [ + "D419", # empty-docstring + "E501", # line-too-long + "W291", # trailing-whitespace + "PLC0414", # useless-import-alias + "PLC2401", # non-ascii-name + "PLC2801", # unnecessary-dunder-call + "PLC3002", # unnecessary-direct-lambda-call + "E999", # syntax-error + "PLE0101", # return-in-init + "F706", # return-outside-function + "F704", # yield-outside-function + "PLE0116", # continue-in-finally + "PLE0117", # nonlocal-without-binding + "PLE0241", # duplicate-bases + "PLE0302", # unexpected-special-method-signature + "PLE0604", # invalid-all-object + "PLE0605", # invalid-all-format + "PLE0643", # potential-index-error + "PLE0704", # misplaced-bare-raise + "PLE1141", # dict-iter-missing-items + "PLE1142", # await-outside-async + "PLE1205", # logging-too-many-args + "PLE1206", # logging-too-few-args + "PLE1307", # bad-string-format-type + "PLE1310", # bad-str-strip-call + "PLE1507", # invalid-envvar-value + "PLE2502", # bidirectional-unicode + "PLE2510", # invalid-character-backspace + "PLE2512", # invalid-character-sub + "PLE2513", # invalid-character-esc + "PLE2514", # invalid-character-nul + "PLE2515", # invalid-character-zero-width-space + "PLR0124", # comparison-with-itself + "PLR0202", # no-classmethod-decorator + "PLR0203", # no-staticmethod-decorator + "UP004", # useless-object-inheritance + "PLR0206", # property-with-parameters + "PLR0904", # too-many-public-methods + "PLR0911", # too-many-return-statements + "PLR0912", # too-many-branches + "PLR0913", # too-many-arguments + "PLR0914", # too-many-locals + "PLR0915", # too-many-statements + "PLR0916", # too-many-boolean-expressions + "PLR1702", # too-many-nested-blocks + "PLR1704", # redefined-argument-from-local + "PLR1711", # useless-return + "C416", # unnecessary-comprehension + "PLR1733", # unnecessary-dict-index-lookup + "PLR1736", # unnecessary-list-index-lookup + + # ruff reports this rule is unstable + #"PLR6301", # no-self-use + + "PLW0108", # unnecessary-lambda + "PLW0120", # useless-else-on-loop + "PLW0127", # self-assigning-variable + "PLW0129", # assert-on-string-literal + "B033", # duplicate-value + "PLW0131", # named-expr-without-context + "PLW0245", # super-without-brackets + "PLW0406", # import-self + "PLW0602", # global-variable-not-assigned + "PLW0603", # global-statement + "PLW0604", # global-at-module-level + + # fails on the try: import typing used by libraries + #"F401", # unused-import + + "F841", # unused-variable + "E722", # bare-except + "PLW0711", # binary-op-exception + "PLW1501", # bad-open-mode + "PLW1508", # invalid-envvar-default + "PLW1509", # subprocess-popen-preexec-fn + "PLW2101", # useless-with-lock + "PLW3301", # nested-min-max +] + +ignore = [ + "PLR2004", # magic-value-comparison + "UP030", # format literals + "PLW1514", # unspecified-encoding + "PLR0913", # too-many-arguments + "PLR0915", # too-many-statements + "PLR0917", # too-many-positional-arguments + "PLR0904", # too-many-public-methods + "PLR0912", # too-many-branches + "PLR0916", # too-many-boolean-expressions + "PLR6301", # could-be-static no-self-use + "PLC0415", # import outside toplevel + "UP006", # built-in instead of typing import + "UP007", # use x | y for annatoations + "PLC2701", # private import + "PLW2901", # for loop var overwritten + "PLW1641", # object not implement hash + "PLR0911", # too many return + "E501", # line too long + "PLR0914", # too many local vars + "E722", # bare except +] + +[format] +line-ending = "lf"