From fa365b0149d943c53fbb62828b7a5a0b4cb27e49 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 16 May 2025 16:11:43 +0000 Subject: [PATCH 1/2] change to ruff --- .gitattributes | 11 + .pre-commit-config.yaml | 43 +- .pylintrc | 399 ------------------ README.rst | 6 +- adafruit_httpserver/__init__.py | 56 +-- adafruit_httpserver/authentication.py | 12 +- adafruit_httpserver/headers.py | 12 +- adafruit_httpserver/interfaces.py | 51 +-- adafruit_httpserver/methods.py | 1 - adafruit_httpserver/mime_types.py | 2 +- adafruit_httpserver/request.py | 44 +- adafruit_httpserver/response.py | 82 ++-- adafruit_httpserver/route.py | 6 +- adafruit_httpserver/server.py | 51 +-- adafruit_httpserver/status.py | 2 +- docs/api.rst | 3 + docs/conf.py | 8 +- .../httpserver_authentication_handlers.py | 5 +- examples/httpserver_authentication_server.py | 3 +- examples/httpserver_chunked.py | 3 +- examples/httpserver_cookies.py | 3 +- examples/httpserver_cpu_information.py | 3 +- examples/httpserver_cpython.py | 3 +- examples/httpserver_form_data.py | 3 +- examples/httpserver_handler_serves_file.py | 3 +- examples/httpserver_https.py | 3 +- examples/httpserver_mdns.py | 3 +- examples/httpserver_methods.py | 13 +- examples/httpserver_multiple_servers.py | 3 +- examples/httpserver_neopixel.py | 3 +- examples/httpserver_redirects.py | 11 +- ...rver_simpletest_auto_connection_manager.py | 3 +- ...ttpserver_simpletest_auto_settings_toml.py | 3 +- examples/httpserver_simpletest_manual_ap.py | 3 +- .../httpserver_simpletest_manual_ethernet.py | 5 +- examples/httpserver_simpletest_manual_wifi.py | 2 +- examples/httpserver_sse.py | 6 +- examples/httpserver_start_and_poll.py | 5 +- examples/httpserver_start_and_poll_asyncio.py | 9 +- examples/httpserver_static_files_serving.py | 3 +- examples/httpserver_templates.py | 2 +- examples/httpserver_url_parameters.py | 21 +- examples/httpserver_video_stream.py | 11 +- examples/httpserver_websocket.py | 9 +- ruff.toml | 112 +++++ 45 files changed, 324 insertions(+), 721 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 70ade69..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: v2.17.4 + - 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 f945e92..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=builtins.Exception diff --git a/README.rst b/README.rst index fe5b99e..5e884a5 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 HTTP Server for CircuitPython. diff --git a/adafruit_httpserver/__init__.py b/adafruit_httpserver/__init__.py index 5fd8099..6c8c7a2 100644 --- a/adafruit_httpserver/__init__.py +++ b/adafruit_httpserver/__init__.py @@ -25,70 +25,70 @@ from .authentication import ( Basic, - Token, Bearer, + Token, check_authentication, require_authentication, ) from .exceptions import ( - ServerStoppedError, AuthenticationError, + BackslashInPathError, + FileNotExistsError, InvalidPathError, ParentDirectoryReferenceError, - BackslashInPathError, + ServerStoppedError, ServingFilesDisabledError, - FileNotExistsError, ) from .headers import Headers from .methods import ( - GET, - POST, - PUT, + CONNECT, DELETE, - PATCH, + GET, HEAD, OPTIONS, + PATCH, + POST, + PUT, TRACE, - CONNECT, ) from .mime_types import MIMETypes -from .request import QueryParams, FormData, Request +from .request import FormData, QueryParams, Request from .response import ( - Response, - FileResponse, ChunkedResponse, + FileResponse, JSONResponse, Redirect, + Response, SSEResponse, Websocket, ) from .route import Route, as_route from .server import ( - Server, - NO_REQUEST, CONNECTION_TIMED_OUT, + NO_REQUEST, REQUEST_HANDLED_NO_RESPONSE, REQUEST_HANDLED_RESPONSE_SENT, + Server, ) from .status import ( - Status, - SWITCHING_PROTOCOLS_101, - OK_200, - CREATED_201, ACCEPTED_202, - NO_CONTENT_204, - PARTIAL_CONTENT_206, - MOVED_PERMANENTLY_301, - FOUND_302, - TEMPORARY_REDIRECT_307, - PERMANENT_REDIRECT_308, BAD_REQUEST_400, - UNAUTHORIZED_401, + CREATED_201, FORBIDDEN_403, - NOT_FOUND_404, - METHOD_NOT_ALLOWED_405, - TOO_MANY_REQUESTS_429, + FOUND_302, INTERNAL_SERVER_ERROR_500, + METHOD_NOT_ALLOWED_405, + MOVED_PERMANENTLY_301, + NO_CONTENT_204, + NOT_FOUND_404, NOT_IMPLEMENTED_501, + OK_200, + PARTIAL_CONTENT_206, + PERMANENT_REDIRECT_308, SERVICE_UNAVAILABLE_503, + SWITCHING_PROTOCOLS_101, + TEMPORARY_REDIRECT_307, + TOO_MANY_REQUESTS_429, + UNAUTHORIZED_401, + Status, ) diff --git a/adafruit_httpserver/authentication.py b/adafruit_httpserver/authentication.py index aa8f60d..73d72c4 100644 --- a/adafruit_httpserver/authentication.py +++ b/adafruit_httpserver/authentication.py @@ -8,7 +8,7 @@ """ try: - from typing import Union, List + from typing import List, Union except ImportError: pass @@ -40,15 +40,13 @@ def __str__(self) -> str: return f"{self.prefix} {self._value}" -class Bearer(Token): # pylint: disable=too-few-public-methods +class Bearer(Token): """Represents HTTP Bearer Token Authentication.""" prefix = "Bearer" -def check_authentication( - request: Request, auths: List[Union[Basic, Token, Bearer]] -) -> bool: +def check_authentication(request: Request, auths: List[Union[Basic, Token, Bearer]]) -> bool: """ Returns ``True`` if request is authorized by any of the authentications, ``False`` otherwise. @@ -65,9 +63,7 @@ def check_authentication( return any(auth_header == str(auth) for auth in auths) -def require_authentication( - request: Request, auths: List[Union[Basic, Token, Bearer]] -) -> None: +def require_authentication(request: Request, auths: List[Union[Basic, Token, Bearer]]) -> None: """ Checks if the request is authorized and raises ``AuthenticationError`` if not. diff --git a/adafruit_httpserver/headers.py b/adafruit_httpserver/headers.py index fca38d4..944c95b 100644 --- a/adafruit_httpserver/headers.py +++ b/adafruit_httpserver/headers.py @@ -93,9 +93,7 @@ def get_directive(self, name: str, default: str = None) -> Union[str, None]: return default return header_value.split(";")[0].strip('" ') - def get_parameter( - self, name: str, parameter: str, default: str = None - ) -> Union[str, None]: + def get_parameter(self, name: str, parameter: str, default: str = None) -> Union[str, None]: """ Returns the value of the given parameter for the given header name, or default if not found. @@ -124,16 +122,12 @@ def setdefault(self, name: str, default: str = None): def update(self, headers: Dict[str, str]): """Updates the headers with the given dict.""" - return self._storage.update( - {key.lower(): [value] for key, value in headers.items()} - ) + return self._storage.update({key.lower(): [value] for key, value in headers.items()}) def copy(self): """Returns a copy of the headers.""" return Headers( - "\r\n".join( - f"{key}: {value}" for key in self.fields for value in self.get_list(key) - ) + "\r\n".join(f"{key}: {value}" for key in self.fields for value in self.get_list(key)) ) def __getitem__(self, name: str): diff --git a/adafruit_httpserver/interfaces.py b/adafruit_httpserver/interfaces.py index 37b7b70..efee790 100644 --- a/adafruit_httpserver/interfaces.py +++ b/adafruit_httpserver/interfaces.py @@ -8,43 +8,34 @@ """ try: - from typing import List, Tuple, Dict, Union, Any + from typing import Any, Dict, List, Tuple, Union except ImportError: pass -class _ISocket: # pylint: disable=missing-function-docstring,no-self-use,unused-argument +class _ISocket: """A class for typing necessary methods for a socket object.""" - def accept(self) -> Tuple["_ISocket", Tuple[str, int]]: - ... + def accept(self) -> Tuple["_ISocket", Tuple[str, int]]: ... - def bind(self, address: Tuple[str, int]) -> None: - ... + def bind(self, address: Tuple[str, int]) -> None: ... - def setblocking(self, flag: bool) -> None: - ... + def setblocking(self, flag: bool) -> None: ... - def settimeout(self, value: "Union[float, None]") -> None: - ... + def settimeout(self, value: "Union[float, None]") -> None: ... - def setsockopt(self, level: int, optname: int, value: int) -> None: - ... + def setsockopt(self, level: int, optname: int, value: int) -> None: ... - def listen(self, backlog: int) -> None: - ... + def listen(self, backlog: int) -> None: ... - def send(self, data: bytes) -> int: - ... + def send(self, data: bytes) -> int: ... - def recv_into(self, buffer: memoryview, nbytes: int) -> int: - ... + def recv_into(self, buffer: memoryview, nbytes: int) -> int: ... - def close(self) -> None: - ... + def close(self) -> None: ... -class _ISocketPool: # pylint: disable=missing-function-docstring,no-self-use,unused-argument +class _ISocketPool: """A class to typing necessary methods and properties for a socket pool object.""" AF_INET: int @@ -52,15 +43,14 @@ class _ISocketPool: # pylint: disable=missing-function-docstring,no-self-use,un SOCK_STREAM: int SOL_SOCKET: int - def socket( # pylint: disable=redefined-builtin + def socket( self, family: int = ..., type: int = ..., proto: int = ..., - ) -> _ISocket: - ... + ) -> _ISocket: ... - def getaddrinfo( # pylint: disable=redefined-builtin,too-many-arguments + def getaddrinfo( self, host: str, port: int, @@ -68,8 +58,7 @@ def getaddrinfo( # pylint: disable=redefined-builtin,too-many-arguments type: int = ..., proto: int = ..., flags: int = ..., - ) -> Tuple[int, int, int, str, Tuple[str, int]]: - ... + ) -> Tuple[int, int, int, str, Tuple[str, int]]: ... class _IFieldStorage: @@ -140,9 +129,7 @@ def _encode_html_entities(value: Union[str, None]) -> Union[str, None]: class _IXSSSafeFieldStorage(_IFieldStorage): - def get( - self, field_name: str, default: Any = None, *, safe=True - ) -> Union[Any, None]: + def get(self, field_name: str, default: Any = None, *, safe=True) -> Union[Any, None]: if safe: return _encode_html_entities(super().get(field_name, default)) @@ -151,9 +138,7 @@ def get( def get_list(self, field_name: str, *, safe=True) -> List[Any]: if safe: - return [ - _encode_html_entities(value) for value in super().get_list(field_name) - ] + return [_encode_html_entities(value) for value in super().get_list(field_name)] _debug_warning_nonencoded_output() return super().get_list(field_name) diff --git a/adafruit_httpserver/methods.py b/adafruit_httpserver/methods.py index 1c6fd47..ad58063 100644 --- a/adafruit_httpserver/methods.py +++ b/adafruit_httpserver/methods.py @@ -7,7 +7,6 @@ * Author(s): Michał Pokusa """ - GET = "GET" POST = "POST" diff --git a/adafruit_httpserver/mime_types.py b/adafruit_httpserver/mime_types.py index 2e99293..4a684e6 100644 --- a/adafruit_httpserver/mime_types.py +++ b/adafruit_httpserver/mime_types.py @@ -8,7 +8,7 @@ """ try: - from typing import List, Dict + from typing import Dict, List except ImportError: pass diff --git a/adafruit_httpserver/request.py b/adafruit_httpserver/request.py index 69e7fc2..0997e2d 100644 --- a/adafruit_httpserver/request.py +++ b/adafruit_httpserver/request.py @@ -8,7 +8,7 @@ """ try: - from typing import List, Dict, Tuple, Union, Any, TYPE_CHECKING + from typing import TYPE_CHECKING, Any, Dict, List, Tuple, Union if TYPE_CHECKING: from .server import Server @@ -18,8 +18,8 @@ import json from .headers import Headers -from .interfaces import _ISocket, _IFieldStorage, _IXSSSafeFieldStorage -from .methods import POST, PUT, PATCH, DELETE +from .interfaces import _IFieldStorage, _ISocket, _IXSSSafeFieldStorage +from .methods import DELETE, PATCH, POST, PUT class QueryParams(_IXSSSafeFieldStorage): @@ -54,9 +54,7 @@ def __init__(self, query_string: str) -> None: def _add_field_value(self, field_name: str, value: str) -> None: super()._add_field_value(field_name, value) - def get( - self, field_name: str, default: str = None, *, safe=True - ) -> Union[str, None]: + def get(self, field_name: str, default: str = None, *, safe=True) -> Union[str, None]: return super().get(field_name, default, safe=safe) def get_list(self, field_name: str, *, safe=True) -> List[str]: @@ -92,9 +90,7 @@ class File: content: Union[str, bytes] """Content of the file.""" - def __init__( - self, filename: str, content_type: str, content: Union[str, bytes] - ) -> None: + def __init__(self, filename: str, content_type: str, content: Union[str, bytes]) -> None: self.filename = filename self.content_type = content_type self.content = content @@ -112,11 +108,7 @@ def content_bytes(self) -> bytes: with open(file.filename, "wb") as f: f.write(file.content_bytes) """ - return ( - self.content.encode("utf-8") - if isinstance(self.content, str) - else self.content - ) + return self.content.encode("utf-8") if isinstance(self.content, str) else self.content @property def size(self) -> int: @@ -177,11 +169,11 @@ class FormData(_IXSSSafeFieldStorage): @staticmethod def _check_is_supported_content_type(content_type: str) -> None: - return content_type in ( + return content_type in { "application/x-www-form-urlencoded", "multipart/form-data", "text/plain", - ) + } def __init__(self, data: bytes, headers: Headers, *, debug: bool = False) -> None: self._storage = {} @@ -231,9 +223,7 @@ def _parse_multipart_form_data(self, data: bytes, boundary: str) -> None: # TODO: Other text content types (e.g. application/json) should be decoded as well and if filename is not None: - self.files._add_field_value( # pylint: disable=protected-access - field_name, File(filename, content_type, value) - ) + self.files._add_field_value(field_name, File(filename, content_type, value)) else: self._add_field_value(field_name, value) @@ -258,12 +248,10 @@ def get_list(self, field_name: str, *, safe=True) -> List[Union[str, bytes]]: def __repr__(self) -> str: class_name = self.__class__.__name__ - return ( - f"<{class_name} {repr(self._storage)}, files={repr(self.files._storage)}>" - ) + return f"<{class_name} {repr(self._storage)}, files={repr(self.files._storage)}>" -class Request: # pylint: disable=too-many-instance-attributes +class Request: """ Incoming request, constructed from raw incoming bytes. It is passed as first argument to all route handlers. @@ -367,9 +355,7 @@ def _parse_cookies(cookie_header: str) -> None: return { name: value.strip('"') - for name, value in [ - cookie.strip().split("=", 1) for cookie in cookie_header.split(";") - ] + for name, value in [cookie.strip().split("=", 1) for cookie in cookie_header.split(";")] } @property @@ -443,7 +429,7 @@ def json(self) -> Union[dict, None]: """ return ( json.loads(self.body) - if (self.body and self.method in (POST, PUT, PATCH, DELETE)) + if (self.body and self.method in {POST, PUT, PATCH, DELETE}) else None ) @@ -467,9 +453,7 @@ def _parse_request_header( ) -> Tuple[str, str, QueryParams, str, Headers]: """Parse HTTP Start line to method, path, query_params and http_version.""" - start_line, headers_string = ( - header_bytes.decode("utf-8").strip().split("\r\n", 1) - ) + start_line, headers_string = header_bytes.decode("utf-8").strip().split("\r\n", 1) method, path, http_version = start_line.strip().split() diff --git a/adafruit_httpserver/response.py b/adafruit_httpserver/response.py index 9f19294..21aa217 100644 --- a/adafruit_httpserver/response.py +++ b/adafruit_httpserver/response.py @@ -8,14 +8,14 @@ """ try: - from typing import Optional, Dict, Union, Tuple, Generator, Any + from typing import Any, Dict, Generator, Optional, Tuple, Union except ImportError: pass -import os import json +import os from binascii import b2a_base64 -from errno import EAGAIN, ECONNRESET, ETIMEDOUT, ENOTCONN +from errno import EAGAIN, ECONNRESET, ENOTCONN, ETIMEDOUT try: try: @@ -33,22 +33,22 @@ FileNotExistsError, ParentDirectoryReferenceError, ) +from .headers import Headers +from .interfaces import _ISocket from .mime_types import MIMETypes from .request import Request from .status import ( - Status, - SWITCHING_PROTOCOLS_101, - OK_200, - MOVED_PERMANENTLY_301, FOUND_302, - TEMPORARY_REDIRECT_307, + MOVED_PERMANENTLY_301, + OK_200, PERMANENT_REDIRECT_308, + SWITCHING_PROTOCOLS_101, + TEMPORARY_REDIRECT_307, + Status, ) -from .headers import Headers -from .interfaces import _ISocket -class Response: # pylint: disable=too-few-public-methods +class Response: """ Response to a given `Request`. Use in `Server.route` handler functions. @@ -62,7 +62,7 @@ def route_func(request: Request): return Response(request, body='Some content', content_type="text/plain") """ - def __init__( # pylint: disable=too-many-arguments + def __init__( self, request: Request, body: Union[str, bytes] = "", @@ -84,9 +84,7 @@ def __init__( # pylint: disable=too-many-arguments self._request = request self._body = body self._status = status if isinstance(status, Status) else Status(*status) - self._headers = ( - headers.copy() if isinstance(headers, Headers) else Headers(headers) - ) + self._headers = headers.copy() if isinstance(headers, Headers) else Headers(headers) self._cookies = cookies.copy() if cookies else {} self._content_type = content_type self._size = 0 @@ -98,13 +96,9 @@ def _send_headers( ) -> None: headers = self._headers.copy() - response_message_header = ( - f"HTTP/1.1 {self._status.code} {self._status.text}\r\n" - ) + response_message_header = f"HTTP/1.1 {self._status.code} {self._status.text}\r\n" - headers.setdefault( - "Content-Type", content_type or self._content_type or MIMETypes.DEFAULT - ) + headers.setdefault("Content-Type", content_type or self._content_type or MIMETypes.DEFAULT) headers.setdefault("Content-Length", content_length) headers.setdefault("Connection", "close") @@ -116,14 +110,10 @@ def _send_headers( response_message_header += f"{header}: {value}\r\n" response_message_header += "\r\n" - self._send_bytes( - self._request.connection, response_message_header.encode("utf-8") - ) + self._send_bytes(self._request.connection, response_message_header.encode("utf-8")) def _send(self) -> None: - encoded_body = ( - self._body.encode("utf-8") if isinstance(self._body, str) else self._body - ) + encoded_body = self._body.encode("utf-8") if isinstance(self._body, str) else self._body self._send_headers(len(encoded_body), self._content_type) self._send_bytes(self._request.connection, encoded_body) @@ -155,7 +145,7 @@ def _close_connection(self) -> None: pass -class FileResponse(Response): # pylint: disable=too-few-public-methods +class FileResponse(Response): """ Specialized version of `Response` class for sending files. @@ -173,7 +163,7 @@ def route_func(request: Request): return FileResponse(request, filename='index.html', root_path='/www') """ - def __init__( # pylint: disable=too-many-arguments + def __init__( self, request: Request, filename: str = "index.html", @@ -243,7 +233,7 @@ def _verify_file_path_is_valid(file_path: str): """ # Check for backslashes - if "\\" in file_path: # pylint: disable=anomalous-backslash-in-string + if "\\" in file_path: raise BackslashInPathError(file_path) # Check each component of the path for parent directory references @@ -276,7 +266,7 @@ def _get_file_length(file_path: str) -> int: assert (st_mode & 0o170000) == 0o100000 # Check if it is a regular file return st_size except (OSError, AssertionError): - raise FileNotExistsError(file_path) # pylint: disable=raise-missing-from + raise FileNotExistsError(file_path) def _send(self) -> None: self._send_headers(self._file_length, self._content_type) @@ -288,7 +278,7 @@ def _send(self) -> None: self._close_connection() -class ChunkedResponse(Response): # pylint: disable=too-few-public-methods +class ChunkedResponse(Response): """ Specialized version of `Response` class for sending data using chunked transfer encoding. @@ -308,7 +298,7 @@ def body(): return ChunkedResponse(request, body, content_type="text/plain") """ - def __init__( # pylint: disable=too-many-arguments + def __init__( self, request: Request, body: Generator[Union[str, bytes], Any, Any], @@ -356,7 +346,7 @@ def _send(self) -> None: self._close_connection() -class JSONResponse(Response): # pylint: disable=too-few-public-methods +class JSONResponse(Response): """ Specialized version of `Response` class for sending JSON data. @@ -403,7 +393,7 @@ def _send(self) -> None: self._close_connection() -class Redirect(Response): # pylint: disable=too-few-public-methods +class Redirect(Response): """ Specialized version of `Response` class for redirecting to another URL. @@ -448,9 +438,7 @@ def __init__( """ if status is not None and (permanent or preserve_method): - raise ValueError( - "Cannot specify both status and permanent/preserve_method argument" - ) + raise ValueError("Cannot specify both status and permanent/preserve_method argument") if status is None: if preserve_method: @@ -466,7 +454,7 @@ def _send(self) -> None: self._close_connection() -class SSEResponse(Response): # pylint: disable=too-few-public-methods +class SSEResponse(Response): """ Specialized version of `Response` class for sending Server-Sent Events. @@ -500,7 +488,7 @@ def route_func(request: Request): sse.close() """ - def __init__( # pylint: disable=too-many-arguments + def __init__( self, request: Request, headers: Union[Headers, Dict[str, str]] = None, @@ -523,11 +511,11 @@ def __init__( # pylint: disable=too-many-arguments def _send(self) -> None: self._send_headers() - def send_event( # pylint: disable=too-many-arguments + def send_event( self, data: str, event: str = None, - id: int = None, # pylint: disable=redefined-builtin,invalid-name + id: int = None, retry: int = None, custom_fields: Dict[str, str] = None, ) -> None: @@ -564,7 +552,7 @@ def close(self): self._close_connection() -class Websocket(Response): # pylint: disable=too-few-public-methods +class Websocket(Response): """ Specialized version of `Response` class for creating a websocket connection. @@ -635,7 +623,7 @@ def _process_sec_websocket_key(request: Request) -> str: return b2a_base64(response_key.digest()).strip().decode() - def __init__( # pylint: disable=too-many-arguments + def __init__( self, request: Request, headers: Union[Headers, Dict[str, str]] = None, @@ -693,7 +681,7 @@ def _read_frame(self): if fin != Websocket.FIN and opcode == Websocket.CONT: return Websocket.CONT, None - payload = bytes() + payload = b"" if fin == Websocket.FIN and opcode == Websocket.CLOSE: return Websocket.CLOSE, payload @@ -746,9 +734,7 @@ def receive(self, fail_silently: bool = False) -> Union[str, bytes, None]: if self.closed: if fail_silently: return None - raise RuntimeError( - "Websocket connection is closed, cannot receive messages" - ) + raise RuntimeError("Websocket connection is closed, cannot receive messages") try: opcode, payload = self._read_frame() diff --git a/adafruit_httpserver/route.py b/adafruit_httpserver/route.py index 0659555..2b66dd6 100644 --- a/adafruit_httpserver/route.py +++ b/adafruit_httpserver/route.py @@ -8,7 +8,7 @@ """ try: - from typing import Callable, Iterable, Union, Tuple, Literal, Dict, TYPE_CHECKING + from typing import TYPE_CHECKING, Callable, Dict, Iterable, Literal, Tuple, Union if TYPE_CHECKING: from .response import Response @@ -52,9 +52,7 @@ def __init__( self._validate_path(path, append_slash) self.path = path - self.methods = ( - set(methods) if isinstance(methods, (set, list, tuple)) else set([methods]) - ) + self.methods = set(methods) if isinstance(methods, (set, list, tuple)) else set([methods]) self.handler = handler self.parameters_names = [ name[1:-1] for name in re.compile(r"/[^<>]*/?").split(path) if name != "" diff --git a/adafruit_httpserver/server.py b/adafruit_httpserver/server.py index 8acebc3..992eae5 100644 --- a/adafruit_httpserver/server.py +++ b/adafruit_httpserver/server.py @@ -8,34 +8,34 @@ """ try: - from typing import Callable, Union, List, Tuple, Dict, Iterable + from typing import Callable, Dict, Iterable, List, Tuple, Union except ImportError: pass -from ssl import SSLContext, create_default_context from errno import EAGAIN, ECONNRESET, ETIMEDOUT +from ssl import SSLContext, create_default_context from sys import implementation from time import monotonic, sleep from traceback import print_exception -from .authentication import Basic, Token, Bearer, require_authentication +from .authentication import Basic, Bearer, Token, require_authentication from .exceptions import ( - ServerStoppedError, AuthenticationError, FileNotExistsError, InvalidPathError, + ServerStoppedError, ServingFilesDisabledError, ) from .headers import Headers -from .interfaces import _ISocketPool, _ISocket +from .interfaces import _ISocket, _ISocketPool from .methods import GET, HEAD from .request import Request -from .response import Response, FileResponse +from .response import FileResponse, Response from .route import Route -from .status import BAD_REQUEST_400, UNAUTHORIZED_401, FORBIDDEN_403, NOT_FOUND_404 +from .status import BAD_REQUEST_400, FORBIDDEN_403, NOT_FOUND_404, UNAUTHORIZED_401 if implementation.name != "circuitpython": - from ssl import Purpose, CERT_NONE, SSLError # pylint: disable=ungrouped-imports + from ssl import CERT_NONE, Purpose, SSLError NO_REQUEST = "no_request" @@ -47,7 +47,7 @@ MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE = -30592 -class Server: # pylint: disable=too-many-instance-attributes +class Server: """A basic socket-based HTTP server.""" host: str @@ -134,7 +134,7 @@ def __init__( else: self._ssl_context = None - if root_path in ["", "/"] and debug: + if root_path in {"", "/"} and debug: _debug_warning_exposed_files(root_path) self.stopped = True @@ -254,7 +254,7 @@ def serve_forever( except KeyboardInterrupt: # Exit on Ctrl-C e.g. during development self.stop() return - except Exception: # pylint: disable=broad-except + except Exception: pass # Ignore exceptions in handler function @staticmethod @@ -292,9 +292,7 @@ def start(self, host: str = "0.0.0.0", port: int = 5000) -> None: self.host, self.port = host, port self.stopped = False - self._sock = self._create_server_socket( - self._socket_source, self._ssl_context, host, port - ) + self._sock = self._create_server_socket(self._socket_source, self._ssl_context, host, port) if self.debug: _debug_started_server(self) @@ -315,7 +313,7 @@ def stop(self) -> None: def _receive_header_bytes(self, sock: _ISocket) -> bytes: """Receive bytes until a empty line is received.""" - received_bytes = bytes() + received_bytes = b"" while b"\r\n\r\n" not in received_bytes: try: length = sock.recv_into(self._buffer, len(self._buffer)) @@ -367,15 +365,11 @@ def _receive_request( received_body_bytes = request.body # Receiving remaining body bytes - request.body = self._receive_body_bytes( - sock, received_body_bytes, content_length - ) + request.body = self._receive_body_bytes(sock, received_body_bytes, content_length) return request - def _find_handler( # pylint: disable=cell-var-from-loop - self, method: str, path: str - ) -> Union[Callable[..., "Response"], None]: + def _find_handler(self, method: str, path: str) -> Union[Callable[..., "Response"], None]: """ Finds a handler for a given route. @@ -419,7 +413,7 @@ def _handle_request( raise ServingFilesDisabledError # Method is GET or HEAD, try to serve a file from the filesystem. - if request.method in (GET, HEAD): + if request.method in {GET, HEAD}: return FileResponse( request, filename=request.path, @@ -451,11 +445,9 @@ def _handle_request( def _set_default_server_headers(self, response: Response) -> None: for name, value in self.headers.items(): - response._headers.setdefault( # pylint: disable=protected-access - name, value - ) + response._headers.setdefault(name, value) - def poll( # pylint: disable=too-many-branches,too-many-return-statements + def poll( self, ) -> str: """ @@ -494,7 +486,7 @@ def poll( # pylint: disable=too-many-branches,too-many-return-statements self._set_default_server_headers(response) # Send the response - response._send() # pylint: disable=protected-access + response._send() if self.debug: _debug_end_time = monotonic() @@ -502,7 +494,7 @@ def poll( # pylint: disable=too-many-branches,too-many-return-statements return REQUEST_HANDLED_RESPONSE_SENT - except Exception as error: # pylint: disable=broad-except + except Exception as error: if isinstance(error, OSError): # There is no data available right now, try again later. if error.errno == EAGAIN: @@ -635,7 +627,6 @@ def _debug_started_server(server: "Server"): def _debug_response_sent(response: "Response", time_elapsed: float): """Prints a message after a response is sent.""" - # pylint: disable=protected-access client_ip = response._request.client_address[0] method = response._request.method query_params = response._request.query_params @@ -650,7 +641,7 @@ def _debug_response_sent(response: "Response", time_elapsed: float): ) -def _debug_stopped_server(server: "Server"): # pylint: disable=unused-argument +def _debug_stopped_server(server: "Server"): """Prints a message after the server stops.""" print("Stopped development server") diff --git a/adafruit_httpserver/status.py b/adafruit_httpserver/status.py index a27f15d..8f40f07 100644 --- a/adafruit_httpserver/status.py +++ b/adafruit_httpserver/status.py @@ -8,7 +8,7 @@ """ -class Status: # pylint: disable=too-few-public-methods +class Status: """HTTP status code.""" def __init__(self, code: int, text: str): diff --git a/docs/api.rst b/docs/api.rst index 8aeda4e..8c344ef 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,6 +4,9 @@ .. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) .. use this format as the module name: "adafruit_foo.foo" +API Reference +############# + .. automodule:: adafruit_httpserver :members: diff --git a/docs/conf.py b/docs/conf.py index 26b7cf1..479ad59 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,12 +1,10 @@ -# -*- coding: utf-8 -*- - # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries # # SPDX-License-Identifier: MIT +import datetime import os import sys -import datetime sys.path.insert(0, os.path.abspath("..")) @@ -54,9 +52,7 @@ creation_year = "2022" 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" author = "Dan Halbert" diff --git a/examples/httpserver_authentication_handlers.py b/examples/httpserver_authentication_handlers.py index 988c241..3cddc91 100644 --- a/examples/httpserver_authentication_handlers.py +++ b/examples/httpserver_authentication_handlers.py @@ -5,17 +5,16 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response, UNAUTHORIZED_401 +from adafruit_httpserver import UNAUTHORIZED_401, Request, Response, Server from adafruit_httpserver.authentication import ( AuthenticationError, Basic, - Token, Bearer, + Token, check_authentication, require_authentication, ) - pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) diff --git a/examples/httpserver_authentication_server.py b/examples/httpserver_authentication_server.py index 8dc5936..9492073 100644 --- a/examples/httpserver_authentication_server.py +++ b/examples/httpserver_authentication_server.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response, Basic, Token, Bearer - +from adafruit_httpserver import Basic, Bearer, Request, Response, Server, Token # Create a list of available authentication methods. auths = [ diff --git a/examples/httpserver_chunked.py b/examples/httpserver_chunked.py index 57c91e6..298e795 100644 --- a/examples/httpserver_chunked.py +++ b/examples/httpserver_chunked.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, ChunkedResponse - +from adafruit_httpserver import ChunkedResponse, Request, Server pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) diff --git a/examples/httpserver_cookies.py b/examples/httpserver_cookies.py index 1f1e91c..d5bcfd0 100644 --- a/examples/httpserver_cookies.py +++ b/examples/httpserver_cookies.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response, GET, Headers - +from adafruit_httpserver import GET, Headers, Request, Response, Server pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) diff --git a/examples/httpserver_cpu_information.py b/examples/httpserver_cpu_information.py index 22abe74..c296bbb 100644 --- a/examples/httpserver_cpu_information.py +++ b/examples/httpserver_cpu_information.py @@ -6,8 +6,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, JSONResponse - +from adafruit_httpserver import JSONResponse, Request, Server pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) diff --git a/examples/httpserver_cpython.py b/examples/httpserver_cpython.py index 292b931..854812c 100644 --- a/examples/httpserver_cpython.py +++ b/examples/httpserver_cpython.py @@ -4,8 +4,7 @@ import socket -from adafruit_httpserver import Server, Request, Response - +from adafruit_httpserver import Request, Response, Server pool = socket server = Server(pool, "/static", debug=True) diff --git a/examples/httpserver_form_data.py b/examples/httpserver_form_data.py index 12090eb..9ed4d90 100644 --- a/examples/httpserver_form_data.py +++ b/examples/httpserver_form_data.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response, GET, POST - +from adafruit_httpserver import GET, POST, Request, Response, Server pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) diff --git a/examples/httpserver_handler_serves_file.py b/examples/httpserver_handler_serves_file.py index c50c767..bc0c930 100644 --- a/examples/httpserver_handler_serves_file.py +++ b/examples/httpserver_handler_serves_file.py @@ -6,8 +6,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, FileResponse - +from adafruit_httpserver import FileResponse, Request, Server pool = socketpool.SocketPool(wifi.radio) server = Server(pool, "/default-static-folder", debug=True) diff --git a/examples/httpserver_https.py b/examples/httpserver_https.py index c006676..d3641f1 100644 --- a/examples/httpserver_https.py +++ b/examples/httpserver_https.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response - +from adafruit_httpserver import Request, Response, Server pool = socketpool.SocketPool(wifi.radio) server = Server( diff --git a/examples/httpserver_mdns.py b/examples/httpserver_mdns.py index 5ad25cb..b62b65e 100644 --- a/examples/httpserver_mdns.py +++ b/examples/httpserver_mdns.py @@ -6,8 +6,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, FileResponse - +from adafruit_httpserver import FileResponse, Request, Server mdns_server = mdns.Server(wifi.radio) mdns_server.hostname = "custom-mdns-hostname" diff --git a/examples/httpserver_methods.py b/examples/httpserver_methods.py index d579536..67a5d40 100644 --- a/examples/httpserver_methods.py +++ b/examples/httpserver_methods.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, JSONResponse, GET, POST, PUT, DELETE - +from adafruit_httpserver import DELETE, GET, POST, PUT, JSONResponse, Request, Server pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) @@ -27,7 +26,7 @@ def api(request: Request): return JSONResponse(request, objects) # Upload or update objects - if request.method in [POST, PUT]: + if request.method in {POST, PUT}: uploaded_object = request.json() # Find object with same ID @@ -41,9 +40,7 @@ def api(request: Request): # If not found, add it objects.append(uploaded_object) - return JSONResponse( - request, {"message": "Object added", "object": uploaded_object} - ) + return JSONResponse(request, {"message": "Object added", "object": uploaded_object}) # Delete objects if request.method == DELETE: @@ -59,9 +56,7 @@ def api(request: Request): ) # If not found, return error - return JSONResponse( - request, {"message": "Object not found", "object": deleted_object} - ) + return JSONResponse(request, {"message": "Object not found", "object": deleted_object}) # If we get here, something went wrong return JSONResponse(request, {"message": "Something went wrong"}) diff --git a/examples/httpserver_multiple_servers.py b/examples/httpserver_multiple_servers.py index b00409f..a793954 100644 --- a/examples/httpserver_multiple_servers.py +++ b/examples/httpserver_multiple_servers.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response - +from adafruit_httpserver import Request, Response, Server pool = socketpool.SocketPool(wifi.radio) diff --git a/examples/httpserver_neopixel.py b/examples/httpserver_neopixel.py index ba60fd2..5c6cf58 100644 --- a/examples/httpserver_neopixel.py +++ b/examples/httpserver_neopixel.py @@ -7,8 +7,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Route, as_route, Request, Response, GET, POST - +from adafruit_httpserver import GET, POST, Request, Response, Route, Server, as_route pool = socketpool.SocketPool(wifi.radio) server = Server(pool, "/static", debug=True) diff --git a/examples/httpserver_redirects.py b/examples/httpserver_redirects.py index 1fb7e9e..1e9ec76 100644 --- a/examples/httpserver_redirects.py +++ b/examples/httpserver_redirects.py @@ -6,16 +6,15 @@ import wifi from adafruit_httpserver import ( - Server, + MOVED_PERMANENTLY_301, + NOT_FOUND_404, + POST, + Redirect, Request, Response, - Redirect, - POST, - NOT_FOUND_404, - MOVED_PERMANENTLY_301, + Server, ) - pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) diff --git a/examples/httpserver_simpletest_auto_connection_manager.py b/examples/httpserver_simpletest_auto_connection_manager.py index 49d0473..81b1900 100644 --- a/examples/httpserver_simpletest_auto_connection_manager.py +++ b/examples/httpserver_simpletest_auto_connection_manager.py @@ -3,10 +3,9 @@ # SPDX-License-Identifier: MIT import wifi - from adafruit_connection_manager import get_radio_socketpool -from adafruit_httpserver import Server, Request, Response +from adafruit_httpserver import Request, Response, Server pool = get_radio_socketpool(wifi.radio) server = Server(pool, "/static", debug=True) diff --git a/examples/httpserver_simpletest_auto_settings_toml.py b/examples/httpserver_simpletest_auto_settings_toml.py index a1f8192..946ee80 100644 --- a/examples/httpserver_simpletest_auto_settings_toml.py +++ b/examples/httpserver_simpletest_auto_settings_toml.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response - +from adafruit_httpserver import Request, Response, Server pool = socketpool.SocketPool(wifi.radio) server = Server(pool, "/static", debug=True) diff --git a/examples/httpserver_simpletest_manual_ap.py b/examples/httpserver_simpletest_manual_ap.py index 767196e..8a8b638 100644 --- a/examples/httpserver_simpletest_manual_ap.py +++ b/examples/httpserver_simpletest_manual_ap.py @@ -5,8 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response - +from adafruit_httpserver import Request, Response, Server AP_SSID = "..." AP_PASSWORD = "..." diff --git a/examples/httpserver_simpletest_manual_ethernet.py b/examples/httpserver_simpletest_manual_ethernet.py index fafee51..5d668b8 100644 --- a/examples/httpserver_simpletest_manual_ethernet.py +++ b/examples/httpserver_simpletest_manual_ethernet.py @@ -4,11 +4,10 @@ import board import digitalio - -from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K from adafruit_wiznet5k import adafruit_wiznet5k_socket as socket -from adafruit_httpserver import Server, Request, Response +from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K +from adafruit_httpserver import Request, Response, Server # For Adafruit Ethernet FeatherWing cs = digitalio.DigitalInOut(board.D10) diff --git a/examples/httpserver_simpletest_manual_wifi.py b/examples/httpserver_simpletest_manual_wifi.py index a9fee46..cbf2605 100644 --- a/examples/httpserver_simpletest_manual_wifi.py +++ b/examples/httpserver_simpletest_manual_wifi.py @@ -5,7 +5,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response +from adafruit_httpserver import Request, Response, Server WIFI_SSID = "..." WIFI_PASSWORD = "..." diff --git a/examples/httpserver_sse.py b/examples/httpserver_sse.py index 51b93a8..9cfafa2 100644 --- a/examples/httpserver_sse.py +++ b/examples/httpserver_sse.py @@ -3,12 +3,12 @@ # SPDX-License-Identifier: Unlicense from time import monotonic + import microcontroller import socketpool import wifi -from adafruit_httpserver import Server, Request, Response, SSEResponse, GET - +from adafruit_httpserver import GET, Request, Response, Server, SSEResponse pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) @@ -43,7 +43,7 @@ def client(request: Request): @server.route("/connect-client", GET) def connect_client(request: Request): - global sse_response # pylint: disable=global-statement + global sse_response if sse_response is not None: sse_response.close() # Close any existing connection diff --git a/examples/httpserver_start_and_poll.py b/examples/httpserver_start_and_poll.py index 1d41284..787f0be 100644 --- a/examples/httpserver_start_and_poll.py +++ b/examples/httpserver_start_and_poll.py @@ -6,13 +6,12 @@ import wifi from adafruit_httpserver import ( - Server, REQUEST_HANDLED_RESPONSE_SENT, - Request, FileResponse, + Request, + Server, ) - pool = socketpool.SocketPool(wifi.radio) server = Server(pool, "/static", debug=True) diff --git a/examples/httpserver_start_and_poll_asyncio.py b/examples/httpserver_start_and_poll_asyncio.py index 3fea850..d88ebe3 100644 --- a/examples/httpserver_start_and_poll_asyncio.py +++ b/examples/httpserver_start_and_poll_asyncio.py @@ -2,18 +2,19 @@ # # SPDX-License-Identifier: Unlicense -from asyncio import create_task, gather, run, sleep as async_sleep +from asyncio import create_task, gather, run +from asyncio import sleep as async_sleep + import socketpool import wifi from adafruit_httpserver import ( - Server, REQUEST_HANDLED_RESPONSE_SENT, - Request, FileResponse, + Request, + Server, ) - pool = socketpool.SocketPool(wifi.radio) server = Server(pool, "/static", debug=True) diff --git a/examples/httpserver_static_files_serving.py b/examples/httpserver_static_files_serving.py index 0026ce8..ca00340 100644 --- a/examples/httpserver_static_files_serving.py +++ b/examples/httpserver_static_files_serving.py @@ -6,8 +6,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, MIMETypes - +from adafruit_httpserver import MIMETypes, Server MIMETypes.configure( default_to="text/plain", diff --git a/examples/httpserver_templates.py b/examples/httpserver_templates.py index 54f7a6b..043242c 100644 --- a/examples/httpserver_templates.py +++ b/examples/httpserver_templates.py @@ -7,7 +7,7 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response, FileResponse +from adafruit_httpserver import FileResponse, Request, Response, Server try: from adafruit_templateengine import render_template diff --git a/examples/httpserver_url_parameters.py b/examples/httpserver_url_parameters.py index d1a2714..2831f82 100644 --- a/examples/httpserver_url_parameters.py +++ b/examples/httpserver_url_parameters.py @@ -5,22 +5,21 @@ import socketpool import wifi -from adafruit_httpserver import Server, Request, Response - +from adafruit_httpserver import Request, Response, Server pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) class Device: - def turn_on(self): # pylint: disable=no-self-use + def turn_on(self): print("Turning on device.") - def turn_off(self): # pylint: disable=no-self-use + def turn_off(self): print("Turning off device.") -def get_device(device_id: str) -> Device: # pylint: disable=unused-argument +def get_device(device_id: str) -> Device: """ This is a **made up** function that returns a `Device` object. """ @@ -29,25 +28,21 @@ def get_device(device_id: str) -> Device: # pylint: disable=unused-argument @server.route("/device//action/") @server.route("/device/emergency-power-off/") -def perform_action( - request: Request, device_id: str, action: str = "emergency_power_off" -): +def perform_action(request: Request, device_id: str, action: str = "emergency_power_off"): """ Performs an "action" on a specified device. """ device = get_device(device_id) - if action in ["turn_on"]: + if action in {"turn_on"}: device.turn_on() - elif action in ["turn_off", "emergency_power_off"]: + elif action in {"turn_off", "emergency_power_off"}: device.turn_off() else: return Response(request, f"Unknown action ({action})") - return Response( - request, f"Action ({action}) performed on device with ID: {device_id}" - ) + return Response(request, f"Action ({action}) performed on device with ID: {device_id}") @server.route("/device//status/") diff --git a/examples/httpserver_video_stream.py b/examples/httpserver_video_stream.py index 44301af..644ef39 100644 --- a/examples/httpserver_video_stream.py +++ b/examples/httpserver_video_stream.py @@ -12,10 +12,9 @@ import socketpool import wifi - from adafruit_pycamera import PyCamera -from adafruit_httpserver import Server, Request, Response, Headers, Status, OK_200 +from adafruit_httpserver import OK_200, Headers, Request, Response, Server, Status pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) @@ -56,13 +55,9 @@ def _get_random_boundary() -> str: return "--" + "".join([choice(symbols) for _ in range(16)]) def send_frame(self, frame: Union[str, bytes] = "") -> None: - encoded_frame = bytes( - frame.encode("utf-8") if isinstance(frame, str) else frame - ) + encoded_frame = bytes(frame.encode("utf-8") if isinstance(frame, str) else frame) - self._send_bytes( - self._request.connection, bytes(f"{self._boundary}\r\n", "utf-8") - ) + self._send_bytes(self._request.connection, bytes(f"{self._boundary}\r\n", "utf-8")) self._send_bytes( self._request.connection, bytes(f"Content-Type: {self._frame_content_type}\r\n\r\n", "utf-8"), diff --git a/examples/httpserver_websocket.py b/examples/httpserver_websocket.py index ac8e86f..e693bc1 100644 --- a/examples/httpserver_websocket.py +++ b/examples/httpserver_websocket.py @@ -2,15 +2,16 @@ # # SPDX-License-Identifier: Unlicense -from asyncio import create_task, gather, run, sleep as async_sleep +from asyncio import create_task, gather, run +from asyncio import sleep as async_sleep + import board import microcontroller import neopixel import socketpool import wifi -from adafruit_httpserver import Server, Request, Response, Websocket, GET - +from adafruit_httpserver import GET, Request, Response, Server, Websocket pool = socketpool.SocketPool(wifi.radio) server = Server(pool, debug=True) @@ -62,7 +63,7 @@ def client(request: Request): @server.route("/connect-websocket", GET) def connect_client(request: Request): - global websocket # pylint: disable=global-statement + global websocket if websocket is not None: websocket.close() # Close any existing connection diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..4e5df57 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,112 @@ +# 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 + "PLC2701", # private import + "PLR0911", # too many return + "PLW1641", # object not implement hash + "PLW0603", # global statement + "PLC1901", # string falsey simplified +] + +[format] +line-ending = "lf" From cd39addea8f7b1a8c8a4684aca2bc9112284b81d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sat, 17 May 2025 10:30:53 -0500 Subject: [PATCH 2/2] fix docs example highlights --- docs/examples.rst | 40 +++++++++++++++++++-------------------- docs/starting_methods.rst | 8 ++++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/examples.rst b/docs/examples.rst index 229a15d..aa2a6d3 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -39,7 +39,7 @@ In order to save memory, we are unregistering unused MIME types and registering .. literalinclude:: ../examples/httpserver_static_files_serving.py :caption: examples/httpserver_static_files_serving.py - :emphasize-lines: 12-18,23-26 + :emphasize-lines: 11-17,22-25 :linenos: You can also serve a specific file from the handler. @@ -51,7 +51,7 @@ By doing that, you can serve files from multiple directories, and decide exactly .. literalinclude:: ../examples/httpserver_handler_serves_file.py :caption: examples/httpserver_handler_serves_file.py - :emphasize-lines: 13,22 + :emphasize-lines: 12,21 :linenos: .. literalinclude:: ../examples/home.html @@ -74,7 +74,7 @@ a running total of the last 10 samples. .. literalinclude:: ../examples/httpserver_start_and_poll.py :caption: examples/httpserver_start_and_poll.py - :emphasize-lines: 29,38 + :emphasize-lines: 28,37 :linenos: @@ -86,7 +86,7 @@ without needing to manually manage the timing of each task. .. literalinclude:: ../examples/httpserver_start_and_poll_asyncio.py :caption: examples/httpserver_start_and_poll_asyncio.py - :emphasize-lines: 5,33,42,45,50,55-62 + :emphasize-lines: 5,6,34,43,46,51,56-63 :linenos: Server with MDNS @@ -101,7 +101,7 @@ On some routers it is also possible to use ``http://custom-mdns-hostname:5000/`` .. literalinclude:: ../examples/httpserver_mdns.py :caption: examples/httpserver_mdns.py - :emphasize-lines: 12-14 + :emphasize-lines: 11-13 :linenos: Get CPU information @@ -115,7 +115,7 @@ More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS .. literalinclude:: ../examples/httpserver_cpu_information.py :caption: examples/httpserver_cpu_information.py - :emphasize-lines: 9,15-18,33 + :emphasize-lines: 9,14-17,32 :linenos: Handling different methods @@ -134,7 +134,7 @@ In example below, handler for ``/api`` and ``/api/`` route will be called when a .. literalinclude:: ../examples/httpserver_methods.py :caption: examples/httpserver_methods.py - :emphasize-lines: 8,19,26,30,49 + :emphasize-lines: 8,18,25,29,46 :linenos: Change NeoPixel color @@ -156,7 +156,7 @@ Tested on ESP32-S2 Feather. .. literalinclude:: ../examples/httpserver_neopixel.py :caption: examples/httpserver_neopixel.py - :emphasize-lines: 26-28,41,52,68,74 + :emphasize-lines: 25-27,40,51,67,73 :linenos: Templates @@ -209,7 +209,7 @@ return only the first one. .. literalinclude:: ../examples/httpserver_form_data.py :caption: examples/httpserver_form_data.py - :emphasize-lines: 32,47,50 + :emphasize-lines: 31,46,49 :linenos: Cookies @@ -223,7 +223,7 @@ In order to set cookies, pass ``cookies`` dictionary to ``Response`` constructo .. literalinclude:: ../examples/httpserver_cookies.py :caption: examples/httpserver_cookies.py - :emphasize-lines: 70,74-75,82 + :emphasize-lines: 69,73-74,81 :linenos: Chunked response @@ -235,7 +235,7 @@ constructor. .. literalinclude:: ../examples/httpserver_chunked.py :caption: examples/httpserver_chunked.py - :emphasize-lines: 8,21-26,28 + :emphasize-lines: 8,20-25,27 :linenos: URL parameters and wildcards @@ -271,7 +271,7 @@ In both cases, wildcards will not match empty path segment, so ``/api/.../users` .. literalinclude:: ../examples/httpserver_url_parameters.py :caption: examples/httpserver_url_parameters.py - :emphasize-lines: 30-34,53-54,65-66 + :emphasize-lines: 29-31,48-49,60-61 :linenos: Authentication @@ -284,7 +284,7 @@ If you want to apply authentication to the whole server, you need to call ``.req .. literalinclude:: ../examples/httpserver_authentication_server.py :caption: examples/httpserver_authentication_server.py - :emphasize-lines: 8,11-16,20 + :emphasize-lines: 8,10-15,19 :linenos: On the other hand, if you want to apply authentication to a set of routes, you need to call ``require_authentication`` function. @@ -292,7 +292,7 @@ In both cases you can check if ``request`` is authenticated by calling ``check_a .. literalinclude:: ../examples/httpserver_authentication_handlers.py :caption: examples/httpserver_authentication_handlers.py - :emphasize-lines: 9-16,22-27,35,49,61 + :emphasize-lines: 9-16,21-26,34,48,60 :linenos: Redirects @@ -309,7 +309,7 @@ Alternatively, you can pass a ``status`` object directly to ``Redirect`` constru .. literalinclude:: ../examples/httpserver_redirects.py :caption: examples/httpserver_redirects.py - :emphasize-lines: 22-26,32,38,50,62 + :emphasize-lines: 21-25,31,37,49,61 :linenos: Server-Sent Events @@ -329,7 +329,7 @@ response object somewhere, so that it can be accessed later. .. literalinclude:: ../examples/httpserver_sse.py :caption: examples/httpserver_sse.py - :emphasize-lines: 10,17,46-53,63 + :emphasize-lines: 11,17,46-53,63 :linenos: Websockets @@ -352,7 +352,7 @@ but it is recommended as it makes it easier to handle multiple tasks. It can be .. literalinclude:: ../examples/httpserver_websocket.py :caption: examples/httpserver_websocket.py - :emphasize-lines: 12,20,65-72,88,99 + :emphasize-lines: 14,21,66-73,89,100 :linenos: Custom response types e.g. video streaming @@ -369,7 +369,7 @@ video to multiple clients while simultaneously handling other requests. .. literalinclude:: ../examples/httpserver_video_stream.py :caption: examples/httpserver_video_stream.py - :emphasize-lines: 31-77,92 + :emphasize-lines: 30-72,87 :linenos: HTTPS @@ -389,7 +389,7 @@ and setting ``https=True``. .. literalinclude:: ../examples/httpserver_https.py :caption: examples/httpserver_https.py - :emphasize-lines: 15-17 + :emphasize-lines: 14-16 :linenos: @@ -418,7 +418,7 @@ You can share same handler functions between servers or use different ones for e .. literalinclude:: ../examples/httpserver_multiple_servers.py :caption: examples/httpserver_multiple_servers.py - :emphasize-lines: 13-14,16-17,20,28,36-37,48-49,54-55 + :emphasize-lines: 12-13,15-16,19,27,35-36,47-48,53-54 :linenos: Debug mode diff --git a/docs/starting_methods.rst b/docs/starting_methods.rst index 6096293..757f966 100644 --- a/docs/starting_methods.rst +++ b/docs/starting_methods.rst @@ -22,7 +22,7 @@ it may not be able to access the internet. .. literalinclude:: ../examples/httpserver_simpletest_manual_ap.py :caption: examples/httpserver_simpletest_manual_ap.py - :emphasize-lines: 11-16,30 + :emphasize-lines: 10-15,29 :linenos: Manual Ethernet @@ -34,7 +34,7 @@ The only difference in usage is related to configuring the ``socket_source`` dif .. literalinclude:: ../examples/httpserver_simpletest_manual_ethernet.py :caption: examples/httpserver_simpletest_manual_ethernet.py - :emphasize-lines: 9-10,13-25,38 + :emphasize-lines: 7,10,12-24,37 :linenos: Automatic WiFi using ``settings.toml`` @@ -62,7 +62,7 @@ Note that we still need to import ``socketpool`` and ``wifi`` modules. .. literalinclude:: ../examples/httpserver_simpletest_auto_settings_toml.py :caption: examples/httpserver_simpletest_auto_settings_toml.py - :emphasize-lines: 11 + :emphasize-lines: 10 :linenos: @@ -78,5 +78,5 @@ You can read `more about it here