diff --git a/examples/asgilook/asgilook/cache.py b/examples/asgilook/asgilook/cache.py
index e4819d0d0..605331dd9 100644
--- a/examples/asgilook/asgilook/cache.py
+++ b/examples/asgilook/asgilook/cache.py
@@ -1,6 +1,4 @@
import msgpack
-import redis.asyncio as redis
-
class RedisCache:
PREFIX = 'asgilook:'
diff --git a/falcon/app.py b/falcon/app.py
index 434dd6b39..4a8554623 100644
--- a/falcon/app.py
+++ b/falcon/app.py
@@ -63,7 +63,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 +1152,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/asgi/app.py b/falcon/asgi/app.py
index a4e0b9366..ce9984e70 100644
--- a/falcon/asgi/app.py
+++ b/falcon/asgi/app.py
@@ -67,7 +67,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/ws.py b/falcon/asgi/ws.py
index db3700b2d..1a6412437 100644
--- a/falcon/asgi/ws.py
+++ b/falcon/asgi/ws.py
@@ -635,13 +635,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 +683,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/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/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/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/util/structures.py b/falcon/util/structures.py
index f5b4e97c5..6b5ec460a 100644
--- a/falcon/util/structures.py
+++ b/falcon/util/structures.py
@@ -45,8 +45,7 @@
# 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 +120,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/pyproject.toml b/pyproject.toml
index 73fbcea1e..291caf533 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -94,6 +94,42 @@
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]
+ ignore = ["F403"]
+ select = [
+ "C9",
+ "E",
+ "F",
+ "W",
+ ]
+
+[tool.ruff.lint.mccabe]
+ max-complexity = 15
+
+[tool.ruff.lint.per-file-ignores]
+ "**/__init__.py" = [
+ "F401",
+ "E402",
+ ]
+ "falcon/uri.py" = ["F401"]
[tool.pytest.ini_options]
filterwarnings = [
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