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/.github/workflows/release_gh.yml b/.github/workflows/release_gh.yml index b8aa8d6..9acec60 100644 --- a/.github/workflows/release_gh.yml +++ b/.github/workflows/release_gh.yml @@ -16,3 +16,4 @@ jobs: uses: adafruit/workflows-circuitpython-libs/release-gh@main with: github-token: ${{ secrets.GITHUB_TOKEN }} + upload-url: ${{ github.event.release.upload_url }} diff --git a/.gitignore b/.gitignore index 544ec4a..db3d538 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ _build # Virtual environment-specific files .env +.venv # MacOS-specific files *.DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e5fccc..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: 22.3.0 - hooks: - - id: black - - repo: https://github.com/fsfe/reuse-tool - rev: v0.14.0 - hooks: - - id: reuse - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.5.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/pycqa/pylint - rev: v2.15.5 + - 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 40208c3..0000000 --- a/.pylintrc +++ /dev/null @@ -1,399 +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 -max-args=5 - -# 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=Exception diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 33c2a61..88bca9f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,6 +8,9 @@ # Required version: 2 +sphinx: + configuration: docs/conf.py + build: os: ubuntu-20.04 tools: diff --git a/README.rst b/README.rst index e4dc7cb..bc4fc31 100644 --- a/README.rst +++ b/README.rst @@ -17,9 +17,9 @@ Introduction :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 Simple BLE Service for reading and writing files over BLE. This BLE service is geared towards file transfer to and from a device running the service. A core part of the protocol is free space diff --git a/adafruit_ble_file_transfer.py b/adafruit_ble_file_transfer.py index 61cc750..0409656 100644 --- a/adafruit_ble_file_transfer.py +++ b/adafruit_ble_file_transfer.py @@ -14,17 +14,18 @@ import struct import time -import _bleio +import _bleio from adafruit_ble.attributes import Attribute from adafruit_ble.characteristics import Characteristic, ComplexCharacteristic from adafruit_ble.characteristics.int import Uint32Characteristic -from adafruit_ble.uuid import VendorUUID, StandardUUID from adafruit_ble.services import Service +from adafruit_ble.uuid import StandardUUID, VendorUUID try: - from typing import Optional, List - from circuitpython_typing import WriteableBuffer, ReadableBuffer + from typing import List, Optional + + from circuitpython_typing import ReadableBuffer, WriteableBuffer except ImportError: pass @@ -37,10 +38,8 @@ class FileTransferUUID(VendorUUID): """UUIDs with the CircuitPython base UUID.""" - # pylint: disable=too-few-public-methods - def __init__(self, uuid16: int) -> None: - uuid128 = bytearray("refsnarTeliF".encode("utf-8") + b"\x00\x00\xaf\xad") + uuid128 = bytearray(b"refsnarTeliF" + b"\x00\x00\xaf\xad") uuid128[-3] = uuid16 >> 8 uuid128[-4] = uuid16 & 0xFF super().__init__(uuid128) @@ -50,8 +49,6 @@ class _TransferCharacteristic(ComplexCharacteristic): """Endpoint for sending commands to a media player. The value read will list all available commands.""" - # pylint: disable=too-few-public-methods - uuid = FileTransferUUID(0x0200) def __init__(self) -> None: @@ -68,9 +65,7 @@ def __init__(self) -> None: def bind(self, service: "FileTransferService") -> _bleio.PacketBuffer: """Binds the characteristic to the given Service.""" bound_characteristic = super().bind(service) - return _bleio.PacketBuffer( - bound_characteristic, buffer_size=4, max_packet_size=512 - ) + return _bleio.PacketBuffer(bound_characteristic, buffer_size=4, max_packet_size=512) class FileTransferService(Service): @@ -79,14 +74,10 @@ class FileTransferService(Service): The server dictates data transfer chunk sizes so it can minimize buffer sizes on its end. """ - # pylint: disable=too-few-public-methods - uuid = StandardUUID(0xFEBB) version = Uint32Characteristic(uuid=FileTransferUUID(0x0100), initial_value=4) raw = _TransferCharacteristic() - # _raw gets shadowed for each MIDIService instance by a PacketBuffer. PyLint doesn't know this - # so it complains about missing members. - # pylint: disable=no-member + # _raw gets shadowed for each MIDIService instance by a PacketBuffer. # Commands INVALID = 0x00 @@ -107,7 +98,7 @@ class FileTransferService(Service): # Responses # 0x00 is INVALID - OK = 0x01 # pylint: disable=invalid-name + OK = 0x01 ERROR = 0x02 ERROR_NO_FILE = 0x03 ERROR_PROTOCOL = 0x04 @@ -152,15 +143,11 @@ def _readinto(self, buffer: WriteableBuffer) -> bytearray: def read(self, path: str, *, offset: int = 0) -> bytearray: """Returns the contents of the file at the given path starting at the given offset""" - # pylint: disable=too-many-locals path = path.encode("utf-8") chunk_size = CHUNK_SIZE start_offset = offset encoded = ( - struct.pack( - " bytearray: chunk_done = True content_length = None chunk_end = 0 - # pylint: disable=unsupported-assignment-operation buf = [] data_header_size = struct.calcsize(" bytearray: if not buf: buf = bytearray(content_length - start_offset) out_offset = current_offset - start_offset - buf[out_offset : out_offset + (read - data_header_size)] = b[ - data_header_size:read - ] + buf[out_offset : out_offset + (read - data_header_size)] = b[data_header_size:read] current_offset += read - data_header_size else: out_offset = current_offset - start_offset @@ -252,10 +236,7 @@ def write( if status != FileTransferService.OK: print("write error", status) raise RuntimeError() - if ( - cmd != FileTransferService.WRITE_PACING - or current_offset != written + offset - ): + if cmd != FileTransferService.WRITE_PACING or current_offset != written + offset: self._write( struct.pack( " int: if modification_time is None: modification_time = int(time.time() * 1_000_000_000) encoded = ( - struct.pack( - " int: def listdir(self, path: str) -> List[tuple]: """Returns a list of tuples, one tuple for each file or directory in the given path""" - # pylint: disable=too-many-locals paths = [] path = path.encode("utf-8") encoded = struct.pack("=4.0.0 +sphinx +sphinxcontrib-jquery +sphinx-rtd-theme diff --git a/examples/ble_file_transfer_listdirs.py b/examples/ble_file_transfer_listdirs.py index c65e8d7..80a2f91 100644 --- a/examples/ble_file_transfer_listdirs.py +++ b/examples/ble_file_transfer_listdirs.py @@ -9,18 +9,17 @@ from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ( - ProvideServicesAdvertisement, Advertisement, + ProvideServicesAdvertisement, ) + import adafruit_ble_file_transfer # Connect to a file transfer device ble = BLERadio() connection = None print("disconnected, scanning") -for advertisement in ble.start_scan( - ProvideServicesAdvertisement, Advertisement, timeout=1 -): +for advertisement in ble.start_scan(ProvideServicesAdvertisement, Advertisement, timeout=1): # print(advertisement.address, advertisement.address.type) if ( not hasattr(advertisement, "services") diff --git a/examples/ble_file_transfer_simpletest.py b/examples/ble_file_transfer_simpletest.py index b55c8ab..2217542 100644 --- a/examples/ble_file_transfer_simpletest.py +++ b/examples/ble_file_transfer_simpletest.py @@ -11,14 +11,14 @@ from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ( - ProvideServicesAdvertisement, Advertisement, + ProvideServicesAdvertisement, ) + import adafruit_ble_file_transfer def _write(client, filename, contents, *, offset=0): - # pylint: disable=redefined-outer-name start = time.monotonic() try: client.write(filename, contents, offset=offset) @@ -32,7 +32,6 @@ def _write(client, filename, contents, *, offset=0): def _read(client, filename, *, offset=0): - # pylint: disable=redefined-outer-name start = time.monotonic() try: contents = client.read(filename, offset=offset) @@ -73,7 +72,6 @@ def wait_for_reconnect(): try: while ble.connected: for connection in ble.connections: - # pylint: disable=redefined-outer-name if adafruit_ble_file_transfer.FileTransferService not in connection: continue if not connection.paired: @@ -85,7 +83,7 @@ def wait_for_reconnect(): client = adafruit_ble_file_transfer.FileTransferClient(service) print("Testing write") - client = _write(client, "/hello.txt", "Hello world".encode("utf-8")) + client = _write(client, "/hello.txt", b"Hello world") time.sleep(1) c = _read(client, "/hello.txt") print(len(c), c) @@ -101,9 +99,9 @@ def wait_for_reconnect(): print() print("Test writing within dir") - client = _write(client, "/world/hi.txt", "Hi world".encode("utf-8")) + client = _write(client, "/world/hi.txt", b"Hi world") - hello_world = "Hello world".encode("utf-8") + hello_world = b"Hello world" client = _write(client, "/world/hello.txt", hello_world) c = _read(client, "/world/hello.txt") print(c) @@ -111,13 +109,11 @@ def wait_for_reconnect(): # Test offsets print("Testing offsets") - hello = len("Hello ".encode("utf-8")) + hello = len(b"Hello ") c = _read(client, "/world/hello.txt", offset=hello) print(c) - client = _write( - client, "/world/hello.txt", "offsets!".encode("utf-8"), offset=hello - ) + client = _write(client, "/world/hello.txt", b"offsets!", offset=hello) c = _read(client, "/world/hello.txt", offset=0) print(c) print() @@ -174,18 +170,15 @@ def wait_for_reconnect(): raise RuntimeError("large contents don't match!") print() time.sleep(20) - except ConnectionError as e: + except ConnectionError: pass print("disconnected, scanning") - for advertisement in ble.start_scan( - ProvideServicesAdvertisement, Advertisement, timeout=1 - ): + for advertisement in ble.start_scan(ProvideServicesAdvertisement, Advertisement, timeout=1): # print(advertisement.address, advertisement.address.type) if ( not hasattr(advertisement, "services") - or adafruit_ble_file_transfer.FileTransferService - not in advertisement.services + or adafruit_ble_file_transfer.FileTransferService not in advertisement.services ): continue ble.connect(advertisement) diff --git a/examples/ble_file_transfer_stub_server.py b/examples/ble_file_transfer_stub_server.py index 4e75137..ac099c8 100644 --- a/examples/ble_file_transfer_stub_server.py +++ b/examples/ble_file_transfer_stub_server.py @@ -3,11 +3,11 @@ # SPDX-License-Identifier: Unlicense """This example broadcasts out the creation id based on the CircuitPython machine - string and provides a stub FileTransferService.""" +string and provides a stub FileTransferService.""" import binascii -import struct import os +import struct import time import adafruit_ble @@ -68,7 +68,7 @@ def write_packets(buf): sent = 0 while offset < len(buf): this_packet = full_packet[: len(buf) - sent] - for k in range(len(this_packet)): # pylint: disable=consider-using-enumerate + for k in range(len(this_packet)): this_packet[k] = buf[sent + k] sent += len(this_packet) service.raw.write(this_packet) @@ -80,9 +80,7 @@ def read_complete_path(starting_path, total_length): remaining_path = total_length - current_path_length complete_path[:current_path_length] = starting_path if remaining_path > 0: - read_packets( - memoryview(complete_path)[current_path_length:], target_size=remaining_path - ) + read_packets(memoryview(complete_path)[current_path_length:], target_size=remaining_path) return str(complete_path, "utf-8") @@ -152,12 +150,8 @@ def read_complete_path(starting_path, total_length): next_amount, ) write_packets(header) - read = read_packets( - packet_buffer, target_size=next_amount + write_data_header_size - ) - cmd, status, offset, data_size = struct.unpack_from( - "