From 09189a85b5b93bef8baa32616a272ceb21293d9b Mon Sep 17 00:00:00 2001 From: Federico Caselli Date: Sat, 13 Jul 2024 21:00:26 +0200 Subject: [PATCH] refactor: replace `flake8` plugins with `ruff` (#2236) * chore: replace flake8 with ruff * chore: remove flake8 block in setup file * fix: make mypy happy * style: enable isort in ruff * chore: rework cython import to avoid coverage issue * style: format the examples * chore: fix mypy error * docs: update tutorial code to reflect format style changes --- docs/user/tutorial-asgi.rst | 10 +++-- docs/user/tutorial.rst | 35 +++++++++++------- e2e-tests/conftest.py | 1 - e2e-tests/server/app.py | 4 +- e2e-tests/server/chat.py | 3 +- e2e-tests/server/hub.py | 5 ++- e2e-tests/server/ping.py | 3 +- examples/asgilook/asgilook/app.py | 3 +- examples/asgilook/asgilook/cache.py | 1 - examples/asgilook/asgilook/config.py | 3 +- examples/asgilook/asgilook/images.py | 1 + examples/asgilook/asgilook/store.py | 3 +- examples/asgilook/tests/conftest.py | 5 ++- examples/look/look/app.py | 3 +- examples/look/look/images.py | 3 +- examples/look/tests/conftest.py | 1 - examples/look/tests/test_app.py | 9 +++-- examples/things_advanced.py | 3 +- examples/things_advanced_asgi.py | 3 +- falcon/__init__.py | 1 - falcon/app.py | 10 ++--- falcon/app_helpers.py | 3 +- falcon/asgi/_asgi_helpers.py | 3 +- falcon/asgi/app.py | 7 ++-- falcon/asgi/request.py | 2 +- falcon/asgi/response.py | 3 +- falcon/asgi/stream.py | 1 - falcon/asgi/structures.py | 1 - falcon/asgi/ws.py | 29 ++++++++------- falcon/bench/bench.py | 3 +- falcon/bench/create.py | 3 +- falcon/bench/dj/dj/settings.py | 3 +- falcon/bench/dj/dj/urls.py | 1 - falcon/bench/dj/dj/wsgi.py | 3 +- falcon/bench/dj/hello/views.py | 1 - falcon/cmd/inspect_app.py | 4 +- falcon/constants.py | 1 - falcon/errors.py | 1 - falcon/forwarded.py | 1 - falcon/hooks.py | 1 - falcon/http_error.py | 4 +- falcon/inspect.py | 8 +--- falcon/media/__init__.py | 1 - falcon/media/multipart.py | 1 - falcon/middleware.py | 4 +- falcon/response.py | 4 +- falcon/testing/client.py | 5 +-- falcon/testing/helpers.py | 6 +-- falcon/typing.py | 1 - falcon/util/__init__.py | 3 +- falcon/util/deprecation.py | 5 +-- falcon/util/misc.py | 7 +--- falcon/util/reader.py | 5 +-- falcon/util/structures.py | 28 +++++++------- falcon/util/sync.py | 8 +--- falcon/util/time.py | 1 - falcon/util/uri.py | 20 +++------- pyproject.toml | 47 ++++++++++++++++++++++++ setup.cfg | 12 ------ setup.py | 11 +++--- tests/_wsgi_test_app.py | 1 - tests/asgi/test_asgi_servers.py | 2 +- tests/asgi/test_boundedstream_asgi.py | 3 +- tests/asgi/test_hello_asgi.py | 4 +- tests/asgi/test_request_body_asgi.py | 1 - tests/asgi/test_response_media_asgi.py | 4 +- tests/asgi/test_scope.py | 3 +- tests/asgi/test_sse.py | 3 +- tests/asgi/test_testing_asgi.py | 1 + tests/asgi/test_ws.py | 5 +-- tests/conftest.py | 1 - tests/test_after_hooks.py | 5 +-- tests/test_app_initializers.py | 3 +- tests/test_before_hooks.py | 5 ++- tests/test_cmd_inspect_app.py | 6 +-- tests/test_compiled_router.py | 6 ++- tests/test_cookies.py | 12 +++--- tests/test_cors_middleware.py | 4 +- tests/test_custom_router.py | 3 +- tests/test_cython.py | 3 +- tests/test_default_router.py | 3 +- tests/test_deprecations.py | 3 +- tests/test_deps.py | 1 - tests/test_error_handlers.py | 7 ++-- tests/test_headers.py | 4 +- tests/test_http_custom_method_routing.py | 5 +-- tests/test_http_method_routing.py | 3 +- tests/test_httperror.py | 3 +- tests/test_httpstatus.py | 3 +- tests/test_inspect.py | 3 +- tests/test_media_handlers.py | 7 ++-- tests/test_media_multipart.py | 4 +- tests/test_media_urlencoded.py | 3 +- tests/test_middleware.py | 4 +- tests/test_query_params.py | 6 +-- tests/test_redirects.py | 3 +- tests/test_request_access_route.py | 3 +- tests/test_request_attrs.py | 7 ++-- tests/test_request_forwarded.py | 3 +- tests/test_request_media.py | 8 ++-- tests/test_response.py | 6 +-- tests/test_response_body.py | 4 +- tests/test_response_media.py | 4 +- tests/test_sink_and_static.py | 3 +- tests/test_sinks.py | 4 +- tests/test_static.py | 6 +-- tests/test_testing.py | 7 ++-- tests/test_uri_converters.py | 1 - tests/test_uri_templates.py | 5 +-- tests/test_utils.py | 20 +++++++--- tests/test_validators.py | 15 ++------ tox.ini | 28 +++----------- 112 files changed, 306 insertions(+), 317 deletions(-) diff --git a/docs/user/tutorial-asgi.rst b/docs/user/tutorial-asgi.rst index dd7c63b20..83324a91c 100644 --- a/docs/user/tutorial-asgi.rst +++ b/docs/user/tutorial-asgi.rst @@ -175,9 +175,10 @@ We can now implement a basic async image store. Save the following code as import io import aiofiles - import falcon import PIL.Image + import falcon + class Image: def __init__(self, config, image_id, size): @@ -266,6 +267,7 @@ of images. Place the code below in a file named ``images.py``: .. code:: python import aiofiles + import falcon @@ -670,8 +672,6 @@ The new ``thumbnails`` end-point should now render thumbnails on the fly:: Again, we could also verify thumbnail URIs in the browser or image viewer that supports HTTP input. - - .. _asgi_tutorial_caching: Caching Responses @@ -979,9 +979,11 @@ your ASGI Falcon application: .. code:: python - import falcon import logging + import falcon + + logging.basicConfig(level=logging.INFO) class ErrorResource: diff --git a/docs/user/tutorial.rst b/docs/user/tutorial.rst index 70b132e8d..b4589af9f 100644 --- a/docs/user/tutorial.rst +++ b/docs/user/tutorial.rst @@ -383,10 +383,9 @@ Then, update the responder to use the new media type: .. code:: python - import falcon - import msgpack + import falcon class Resource: @@ -467,11 +466,12 @@ Next, edit ``test_app.py`` to look like this: .. code:: python - import falcon - from falcon import testing import msgpack import pytest + import falcon + from falcon import testing + from look.app import app @@ -601,9 +601,10 @@ POSTs. Open ``images.py`` and add a POST responder to the import uuid import mimetypes - import falcon import msgpack + import falcon + class Resource: @@ -723,9 +724,10 @@ operation: import os import uuid - import falcon import msgpack + import falcon + class Resource: @@ -789,7 +791,8 @@ Hmm, it looks like we forgot to update ``app.py``. Let's do that now: import falcon - from .images import ImageStore, Resource + from .images import ImageStore + from .images import Resource app = application = falcon.App() @@ -813,7 +816,8 @@ similar to the following: import falcon - from .images import ImageStore, Resource + from .images import ImageStore + from .images import Resource def create_app(image_store): @@ -849,11 +853,12 @@ look similar to this: from unittest.mock import call, MagicMock, mock_open - import falcon - from falcon import testing import msgpack import pytest + import falcon + from falcon import testing + import look.app import look.images @@ -1041,7 +1046,8 @@ the image storage directory with an environment variable: import falcon - from .images import ImageStore, Resource + from .images import ImageStore + from .images import Resource def create_app(image_store): @@ -1123,9 +1129,10 @@ Go ahead and edit your ``images.py`` file to look something like this: import uuid import mimetypes - import falcon import msgpack + import falcon + class Collection: @@ -1234,7 +1241,9 @@ similar to the following: import falcon - from .images import Collection, ImageStore, Item + from .images import Collection + from .images import ImageStore + from .images import Item def create_app(image_store): diff --git a/e2e-tests/conftest.py b/e2e-tests/conftest.py index 0fc22ecb0..342d177c7 100644 --- a/e2e-tests/conftest.py +++ b/e2e-tests/conftest.py @@ -21,7 +21,6 @@ import falcon.testing - HERE = pathlib.Path(__file__).resolve().parent INDEX = '/static/index.html' diff --git a/e2e-tests/server/app.py b/e2e-tests/server/app.py index bde7e399d..be9558985 100644 --- a/e2e-tests/server/app.py +++ b/e2e-tests/server/app.py @@ -2,8 +2,10 @@ import falcon import falcon.asgi + from .chat import Chat -from .hub import Events, Hub +from .hub import Events +from .hub import Hub from .ping import Pong HERE = pathlib.Path(__file__).resolve().parent diff --git a/e2e-tests/server/chat.py b/e2e-tests/server/chat.py index 8cad04a89..0e40902d5 100644 --- a/e2e-tests/server/chat.py +++ b/e2e-tests/server/chat.py @@ -1,6 +1,7 @@ import re -from falcon.asgi import Request, WebSocket +from falcon.asgi import Request +from falcon.asgi import WebSocket from .hub import Hub diff --git a/e2e-tests/server/hub.py b/e2e-tests/server/hub.py index 181b2555f..e4e729b59 100644 --- a/e2e-tests/server/hub.py +++ b/e2e-tests/server/hub.py @@ -2,7 +2,10 @@ import typing import uuid -from falcon.asgi import Request, Response, SSEvent, WebSocket +from falcon.asgi import Request +from falcon.asgi import Response +from falcon.asgi import SSEvent +from falcon.asgi import WebSocket class Emitter: diff --git a/e2e-tests/server/ping.py b/e2e-tests/server/ping.py index bac2aec68..7deb5f077 100644 --- a/e2e-tests/server/ping.py +++ b/e2e-tests/server/ping.py @@ -1,7 +1,8 @@ from http import HTTPStatus import falcon -from falcon.asgi import Request, Response +from falcon.asgi import Request +from falcon.asgi import Response class Pong: diff --git a/examples/asgilook/asgilook/app.py b/examples/asgilook/asgilook/app.py index 6cdc48e83..de3f4e2e6 100644 --- a/examples/asgilook/asgilook/app.py +++ b/examples/asgilook/asgilook/app.py @@ -2,7 +2,8 @@ from .cache import RedisCache from .config import Config -from .images import Images, Thumbnails +from .images import Images +from .images import Thumbnails from .store import Store diff --git a/examples/asgilook/asgilook/cache.py b/examples/asgilook/asgilook/cache.py index e4819d0d0..ebb0f2532 100644 --- a/examples/asgilook/asgilook/cache.py +++ b/examples/asgilook/asgilook/cache.py @@ -1,5 +1,4 @@ import msgpack -import redis.asyncio as redis class RedisCache: diff --git a/examples/asgilook/asgilook/config.py b/examples/asgilook/asgilook/config.py index e5ac12c5b..701b4ab78 100644 --- a/examples/asgilook/asgilook/config.py +++ b/examples/asgilook/asgilook/config.py @@ -1,8 +1,9 @@ import os import pathlib -import redis.asyncio import uuid +import redis.asyncio + class Config: DEFAULT_CONFIG_PATH = '/tmp/asgilook' diff --git a/examples/asgilook/asgilook/images.py b/examples/asgilook/asgilook/images.py index 11eae57ac..20ce345a0 100644 --- a/examples/asgilook/asgilook/images.py +++ b/examples/asgilook/asgilook/images.py @@ -1,4 +1,5 @@ import aiofiles + import falcon diff --git a/examples/asgilook/asgilook/store.py b/examples/asgilook/asgilook/store.py index faf873c91..f6c43522f 100644 --- a/examples/asgilook/asgilook/store.py +++ b/examples/asgilook/asgilook/store.py @@ -3,9 +3,10 @@ import io import aiofiles -import falcon import PIL.Image +import falcon + class Image: def __init__(self, config, image_id, size): diff --git a/examples/asgilook/tests/conftest.py b/examples/asgilook/tests/conftest.py index 420a256df..efd920860 100644 --- a/examples/asgilook/tests/conftest.py +++ b/examples/asgilook/tests/conftest.py @@ -3,12 +3,13 @@ import uuid import fakeredis.aioredis -import falcon.asgi -import falcon.testing import PIL.Image import PIL.ImageDraw import pytest +import falcon.asgi +import falcon.testing + from asgilook.app import create_app from asgilook.config import Config diff --git a/examples/look/look/app.py b/examples/look/look/app.py index e472e1e09..abce808bd 100644 --- a/examples/look/look/app.py +++ b/examples/look/look/app.py @@ -2,7 +2,8 @@ import falcon -from .images import ImageStore, Resource +from .images import ImageStore +from .images import Resource def create_app(image_store): diff --git a/examples/look/look/images.py b/examples/look/look/images.py index 3b4e84a0c..31466d93c 100644 --- a/examples/look/look/images.py +++ b/examples/look/look/images.py @@ -3,9 +3,10 @@ import os import uuid -import falcon import msgpack +import falcon + class Resource: def __init__(self, image_store): diff --git a/examples/look/tests/conftest.py b/examples/look/tests/conftest.py index e7ce3f236..9d93edd06 100644 --- a/examples/look/tests/conftest.py +++ b/examples/look/tests/conftest.py @@ -5,7 +5,6 @@ import requests - LOOK_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) gunicorn = None diff --git a/examples/look/tests/test_app.py b/examples/look/tests/test_app.py index 3443ae0d4..c6db6451c 100644 --- a/examples/look/tests/test_app.py +++ b/examples/look/tests/test_app.py @@ -1,12 +1,15 @@ import io +from unittest.mock import call +from unittest.mock import MagicMock +from unittest.mock import mock_open from wsgiref.validate import InputWrapper -import falcon -from falcon import testing -from unittest.mock import call, MagicMock, mock_open import msgpack import pytest +import falcon +from falcon import testing + import look.app import look.images diff --git a/examples/things_advanced.py b/examples/things_advanced.py index 5c28280a7..ba3c87512 100644 --- a/examples/things_advanced.py +++ b/examples/things_advanced.py @@ -5,9 +5,10 @@ import uuid from wsgiref import simple_server -import falcon import requests +import falcon + class StorageEngine: def get_things(self, marker, limit): diff --git a/examples/things_advanced_asgi.py b/examples/things_advanced_asgi.py index dcd816ef5..fa05bc9a9 100644 --- a/examples/things_advanced_asgi.py +++ b/examples/things_advanced_asgi.py @@ -4,9 +4,10 @@ import logging import uuid +import httpx + import falcon import falcon.asgi -import httpx class StorageEngine: diff --git a/falcon/__init__.py b/falcon/__init__.py index 745856058..169f8bfc4 100644 --- a/falcon/__init__.py +++ b/falcon/__init__.py @@ -93,7 +93,6 @@ from falcon.util import wrap_sync_to_async_unsafe from falcon.version import __version__ - # NOTE(kgriffs): Only to be used internally on the rare occasion that we # need to log something that we can't communicate any other way. _logger = _logging.getLogger('falcon') diff --git a/falcon/app.py b/falcon/app.py index 434dd6b39..f71a291f6 100644 --- a/falcon/app.py +++ b/falcon/app.py @@ -37,12 +37,13 @@ from falcon.response import Response from falcon.response import ResponseOptions import falcon.status_codes as status -from falcon.typing import ErrorHandler, ErrorSerializer, SinkPrefix +from falcon.typing import ErrorHandler +from falcon.typing import ErrorSerializer +from falcon.typing import SinkPrefix from falcon.util import deprecation from falcon.util import misc from falcon.util.misc import code_to_http_status - # PERF(vytas): On Python 3.5+ (including cythonized modules), # reference via module global is faster than going via self _BODILESS_STATUS_CODES = frozenset( @@ -63,7 +64,7 @@ class App: - """This class is the main entry point into a Falcon-based WSGI app. + """The main entry point into a Falcon-based WSGI app. Each App instance provides a callable `WSGI `_ interface @@ -1152,8 +1153,7 @@ def _update_sink_and_static_routes(self): # TODO(myusko): This class is a compatibility alias, and should be removed # in the next major release (4.0). class API(App): - """ - This class is a compatibility alias of :class:`falcon.App`. + """Compatibility alias of :class:`falcon.App`. ``API`` was renamed to :class:`App ` in Falcon 3.0 in order to reflect the breadth of applications that :class:`App `, and its diff --git a/falcon/app_helpers.py b/falcon/app_helpers.py index 38b591914..1f0730f86 100644 --- a/falcon/app_helpers.py +++ b/falcon/app_helpers.py @@ -20,7 +20,8 @@ from falcon import util from falcon.constants import MEDIA_JSON from falcon.constants import MEDIA_XML -from falcon.errors import CompatibilityError, HTTPError +from falcon.errors import CompatibilityError +from falcon.errors import HTTPError from falcon.request import Request from falcon.response import Response from falcon.util.sync import _wrap_non_coroutine_unsafe diff --git a/falcon/asgi/_asgi_helpers.py b/falcon/asgi/_asgi_helpers.py index 3b96d1708..ce298abf2 100644 --- a/falcon/asgi/_asgi_helpers.py +++ b/falcon/asgi/_asgi_helpers.py @@ -15,7 +15,8 @@ import functools import inspect -from falcon.errors import UnsupportedError, UnsupportedScopeError +from falcon.errors import UnsupportedError +from falcon.errors import UnsupportedScopeError @functools.lru_cache(maxsize=16) diff --git a/falcon/asgi/app.py b/falcon/asgi/app.py index a4e0b9366..92b3ac2d4 100644 --- a/falcon/asgi/app.py +++ b/falcon/asgi/app.py @@ -34,12 +34,14 @@ from falcon.http_status import HTTPStatus from falcon.media.multipart import MultipartFormHandler import falcon.routing -from falcon.typing import ErrorHandler, SinkPrefix +from falcon.typing import ErrorHandler +from falcon.typing import SinkPrefix from falcon.util.misc import is_python_func from falcon.util.sync import _should_wrap_non_coroutines from falcon.util.sync import _wrap_non_coroutine_unsafe from falcon.util.sync import get_running_loop from falcon.util.sync import wrap_sync_to_async + from ._asgi_helpers import _validate_asgi_scope from ._asgi_helpers import _wrap_asgi_coroutine_func from .multipart import MultipartForm @@ -50,7 +52,6 @@ from .ws import WebSocket from .ws import WebSocketOptions - __all__ = ['App'] @@ -67,7 +68,7 @@ class App(falcon.app.App): - """This class is the main entry point into a Falcon-based ASGI app. + """The main entry point into a Falcon-based ASGI app. Each App instance provides a callable `ASGI `_ interface diff --git a/falcon/asgi/request.py b/falcon/asgi/request.py index 9650bfb63..4301fc4e6 100644 --- a/falcon/asgi/request.py +++ b/falcon/asgi/request.py @@ -21,10 +21,10 @@ from falcon.constants import SINGLETON_HEADERS from falcon.util.uri import parse_host from falcon.util.uri import parse_query_string + from . import _request_helpers as asgi_helpers from .stream import BoundedStream - __all__ = ['Request'] _SINGLETON_HEADERS_BYTESTR = frozenset([h.encode() for h in SINGLETON_HEADERS]) diff --git a/falcon/asgi/response.py b/falcon/asgi/response.py index 1d9110b12..2ec33e95a 100644 --- a/falcon/asgi/response.py +++ b/falcon/asgi/response.py @@ -19,7 +19,8 @@ from falcon import response from falcon.constants import _UNSET -from falcon.util.misc import _encode_items_to_latin1, is_python_func +from falcon.util.misc import _encode_items_to_latin1 +from falcon.util.misc import is_python_func __all__ = ['Response'] diff --git a/falcon/asgi/stream.py b/falcon/asgi/stream.py index 4b052bef5..e46179dd0 100644 --- a/falcon/asgi/stream.py +++ b/falcon/asgi/stream.py @@ -16,7 +16,6 @@ from falcon.errors import OperationNotAllowed - __all__ = ['BoundedStream'] diff --git a/falcon/asgi/structures.py b/falcon/asgi/structures.py index 2c44fa2f2..a1e9dda45 100644 --- a/falcon/asgi/structures.py +++ b/falcon/asgi/structures.py @@ -1,7 +1,6 @@ from falcon.constants import MEDIA_JSON from falcon.media.json import _DEFAULT_JSON_HANDLER - __all__ = ['SSEvent'] diff --git a/falcon/asgi/ws.py b/falcon/asgi/ws.py index db3700b2d..3879a6e52 100644 --- a/falcon/asgi/ws.py +++ b/falcon/asgi/ws.py @@ -1,15 +1,17 @@ import asyncio import collections from enum import Enum -from typing import Any -from typing import Awaitable -from typing import Callable -from typing import Deque -from typing import Dict -from typing import Iterable -from typing import Mapping -from typing import Optional -from typing import Union +from typing import ( + Any, + Awaitable, + Callable, + Deque, + Dict, + Iterable, + Mapping, + Optional, + Union, +) import falcon from falcon import errors @@ -18,7 +20,6 @@ from falcon.asgi_spec import WSCloseCode from falcon.constants import WebSocketPayloadType - _WebSocketState = Enum('_WebSocketState', 'HANDSHAKE ACCEPTED CLOSED') @@ -635,13 +636,13 @@ async def receive(self): # NOTE(kgriffs): Wait for a message if none are available. This pattern # was borrowed from the websockets.protocol module. while not self._messages: - # ------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # NOTE(kgriffs): The pattern below was borrowed from the websockets.protocol # module under the BSD 3-Clause "New" or "Revised" License. # # Ref: https://github.com/aaugustin/websockets/blob/master/src/websockets/protocol.py # noqa E501 # - # ------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # PERF(kgriffs): Using a bare future like this seems to be # slightly more efficient vs. something like asyncio.Event @@ -683,13 +684,13 @@ async def _pump(self): 'code', WSCloseCode.NORMAL ) - # ------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # NOTE(kgriffs): The pattern below was borrowed from the websockets.protocol # module under the BSD 3-Clause "New" or "Revised" License. # # Ref: https://github.com/aaugustin/websockets/blob/master/src/websockets/protocol.py # noqa E501 # - # ------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- while len(self._messages) >= self._max_queue: self._put_message_waiter = self._loop.create_future() try: diff --git a/falcon/bench/bench.py b/falcon/bench/bench.py index 5b12f8e40..9f3e4d899 100755 --- a/falcon/bench/bench.py +++ b/falcon/bench/bench.py @@ -15,7 +15,8 @@ # limitations under the License. import argparse -from collections import defaultdict, deque +from collections import defaultdict +from collections import deque from decimal import Decimal import gc import inspect diff --git a/falcon/bench/create.py b/falcon/bench/create.py index 7187a2590..cc53b98cb 100644 --- a/falcon/bench/create.py +++ b/falcon/bench/create.py @@ -80,8 +80,9 @@ def hello(account_id): def werkzeug(body, headers): + from werkzeug.routing import Map + from werkzeug.routing import Rule import werkzeug.wrappers as werkzeug - from werkzeug.routing import Map, Rule path = '/hello//test' url_map = Map([Rule(path, endpoint='hello')]) diff --git a/falcon/bench/dj/dj/settings.py b/falcon/bench/dj/dj/settings.py index bbb9cf898..15f575007 100644 --- a/falcon/bench/dj/dj/settings.py +++ b/falcon/bench/dj/dj/settings.py @@ -1,5 +1,4 @@ -""" -Django settings for dj project. +"""Django settings for dj project. Generated by 'django-admin startproject' using Django 1.11.3. diff --git a/falcon/bench/dj/dj/urls.py b/falcon/bench/dj/dj/urls.py index 90e2d24a6..bd1e2de8c 100644 --- a/falcon/bench/dj/dj/urls.py +++ b/falcon/bench/dj/dj/urls.py @@ -1,5 +1,4 @@ from django.urls import re_path as url from hello import views - urlpatterns = [url(r'^hello/(?P[0-9]+)/test$', views.hello)] diff --git a/falcon/bench/dj/dj/wsgi.py b/falcon/bench/dj/dj/wsgi.py index cd4a41847..b6aa68291 100644 --- a/falcon/bench/dj/dj/wsgi.py +++ b/falcon/bench/dj/dj/wsgi.py @@ -1,5 +1,4 @@ -""" -WSGI config for dj project. +"""WSGI config for dj project. It exposes the WSGI callable as a module-level variable named ``application``. diff --git a/falcon/bench/dj/hello/views.py b/falcon/bench/dj/hello/views.py index 9a98a7745..29f4b79e8 100644 --- a/falcon/bench/dj/hello/views.py +++ b/falcon/bench/dj/hello/views.py @@ -1,7 +1,6 @@ import django from django.http import HttpResponse - _body = django.x_test_body _headers = django.x_test_headers diff --git a/falcon/cmd/inspect_app.py b/falcon/cmd/inspect_app.py index bd3844f88..d1a1a038d 100644 --- a/falcon/cmd/inspect_app.py +++ b/falcon/cmd/inspect_app.py @@ -12,9 +12,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" -Script that prints out the routes of an App instance. -""" +"""Script that prints out the routes of an App instance.""" import argparse import importlib diff --git a/falcon/constants.py b/falcon/constants.py index 9bd71f373..2bf1252a4 100644 --- a/falcon/constants.py +++ b/falcon/constants.py @@ -2,7 +2,6 @@ import os import sys - PYPY = sys.implementation.name == 'pypy' """Evaluates to ``True`` when the current Python implementation is PyPy.""" diff --git a/falcon/errors.py b/falcon/errors.py index cdad7ffa7..74a50c69c 100644 --- a/falcon/errors.py +++ b/falcon/errors.py @@ -42,7 +42,6 @@ def on_get(self, req, resp): from falcon.util.deprecation import deprecated_args from falcon.util.misc import dt_to_http - __all__ = ( 'CompatibilityError', 'DelimiterError', diff --git a/falcon/forwarded.py b/falcon/forwarded.py index ba91975fb..9fe3c03f8 100644 --- a/falcon/forwarded.py +++ b/falcon/forwarded.py @@ -22,7 +22,6 @@ from falcon.util.uri import unquote_string - # '-' at the end to prevent interpretation as range in a char class _TCHAR = string.digits + string.ascii_letters + r"!#$%&'*+.^_`|~-" diff --git a/falcon/hooks.py b/falcon/hooks.py index 4172e9da6..f4bb7afae 100644 --- a/falcon/hooks.py +++ b/falcon/hooks.py @@ -23,7 +23,6 @@ from falcon.util.misc import get_argnames from falcon.util.sync import _wrap_non_coroutine_unsafe - _DECORABLE_METHOD_NAME = re.compile( r'^on_({})(_\w+)?$'.format('|'.join(method.lower() for method in COMBINED_METHODS)) ) diff --git a/falcon/http_error.py b/falcon/http_error.py index ad63c7ab7..20c221fe3 100644 --- a/falcon/http_error.py +++ b/falcon/http_error.py @@ -18,7 +18,9 @@ import xml.etree.ElementTree as et from falcon.constants import MEDIA_JSON -from falcon.util import code_to_http_status, http_status_to_code, uri +from falcon.util import code_to_http_status +from falcon.util import http_status_to_code +from falcon.util import uri from falcon.util.deprecation import deprecated_args diff --git a/falcon/inspect.py b/falcon/inspect.py index e5bc4c690..919165687 100644 --- a/falcon/inspect.py +++ b/falcon/inspect.py @@ -16,11 +16,7 @@ from functools import partial import inspect -from typing import Callable # NOQA: F401 -from typing import Dict # NOQA: F401 -from typing import List -from typing import Optional -from typing import Type # NOQA: F401 +from typing import Callable, Dict, List, Optional, Type from falcon import app_helpers from falcon.app import App @@ -101,7 +97,7 @@ def wraps(fn): # router inspection registry -_supported_routers = {} # type: Dict[Type, Callable] +_supported_routers: Dict[Type, Callable] = {} def inspect_static_routes(app: App) -> 'List[StaticRouteInfo]': diff --git a/falcon/media/__init__.py b/falcon/media/__init__.py index 3db2a19b8..a90c0e384 100644 --- a/falcon/media/__init__.py +++ b/falcon/media/__init__.py @@ -10,7 +10,6 @@ from .multipart import MultipartFormHandler from .urlencoded import URLEncodedFormHandler - __all__ = [ 'BaseHandler', 'BinaryBaseHandlerWS', diff --git a/falcon/media/multipart.py b/falcon/media/multipart.py index 240a4781c..63432da21 100644 --- a/falcon/media/multipart.py +++ b/falcon/media/multipart.py @@ -25,7 +25,6 @@ from falcon.util import misc from falcon.util.mediatypes import parse_header - # TODO(vytas): # * Better support for form-wide charset setting # * Clean up, simplify, and optimize BufferedReader diff --git a/falcon/middleware.py b/falcon/middleware.py index 195892a29..a799fe2f8 100644 --- a/falcon/middleware.py +++ b/falcon/middleware.py @@ -1,6 +1,4 @@ -from typing import Iterable -from typing import Optional -from typing import Union +from typing import Iterable, Optional, Union from .request import Request from .response import Response diff --git a/falcon/response.py b/falcon/response.py index cad529d3c..de3c3b175 100644 --- a/falcon/response.py +++ b/falcon/response.py @@ -34,11 +34,11 @@ from falcon.util import http_status_to_code from falcon.util import structures from falcon.util import TimezoneGMT -from falcon.util.deprecation import AttributeRemovedError, deprecated +from falcon.util.deprecation import AttributeRemovedError +from falcon.util.deprecation import deprecated from falcon.util.uri import encode_check_escaped as uri_encode from falcon.util.uri import encode_value_check_escaped as uri_encode_value - GMT_TIMEZONE = TimezoneGMT() _STREAM_LEN_REMOVED_MSG = ( diff --git a/falcon/testing/client.py b/falcon/testing/client.py index 05a59f599..12f425967 100644 --- a/falcon/testing/client.py +++ b/falcon/testing/client.py @@ -23,10 +23,7 @@ import inspect import json as json_module import time -from typing import Dict -from typing import Optional -from typing import Sequence -from typing import Union +from typing import Dict, Optional, Sequence, Union import warnings import wsgiref.validate diff --git a/falcon/testing/helpers.py b/falcon/testing/helpers.py index d0d92dbff..1b38e975e 100644 --- a/falcon/testing/helpers.py +++ b/falcon/testing/helpers.py @@ -35,11 +35,7 @@ import socket import sys import time -from typing import Any -from typing import Dict -from typing import Iterable -from typing import Optional -from typing import Union +from typing import Any, Dict, Iterable, Optional, Union import falcon from falcon import errors as falcon_errors diff --git a/falcon/typing.py b/falcon/typing.py index 4acf8ad97..bc4137027 100644 --- a/falcon/typing.py +++ b/falcon/typing.py @@ -19,7 +19,6 @@ from falcon.request import Request from falcon.response import Response - # Error handlers ErrorHandler = Callable[[Request, Response, BaseException, dict], Any] diff --git a/falcon/util/__init__.py b/falcon/util/__init__.py index 1cead07e8..2d946f8be 100644 --- a/falcon/util/__init__.py +++ b/falcon/util/__init__.py @@ -53,7 +53,6 @@ from falcon.util.sync import wrap_sync_to_async_unsafe from falcon.util.time import TimezoneGMT - # NOTE(kgriffs): Backport support for the new 'SameSite' attribute # for Python versions prior to 3.8. We do it this way because # SimpleCookie does not give us a simple way to specify our own @@ -81,8 +80,8 @@ def __getattr__(name: str) -> ModuleType: if name == 'json': - import warnings import json # NOQA + import warnings warnings.warn( 'Importing json from "falcon.util" is deprecated.', DeprecatedWarning diff --git a/falcon/util/deprecation.py b/falcon/util/deprecation.py index ed1229916..56ccf213c 100644 --- a/falcon/util/deprecation.py +++ b/falcon/util/deprecation.py @@ -18,12 +18,9 @@ """ import functools -from typing import Any -from typing import Callable -from typing import Optional +from typing import Any, Callable, Optional import warnings - __all__ = ( 'AttributeRemovedError', 'DeprecatedWarning', diff --git a/falcon/util/misc.py b/falcon/util/misc.py index bbd3080ed..a6a60a0dc 100644 --- a/falcon/util/misc.py +++ b/falcon/util/misc.py @@ -28,12 +28,7 @@ import http import inspect import re -from typing import Any -from typing import Callable -from typing import Dict -from typing import List -from typing import Tuple -from typing import Union +from typing import Any, Callable, Dict, List, Tuple, Union import unicodedata from falcon import status_codes diff --git a/falcon/util/reader.py b/falcon/util/reader.py index b97484f7f..96adc4b5f 100644 --- a/falcon/util/reader.py +++ b/falcon/util/reader.py @@ -18,10 +18,7 @@ import functools import io -from typing import Callable -from typing import IO -from typing import List -from typing import Optional +from typing import Callable, IO, List, Optional from falcon.errors import DelimiterError diff --git a/falcon/util/structures.py b/falcon/util/structures.py index f5b4e97c5..020d43471 100644 --- a/falcon/util/structures.py +++ b/falcon/util/structures.py @@ -30,23 +30,24 @@ from collections.abc import Mapping from collections.abc import MutableMapping -from typing import Any -from typing import Dict -from typing import ItemsView -from typing import Iterable -from typing import Iterator -from typing import KeysView -from typing import Optional -from typing import Tuple -from typing import TYPE_CHECKING -from typing import ValuesView +from typing import ( + Any, + Dict, + ItemsView, + Iterable, + Iterator, + KeysView, + Optional, + Tuple, + TYPE_CHECKING, + ValuesView, +) # TODO(kgriffs): If we ever diverge from what is upstream in Requests, # then we will need write tests and remove the "no cover" pragma. class CaseInsensitiveDict(MutableMapping): # pragma: no cover - """ - A case-insensitive ``dict``-like object. + """A case-insensitive ``dict``-like object. Implements all methods and operations of ``collections.abc.MutableMapping`` as well as dict's `copy`. Also @@ -121,8 +122,7 @@ def __repr__(self) -> str: # Context is, by design, a bare class, and the mapping interface may be # removed in a future Falcon release. class Context: - """ - Convenience class to hold contextual information in its attributes. + """Convenience class to hold contextual information in its attributes. This class is used as the default :class:`~.Request` and :class:`~Response` context type (see diff --git a/falcon/util/sync.py b/falcon/util/sync.py index f19d9f1ae..c32c3a3d4 100644 --- a/falcon/util/sync.py +++ b/falcon/util/sync.py @@ -4,13 +4,7 @@ from functools import wraps import inspect import os -from typing import Any -from typing import Awaitable -from typing import Callable -from typing import Optional -from typing import TypeVar -from typing import Union - +from typing import Any, Awaitable, Callable, Optional, TypeVar, Union __all__ = [ 'async_to_sync', diff --git a/falcon/util/time.py b/falcon/util/time.py index 485f3b78a..d475a166e 100644 --- a/falcon/util/time.py +++ b/falcon/util/time.py @@ -12,7 +12,6 @@ import datetime from typing import Optional - __all__ = ['TimezoneGMT'] diff --git a/falcon/util/uri.py b/falcon/util/uri.py index 15bef3c97..a9acec6d4 100644 --- a/falcon/util/uri.py +++ b/falcon/util/uri.py @@ -23,23 +23,14 @@ name, port = uri.parse_host('example.org:8080') """ -from typing import Callable -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple, TYPE_CHECKING -from typing import Union +from typing import Callable, Dict, List, Optional, Tuple, TYPE_CHECKING, Union from falcon.constants import PYPY try: - from falcon.cyutil.uri import ( - decode as _cy_decode, - parse_query_string as _cy_parse_query_string, - ) + from falcon.cyutil import uri as _cy_uri # type: ignore except ImportError: - _cy_decode = None - _cy_parse_query_string = None + _cy_uri = None # NOTE(kgriffs): See also RFC 3986 @@ -553,8 +544,9 @@ def unquote_string(quoted: str) -> str: # TODO(vytas): Restructure this in favour of a cleaner way to hoist the pure # Cython functions into this module. if not TYPE_CHECKING: - decode = _cy_decode or decode # NOQA - parse_query_string = _cy_parse_query_string or parse_query_string # NOQA + if _cy_uri is not None: + decode = _cy_uri.decode # NOQA + parse_query_string = _cy_uri.parse_query_string # NOQA __all__ = [ diff --git a/pyproject.toml b/pyproject.toml index 73fbcea1e..c56da1c31 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,6 +94,53 @@ format.quote-style = "single" line-length = 88 extend-exclude = ["falcon/vendor"] + builtins = [ + "ignore", + "attr", + "defined", + ] + exclude = [ + ".ecosystem", + ".eggs", + ".git", + ".tox", + ".venv", + "build", + "dist", + "docs", + "examples", + "falcon/bench/nuts", + ] + +[tool.ruff.lint] + select = [ + "C9", + "E", + "F", + "W", + "I" + ] + +[tool.ruff.lint.mccabe] + max-complexity = 15 + +[tool.ruff.lint.per-file-ignores] + "**/__init__.py" = [ + "F401", + "E402", + "F403" + ] + "falcon/uri.py" = ["F401"] + +[tool.ruff.lint.isort] + case-sensitive = false + force-single-line = true + order-by-type = false + single-line-exclusions = [ + "typing" + ] + force-sort-within-sections = true + known-local-folder = ["asgilook", "look"] [tool.pytest.ini_options] filterwarnings = [ diff --git a/setup.cfg b/setup.cfg index e7c308429..04059572e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -78,15 +78,3 @@ tag_build = dev1 [aliases] test=pytest - -[flake8] -max-complexity = 15 -exclude = .ecosystem,.eggs,.git,.tox,.venv,build,dist,docs,examples,falcon/bench/nuts -extend-ignore = F403,W504,E203,I202 -max-line-length = 88 -import-order-style = google -application-import-names = falcon,examples -builtins = ignore,attr,defined -per-file-ignores = - **/__init__.py:F401,E402 - falcon/uri.py:F401 diff --git a/setup.py b/setup.py index edae6c702..200e7bab3 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,8 @@ import re import sys -from setuptools import Extension, setup +from setuptools import Extension +from setuptools import setup MYDIR = path.abspath(os.path.dirname(__file__)) @@ -32,11 +33,9 @@ class BuildFailed(Exception): def get_cython_options(): # from sqlalchemy setup.py - from distutils.errors import ( - CCompilerError, - DistutilsExecError, - DistutilsPlatformError, - ) + from distutils.errors import CCompilerError + from distutils.errors import DistutilsExecError + from distutils.errors import DistutilsPlatformError ext_errors = (CCompilerError, DistutilsExecError, DistutilsPlatformError) if sys.platform == 'win32': diff --git a/tests/_wsgi_test_app.py b/tests/_wsgi_test_app.py index 871ce3d04..aa565ef66 100644 --- a/tests/_wsgi_test_app.py +++ b/tests/_wsgi_test_app.py @@ -4,7 +4,6 @@ import falcon - HERE = os.path.abspath(os.path.dirname(__file__)) diff --git a/tests/asgi/test_asgi_servers.py b/tests/asgi/test_asgi_servers.py index 321e41f96..6e790e0fd 100644 --- a/tests/asgi/test_asgi_servers.py +++ b/tests/asgi/test_asgi_servers.py @@ -17,8 +17,8 @@ import websockets.exceptions from falcon import testing -from . import _asgi_test_app +from . import _asgi_test_app _MODULE_DIR = os.path.abspath(os.path.dirname(__file__)) diff --git a/tests/asgi/test_boundedstream_asgi.py b/tests/asgi/test_boundedstream_asgi.py index 135d7441d..db79b7f86 100644 --- a/tests/asgi/test_boundedstream_asgi.py +++ b/tests/asgi/test_boundedstream_asgi.py @@ -3,7 +3,8 @@ import pytest import falcon -from falcon import asgi, testing +from falcon import asgi +from falcon import testing @pytest.mark.parametrize( diff --git a/tests/asgi/test_hello_asgi.py b/tests/asgi/test_hello_asgi.py index c60cc6737..cbc5d3dc3 100644 --- a/tests/asgi/test_hello_asgi.py +++ b/tests/asgi/test_hello_asgi.py @@ -2,6 +2,7 @@ import os import tempfile +from _util import disable_asgi_non_coroutine_wrapping # NOQA import aiofiles import pytest @@ -9,9 +10,6 @@ from falcon import testing import falcon.asgi -from _util import disable_asgi_non_coroutine_wrapping # NOQA - - SIZE_1_KB = 1024 diff --git a/tests/asgi/test_request_body_asgi.py b/tests/asgi/test_request_body_asgi.py index 4726712e5..fed5267b9 100644 --- a/tests/asgi/test_request_body_asgi.py +++ b/tests/asgi/test_request_body_asgi.py @@ -7,7 +7,6 @@ import falcon.request import falcon.testing as testing - SIZE_1_KB = 1024 diff --git a/tests/asgi/test_response_media_asgi.py b/tests/asgi/test_response_media_asgi.py index a55c6e606..b911c1486 100644 --- a/tests/asgi/test_response_media_asgi.py +++ b/tests/asgi/test_response_media_asgi.py @@ -3,7 +3,9 @@ import pytest import falcon -from falcon import errors, media, testing +from falcon import errors +from falcon import media +from falcon import testing import falcon.asgi from falcon.util.deprecation import DeprecatedWarning diff --git a/tests/asgi/test_scope.py b/tests/asgi/test_scope.py index e368f6576..a4bd26293 100644 --- a/tests/asgi/test_scope.py +++ b/tests/asgi/test_scope.py @@ -5,7 +5,8 @@ import falcon from falcon import testing from falcon.asgi import App -from falcon.errors import UnsupportedError, UnsupportedScopeError +from falcon.errors import UnsupportedError +from falcon.errors import UnsupportedScopeError class CustomCookies: diff --git a/tests/asgi/test_sse.py b/tests/asgi/test_sse.py index df04688c7..f6e6a7b53 100644 --- a/tests/asgi/test_sse.py +++ b/tests/asgi/test_sse.py @@ -5,7 +5,8 @@ import falcon from falcon import testing -from falcon.asgi import App, SSEvent +from falcon.asgi import App +from falcon.asgi import SSEvent def test_no_events(): diff --git a/tests/asgi/test_testing_asgi.py b/tests/asgi/test_testing_asgi.py index 5f67196de..f2de736cd 100644 --- a/tests/asgi/test_testing_asgi.py +++ b/tests/asgi/test_testing_asgi.py @@ -4,6 +4,7 @@ import falcon from falcon import testing + from . import _asgi_test_app diff --git a/tests/asgi/test_ws.py b/tests/asgi/test_ws.py index 10004751d..e83911043 100644 --- a/tests/asgi/test_ws.py +++ b/tests/asgi/test_ws.py @@ -5,16 +5,15 @@ import cbor2 import pytest - import falcon -from falcon import media, testing +from falcon import media +from falcon import testing from falcon.asgi import App from falcon.asgi.ws import _WebSocketState as ServerWebSocketState from falcon.asgi.ws import WebSocket from falcon.asgi.ws import WebSocketOptions from falcon.testing.helpers import _WebSocketState as ClientWebSocketState - try: import rapidjson # type: ignore except ImportError: diff --git a/tests/conftest.py b/tests/conftest.py index 3ea143330..25707f7ca 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,7 +4,6 @@ import falcon - _FALCON_TEST_ENV = ( ('FALCON_ASGI_WRAP_NON_COROUTINES', 'Y'), ('FALCON_TESTING_SESSION', 'Y'), diff --git a/tests/test_after_hooks.py b/tests/test_after_hooks.py index 4f5cc1f00..46bb07771 100644 --- a/tests/test_after_hooks.py +++ b/tests/test_after_hooks.py @@ -1,14 +1,13 @@ import functools import json +from _util import create_app # NOQA +from _util import create_resp # NOQA import pytest import falcon from falcon import testing -from _util import create_app, create_resp # NOQA - - # -------------------------------------------------------------------- # Fixtures # -------------------------------------------------------------------- diff --git a/tests/test_app_initializers.py b/tests/test_app_initializers.py index a2cedd59d..0df3429c1 100644 --- a/tests/test_app_initializers.py +++ b/tests/test_app_initializers.py @@ -1,7 +1,8 @@ import pytest import falcon -from falcon import media, testing +from falcon import media +from falcon import testing class MediaResource: diff --git a/tests/test_before_hooks.py b/tests/test_before_hooks.py index ebc936030..23d5eed57 100644 --- a/tests/test_before_hooks.py +++ b/tests/test_before_hooks.py @@ -2,13 +2,14 @@ import io import json +from _util import create_app # NOQA +from _util import create_resp # NOQA +from _util import disable_asgi_non_coroutine_wrapping # NOQA import pytest import falcon import falcon.testing as testing -from _util import create_app, create_resp, disable_asgi_non_coroutine_wrapping # NOQA - def validate(req, resp, resource, params): assert resource diff --git a/tests/test_cmd_inspect_app.py b/tests/test_cmd_inspect_app.py index fc46d1192..7a6866f74 100644 --- a/tests/test_cmd_inspect_app.py +++ b/tests/test_cmd_inspect_app.py @@ -2,14 +2,14 @@ import io import sys +from _util import create_app # NOQA import pytest -from falcon import App, inspect +from falcon import App +from falcon import inspect from falcon.cmd import inspect_app from falcon.testing import redirected -from _util import create_app # NOQA - _WIN32 = sys.platform.startswith('win') _MODULE = 'tests.test_cmd_inspect_app' diff --git a/tests/test_compiled_router.py b/tests/test_compiled_router.py index 74c3ac0cf..3ef622fa8 100644 --- a/tests/test_compiled_router.py +++ b/tests/test_compiled_router.py @@ -1,10 +1,12 @@ -from threading import Barrier, Thread +from threading import Barrier +from threading import Thread from time import sleep from unittest.mock import MagicMock import pytest -from falcon.routing import CompiledRouter, CompiledRouterOptions +from falcon.routing import CompiledRouter +from falcon.routing import CompiledRouterOptions def test_find_src(monkeypatch): diff --git a/tests/test_cookies.py b/tests/test_cookies.py index 1d2e0c847..cb492c32c 100644 --- a/tests/test_cookies.py +++ b/tests/test_cookies.py @@ -1,15 +1,17 @@ -from datetime import datetime, timedelta, timezone, tzinfo +from datetime import datetime +from datetime import timedelta +from datetime import timezone +from datetime import tzinfo from http import cookies as http_cookies import re +from _util import create_app # NOQA import pytest import falcon import falcon.testing as testing -from falcon.util import http_date_to_dt, TimezoneGMT - -from _util import create_app # NOQA - +from falcon.util import http_date_to_dt +from falcon.util import TimezoneGMT UNICODE_TEST_STRING = 'Unicode_\xc3\xa6\xc3\xb8' diff --git a/tests/test_cors_middleware.py b/tests/test_cors_middleware.py index 05f6c518e..dae9a7ee7 100644 --- a/tests/test_cors_middleware.py +++ b/tests/test_cors_middleware.py @@ -1,10 +1,10 @@ +from _util import create_app # NOQA +from _util import disable_asgi_non_coroutine_wrapping # NOQA import pytest import falcon from falcon import testing -from _util import create_app, disable_asgi_non_coroutine_wrapping # NOQA - @pytest.fixture def client(asgi): diff --git a/tests/test_custom_router.py b/tests/test_custom_router.py index b21b0c447..f38c914eb 100644 --- a/tests/test_custom_router.py +++ b/tests/test_custom_router.py @@ -1,10 +1,9 @@ +from _util import create_app # NOQA import pytest import falcon from falcon import testing -from _util import create_app # NOQA - @pytest.mark.parametrize('asgi', [True, False]) def test_custom_router_add_route_should_be_used(asgi): diff --git a/tests/test_cython.py b/tests/test_cython.py index 93b7a83fa..ea7c92bbb 100644 --- a/tests/test_cython.py +++ b/tests/test_cython.py @@ -1,12 +1,11 @@ import io +from _util import has_cython # NOQA import pytest import falcon import falcon.util -from _util import has_cython # NOQA - class TestCythonized: @pytest.mark.skipif(not has_cython, reason='Cython not installed') diff --git a/tests/test_default_router.py b/tests/test_default_router.py index efffe29d0..de9dc83e0 100644 --- a/tests/test_default_router.py +++ b/tests/test_default_router.py @@ -1,12 +1,11 @@ import textwrap +from _util import create_app # NOQA import pytest from falcon import testing from falcon.routing import DefaultRouter -from _util import create_app # NOQA - def client(asgi): return testing.TestClient(create_app(asgi)) diff --git a/tests/test_deprecations.py b/tests/test_deprecations.py index 09570a3b0..3907f268c 100644 --- a/tests/test_deprecations.py +++ b/tests/test_deprecations.py @@ -1,4 +1,5 @@ -from falcon import request_helpers, stream +from falcon import request_helpers +from falcon import stream def test_bounded_stream(): diff --git a/tests/test_deps.py b/tests/test_deps.py index 73e28e1a6..a747b2af7 100644 --- a/tests/test_deps.py +++ b/tests/test_deps.py @@ -1,6 +1,5 @@ from falcon.vendor import mimeparse - # TODO(vytas): Remove this test since it makes little sense now that # we have vendored python-mimeparse? diff --git a/tests/test_error_handlers.py b/tests/test_error_handlers.py index 06282bdc7..c6c5785ff 100644 --- a/tests/test_error_handlers.py +++ b/tests/test_error_handlers.py @@ -1,12 +1,13 @@ +from _util import create_app # NOQA +from _util import disable_asgi_non_coroutine_wrapping # NOQA import pytest import falcon -from falcon import constants, testing +from falcon import constants +from falcon import testing import falcon.asgi from falcon.util.deprecation import DeprecatedWarning -from _util import create_app, disable_asgi_non_coroutine_wrapping # NOQA - def capture_error(req, resp, ex, params): resp.status = falcon.HTTP_723 diff --git a/tests/test_headers.py b/tests/test_headers.py index afdf18e0c..ccf877fd1 100644 --- a/tests/test_headers.py +++ b/tests/test_headers.py @@ -1,6 +1,7 @@ from collections import defaultdict from datetime import datetime +from _util import create_app # NOQA import pytest import falcon @@ -8,9 +9,6 @@ from falcon.util.deprecation import DeprecatedWarning from falcon.util.misc import _utcnow -from _util import create_app # NOQA - - SAMPLE_BODY = testing.rand_string(0, 128 * 1024) diff --git a/tests/test_http_custom_method_routing.py b/tests/test_http_custom_method_routing.py index c80fa0289..7271f4082 100644 --- a/tests/test_http_custom_method_routing.py +++ b/tests/test_http_custom_method_routing.py @@ -2,6 +2,8 @@ import os import wsgiref.validate +from _util import create_app # NOQA +from _util import has_cython # NOQA import pytest import falcon @@ -9,9 +11,6 @@ import falcon.constants from falcon.routing import util -from _util import create_app, has_cython # NOQA - - FALCON_CUSTOM_HTTP_METHODS = ['FOO', 'BAR'] diff --git a/tests/test_http_method_routing.py b/tests/test_http_method_routing.py index 0ef87f384..529e4621d 100644 --- a/tests/test_http_method_routing.py +++ b/tests/test_http_method_routing.py @@ -1,13 +1,12 @@ from functools import wraps +from _util import create_app # NOQA import pytest import falcon import falcon.constants import falcon.testing as testing -from _util import create_app # NOQA - # RFC 7231, 5789 methods HTTP_METHODS = [ 'CONNECT', diff --git a/tests/test_httperror.py b/tests/test_httperror.py index e844a5957..2de1972ee 100644 --- a/tests/test_httperror.py +++ b/tests/test_httperror.py @@ -6,6 +6,7 @@ import wsgiref.validate import xml.etree.ElementTree as et # noqa: I202 +from _util import create_app # NOQA import pytest import yaml @@ -13,8 +14,6 @@ import falcon.testing as testing from falcon.util.deprecation import DeprecatedWarning -from _util import create_app # NOQA - @pytest.fixture def client(asgi): diff --git a/tests/test_httpstatus.py b/tests/test_httpstatus.py index 41cbd0523..e7ff51c17 100644 --- a/tests/test_httpstatus.py +++ b/tests/test_httpstatus.py @@ -2,6 +2,7 @@ import http +from _util import create_app # NOQA import pytest import falcon @@ -9,8 +10,6 @@ import falcon.testing as testing from falcon.util.deprecation import AttributeRemovedError -from _util import create_app # NOQA - @pytest.fixture(params=[True, False]) def client(request): diff --git a/tests/test_inspect.py b/tests/test_inspect.py index 84b9c218b..5da970ed2 100644 --- a/tests/test_inspect.py +++ b/tests/test_inspect.py @@ -6,7 +6,8 @@ import pytest import falcon -from falcon import inspect, routing +from falcon import inspect +from falcon import routing import falcon.asgi diff --git a/tests/test_media_handlers.py b/tests/test_media_handlers.py index 8b95600b6..e0442751b 100644 --- a/tests/test_media_handlers.py +++ b/tests/test_media_handlers.py @@ -3,18 +3,17 @@ import json import platform +from _util import create_app # NOQA import mujson import pytest import ujson import falcon -from falcon import media, testing +from falcon import media +from falcon import testing from falcon.asgi.stream import BoundedStream from falcon.util.deprecation import DeprecatedWarning -from _util import create_app # NOQA - - orjson = None rapidjson = None try: diff --git a/tests/test_media_multipart.py b/tests/test_media_multipart.py index 6643a3146..1f91fe3e2 100644 --- a/tests/test_media_multipart.py +++ b/tests/test_media_multipart.py @@ -3,6 +3,7 @@ import os import random +from _util import create_app # NOQA: I100 import pytest import falcon @@ -10,9 +11,6 @@ from falcon import testing from falcon.util import BufferedReader -from _util import create_app # NOQA: I100 - - try: import msgpack # type: ignore except ImportError: diff --git a/tests/test_media_urlencoded.py b/tests/test_media_urlencoded.py index be7458773..45d38c583 100644 --- a/tests/test_media_urlencoded.py +++ b/tests/test_media_urlencoded.py @@ -1,13 +1,12 @@ import io +from _util import create_app # NOQA import pytest import falcon from falcon import media from falcon import testing -from _util import create_app # NOQA - def test_deserialize_empty_form(): handler = media.URLEncodedFormHandler() diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 04de946e8..6b5557738 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -4,6 +4,7 @@ import cython except ImportError: cython = None +from _util import create_app # NOQA import pytest import falcon @@ -12,9 +13,6 @@ from falcon.util.deprecation import DeprecatedWarning from falcon.util.misc import _utcnow -from _util import create_app # NOQA - - _EXPECTED_BODY = {'status': 'ok'} context = {'executed_methods': []} # type: ignore diff --git a/tests/test_query_params.py b/tests/test_query_params.py index 3d86da060..239daf5c2 100644 --- a/tests/test_query_params.py +++ b/tests/test_query_params.py @@ -1,15 +1,15 @@ -from datetime import date, datetime +from datetime import date +from datetime import datetime import json from uuid import UUID +from _util import create_app # NOQA import pytest import falcon from falcon.errors import HTTPInvalidParam import falcon.testing as testing -from _util import create_app # NOQA - class Resource(testing.SimpleTestResource): @falcon.before(testing.capture_responder_args) diff --git a/tests/test_redirects.py b/tests/test_redirects.py index e4d2429b0..7138e084a 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -1,10 +1,9 @@ +from _util import create_app # NOQA import pytest import falcon import falcon.testing as testing -from _util import create_app # NOQA - @pytest.fixture def client(asgi): diff --git a/tests/test_request_access_route.py b/tests/test_request_access_route.py index 7571efae7..96de6a87e 100644 --- a/tests/test_request_access_route.py +++ b/tests/test_request_access_route.py @@ -1,10 +1,9 @@ +from _util import create_req # NOQA import pytest from falcon.request import Request import falcon.testing as testing -from _util import create_req # NOQA - def test_remote_addr_default(asgi): req = create_req(asgi) diff --git a/tests/test_request_attrs.py b/tests/test_request_attrs.py index 8ae5b72dc..5d8f341dd 100644 --- a/tests/test_request_attrs.py +++ b/tests/test_request_attrs.py @@ -1,18 +1,17 @@ import datetime import itertools +from _util import create_req # NOQA import pytest import falcon -from falcon.request import Request, RequestOptions +from falcon.request import Request +from falcon.request import RequestOptions from falcon.request_helpers import _parse_etags import falcon.testing as testing import falcon.uri from falcon.util.structures import ETag -from _util import create_req # NOQA - - _HTTP_VERSIONS = ['1.0', '1.1', '2'] diff --git a/tests/test_request_forwarded.py b/tests/test_request_forwarded.py index c4d36c39f..2ab60bb28 100644 --- a/tests/test_request_forwarded.py +++ b/tests/test_request_forwarded.py @@ -1,6 +1,5 @@ -import pytest - from _util import create_req # NOQA +import pytest def test_no_forwarded_headers(asgi): diff --git a/tests/test_request_media.py b/tests/test_request_media.py index 23654cc27..4f3d8febc 100644 --- a/tests/test_request_media.py +++ b/tests/test_request_media.py @@ -1,11 +1,13 @@ import json +from _util import create_app # NOQA import pytest import falcon -from falcon import errors, media, testing, util - -from _util import create_app # NOQA +from falcon import errors +from falcon import media +from falcon import testing +from falcon import util def create_client(asgi, handlers=None, resource=None): diff --git a/tests/test_response.py b/tests/test_response.py index fe2b73d93..f8e370eb1 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -1,10 +1,10 @@ from unittest.mock import MagicMock +from _util import create_resp # NOQA import pytest -from falcon import MEDIA_TEXT, ResponseOptions - -from _util import create_resp # NOQA +from falcon import MEDIA_TEXT +from falcon import ResponseOptions @pytest.fixture(params=[True, False]) diff --git a/tests/test_response_body.py b/tests/test_response_body.py index 8a1a221bb..2f1e9027e 100644 --- a/tests/test_response_body.py +++ b/tests/test_response_body.py @@ -1,11 +1,11 @@ +from _util import create_app # NOQA +from _util import create_resp # NOQA import pytest import falcon from falcon import testing from falcon.util.deprecation import AttributeRemovedError -from _util import create_app, create_resp # NOQA - @pytest.fixture def resp(asgi): diff --git a/tests/test_response_media.py b/tests/test_response_media.py index 6c19a59ea..4c72ce374 100644 --- a/tests/test_response_media.py +++ b/tests/test_response_media.py @@ -3,7 +3,9 @@ import pytest import falcon -from falcon import errors, media, testing +from falcon import errors +from falcon import media +from falcon import testing @pytest.fixture diff --git a/tests/test_sink_and_static.py b/tests/test_sink_and_static.py index 35002e289..c87a2c53e 100644 --- a/tests/test_sink_and_static.py +++ b/tests/test_sink_and_static.py @@ -1,10 +1,9 @@ +from _util import create_app # NOQA import pytest import falcon from falcon import testing -from _util import create_app # NOQA - def sink(req, resp, **kw): resp.text = 'sink' diff --git a/tests/test_sinks.py b/tests/test_sinks.py index a1427c41f..ca241151f 100644 --- a/tests/test_sinks.py +++ b/tests/test_sinks.py @@ -1,12 +1,12 @@ import re +from _util import create_app # NOQA +from _util import disable_asgi_non_coroutine_wrapping # NOQA import pytest import falcon import falcon.testing as testing -from _util import create_app, disable_asgi_non_coroutine_wrapping # NOQA - class Proxy: def forward(self, req): diff --git a/tests/test_static.py b/tests/test_static.py index 591276da4..2b9907adb 100644 --- a/tests/test_static.py +++ b/tests/test_static.py @@ -3,15 +3,15 @@ import os import pathlib +import _util # NOQA import pytest import falcon -from falcon.routing import StaticRoute, StaticRouteAsync +from falcon.routing import StaticRoute +from falcon.routing import StaticRouteAsync from falcon.routing.static import _BoundedFile import falcon.testing as testing -import _util # NOQA - @pytest.fixture() def client(asgi): diff --git a/tests/test_testing.py b/tests/test_testing.py index d3cc193b2..0cf4a3d3a 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -1,9 +1,10 @@ +from _util import create_app # NOQA: I100 import pytest import falcon -from falcon import App, status_codes, testing - -from _util import create_app # NOQA: I100 +from falcon import App +from falcon import status_codes +from falcon import testing class CustomCookies: diff --git a/tests/test_uri_converters.py b/tests/test_uri_converters.py index 7efc39fbf..9b75b46a3 100644 --- a/tests/test_uri_converters.py +++ b/tests/test_uri_converters.py @@ -8,7 +8,6 @@ from falcon.routing import converters - _TEST_UUID = uuid.uuid4() _TEST_UUID_STR = str(_TEST_UUID) _TEST_UUID_STR_SANS_HYPHENS = _TEST_UUID_STR.replace('-', '') diff --git a/tests/test_uri_templates.py b/tests/test_uri_templates.py index 448209a5a..3c7805cb7 100644 --- a/tests/test_uri_templates.py +++ b/tests/test_uri_templates.py @@ -9,15 +9,14 @@ import math import uuid +from _util import as_params # NOQA +from _util import create_app # NOQA import pytest import falcon from falcon import testing from falcon.routing.util import SuffixedMethodNotFoundError -from _util import as_params, create_app # NOQA - - _TEST_UUID = uuid.uuid4() _TEST_UUID_2 = uuid.uuid4() _TEST_UUID_STR = str(_TEST_UUID) diff --git a/tests/test_utils.py b/tests/test_utils.py index df5ff2fc4..4d1b51ff6 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,23 +1,31 @@ # -*- coding: utf-8 -*- -from datetime import datetime, timezone +from datetime import datetime +from datetime import timezone import functools import http import itertools import json import random -from urllib.parse import quote, unquote_plus +from urllib.parse import quote +from urllib.parse import unquote_plus +from _util import create_app # NOQA +from _util import to_coroutine # NOQA import pytest import falcon from falcon import media from falcon import testing from falcon import util -from falcon.constants import MEDIA_JSON, MEDIA_MSGPACK, MEDIA_URLENCODED, MEDIA_YAML -from falcon.util import deprecation, misc, structures, uri - -from _util import create_app, to_coroutine # NOQA +from falcon.constants import MEDIA_JSON +from falcon.constants import MEDIA_MSGPACK +from falcon.constants import MEDIA_URLENCODED +from falcon.constants import MEDIA_YAML +from falcon.util import deprecation +from falcon.util import misc +from falcon.util import structures +from falcon.util import uri @pytest.fixture diff --git a/tests/test_validators.py b/tests/test_validators.py index a7f5ed273..6f04dd6a3 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -1,24 +1,17 @@ import typing # NOQA: F401 try: - import jsonschema as _jsonschema # NOQA + import jsonschema except ImportError: - pass + jsonschema = None # type: ignore +from _util import create_app # NOQA +from _util import disable_asgi_non_coroutine_wrapping # NOQA import pytest import falcon from falcon import testing from falcon.media import validators -from _util import create_app, disable_asgi_non_coroutine_wrapping # NOQA - - -# NOTE(kgriffs): Default to None if missing. We do it like this, here, instead -# of in the body of the except statement, above, to avoid flake8 import -# ordering errors. -jsonschema = globals().get('_jsonschema') - - _VALID_MEDIA = {'message': 'something'} _INVALID_MEDIA = {} # type: typing.Dict[str, str] diff --git a/tox.ini b/tox.ini index e6ca31342..20c2feac0 100644 --- a/tox.ini +++ b/tox.ini @@ -264,10 +264,8 @@ commands = {[smoke-test]commands} # -------------------------------------------------------------------- [testenv:pep8] -deps = flake8 - flake8-quotes - flake8-import-order -commands = flake8 [] +deps = ruff +commands = ruff check [] [testenv:ruff] deps = ruff>=0.3.7 @@ -280,29 +278,15 @@ skip_install = True commands = ruff format . [] [testenv:pep8-docstrings] -deps = flake8 - flake8-docstrings -basepython = python3.10 -commands = flake8 \ - --docstring-convention=pep257 \ +deps = ruff +commands = ruff check \ --exclude=.ecosystem,.eggs,.git,.tox,.venv,build,dist,docs,examples,tests,falcon/vendor,falcon/bench/nuts \ --select=D205,D212,D400,D401,D403,D404 \ [] [testenv:pep8-examples] -deps = flake8 - flake8-quotes - flake8-import-order - -basepython = python3.10 - -commands = flake8 examples \ - --max-complexity=12 \ - --ignore=F403,W503,W504 \ - --max-line-length=99 \ - --import-order-style=google \ - --application-import-names=asgilook,look \ - [] +deps = ruff +commands = ruff check examples --line-length=99 [] # -------------------------------------------------------------------- # For viewing environ dicts generated by various WSGI servers