Enable 4 ruff rules (DTZ, ERA, ISC, INP) and fix 9 violations (#3842)

- DTZ: Use timezone-aware datetime.now(timezone.utc)
- ERA: Remove commented-out code, clarify ambiguous comment
- ISC: Convert explicit string concatenation to implicit
- INP: Add missing __init__.py in auth/handlers/

🤖 Generated with Claude Code

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bill Easton 2026-04-12 11:54:52 -05:00 committed by GitHub
commit 73deedf3a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 17 additions and 10 deletions

View file

@ -185,9 +185,13 @@ ignore = [
extend-select = [
"B", # flake8-bugbear: Catches actual bugs like mutable default arguments
"C4", # flake8-comprehensions: More efficient/readable comprehensions
"DTZ", # flake8-datetimez: Enforce timezone-aware datetime usage
"ERA", # eradicate: Detect commented-out code
"FA", # flake8-future-annotations: Enforce from __future__ import annotations
"FLY", # flynt: Static string joins that should be f-strings
"I", # isort: Import sorting
"INP", # flake8-no-pep420: Require __init__.py in namespace packages
"ISC", # flake8-implicit-str-concat: Prevent accidental string concatenation
"LOG", # flake8-logging: Catches logging module misuse
"PIE", # flake8-pie: More idiomatic Python code
"PLE", # pylint-error: Catches actual errors (invalid operations, syntax issues)
@ -209,8 +213,12 @@ known-first-party = ["fastmcp"]
"!src/**.py" = [ # Only enforce extended ruff rules for code in src/
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"ERA", # eradicate
"FA", # flake8-future-annotations
"FLY", # flynt
"INP", # flake8-no-pep420
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"PIE", # flake8-pie
"PLE", # pylint-error

View file

@ -60,7 +60,7 @@ except ImportError as _exc:
) from _exc
import base64
from datetime import datetime
from datetime import datetime, timezone
from typing import Any
from fastmcp.apps.app import FastMCPApp
@ -209,7 +209,7 @@ class FileUpload(FastMCPApp):
"size": f["size"],
"type": f["type"],
"data": f["data"],
"uploaded_at": datetime.now().isoformat(timespec="seconds"),
"uploaded_at": datetime.now(timezone.utc).isoformat(timespec="seconds"),
}
return [_make_summary(e) for e in session_files.values()]

View file

@ -279,8 +279,8 @@ class OAuth(OAuthClientProvider):
warn(
message="Using in-memory token storage -- tokens will be lost when the client restarts. "
+ "For persistent storage across multiple MCP servers, provide an encrypted AsyncKeyValue backend. "
+ "See https://gofastmcp.com/clients/auth/oauth#token-storage for details.",
"For persistent storage across multiple MCP servers, provide an encrypted AsyncKeyValue backend. "
"See https://gofastmcp.com/clients/auth/oauth#token-storage for details.",
stacklevel=2,
)

View file

@ -376,7 +376,7 @@ class OAuthProxy(OAuthProvider, ConsentMixin):
):
logger.warning(
"allowed_client_redirect_uris is empty list; no redirect URIs will be accepted. "
+ "This will block all OAuth clients."
"This will block all OAuth clients."
)
self._allowed_client_redirect_uris: list[str] | None = (
allowed_client_redirect_uris
@ -402,7 +402,7 @@ class OAuthProxy(OAuthProvider, ConsentMixin):
elif not require_authorization_consent:
logger.warning(
"Authorization consent screen disabled - only use for local development or testing. "
+ "In production, this screen protects against confused deputy attacks."
"In production, this screen protects against confused deputy attacks."
)
# Extra parameters for authorization and token endpoints
@ -429,7 +429,7 @@ class OAuthProxy(OAuthProvider, ConsentMixin):
if len(jwt_signing_key) < 12:
logger.warning(
"jwt_signing_key is less than 12 characters; it is recommended to use a longer. "
+ "string for the key derivation."
"string for the key derivation."
)
jwt_signing_key = derive_jwt_key(
low_entropy_material=jwt_signing_key,

View file

@ -767,7 +767,7 @@ def get_http_headers(
}
if include:
exclude_headers -= {h.lower() for h in include}
# (just in case)
# Sanity check: all entries must already be lowercase
if not all(h.lower() == h for h in exclude_headers):
raise ValueError("Excluded headers must be lowercase")
headers: dict[str, str] = {}

View file

@ -262,7 +262,7 @@ def _lifespan_proxy(
if not fastmcp_server._lifespan_result_set:
raise RuntimeError(
"FastMCP server has a lifespan defined but no lifespan result is set, which means the server's context manager was not entered. "
+ " Are you running the server in a way that supports lifespans? If so, please file an issue at https://github.com/PrefectHQ/fastmcp/issues."
" Are you running the server in a way that supports lifespans? If so, please file an issue at https://github.com/PrefectHQ/fastmcp/issues."
)
yield fastmcp_server._lifespan_result # ty:ignore[invalid-yield]

View file

@ -240,7 +240,6 @@ def log_server_banner(server: FastMCP[Any]) -> None:
panel_content,
border_style="dim",
padding=(1, 4),
# expand=False,
width=80, # Set max width for the panel
)