diff --git a/docs/index.rst b/docs/index.rst
index 15aab45dd..6827981c5 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -18,6 +18,8 @@ while remaining highly effective.
.. code:: python
+ import falcon
+
class QuoteResource:
def on_get(self, req, resp):
@@ -36,6 +38,8 @@ while remaining highly effective.
app = falcon.App()
app.add_route('/quote', QuoteResource())
+For a fully working example, check out the :ref:`quickstart`.
+
Quick Links
-----------
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 a22214c4d..c3cc23ece 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 249bbbc63..55aeb28a2 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 307e4bb90..561f67037 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 27e369cca..2a4459e43 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