mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-20 12:34:17 +02:00
Enable PERF and T20 ruff rules (#3845)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6f045972ab
commit
f248845133
10 changed files with 45 additions and 38 deletions
|
|
@ -180,6 +180,7 @@ error-on-warning = true
|
|||
fixable = ["ALL"]
|
||||
ignore = [
|
||||
"COM812",
|
||||
"PERF203", # try-except in loop — all existing hits are intentional (retry loops, error skipping)
|
||||
"PLR0913", # Too many arguments, MCP Servers have a lot of arguments, OKAY?!
|
||||
"SIM102", # Dont require combining if statements
|
||||
]
|
||||
|
|
@ -194,12 +195,14 @@ extend-select = [
|
|||
"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
|
||||
"PERF", # perflint: Performance anti-patterns (unnecessary copies, allocations)
|
||||
"PIE", # flake8-pie: More idiomatic Python code
|
||||
"PLE", # pylint-error: Catches actual errors (invalid operations, syntax issues)
|
||||
"RSE", # flake8-raise: Unnecessary parentheses on raise
|
||||
"RUF", # Ruff-specific: Modern best practices unique to Ruff
|
||||
"SIM", # flake8-simplify: Simplifies verbose code patterns
|
||||
"SLOT", # flake8-slots: Enforce __slots__ where applicable
|
||||
"T20", # flake8-print: Catch accidental print() in library code
|
||||
"TID", # flake8-tidy-imports: Banned imports and relative import enforcement
|
||||
"UP", # pyupgrade: Modernize syntax for newer Python versions
|
||||
]
|
||||
|
|
@ -211,6 +214,10 @@ known-first-party = ["fastmcp"]
|
|||
"__init__.py" = ["F401", "I001", "RUF013"]
|
||||
# allow imports not at the top of the file
|
||||
"src/fastmcp/__init__.py" = ["E402"]
|
||||
# CLI and example code legitimately uses print() for user-facing output
|
||||
"src/fastmcp/cli/**.py" = ["T20"]
|
||||
"src/fastmcp/client/oauth_callback.py" = ["T20"]
|
||||
"src/fastmcp/contrib/**/example.py" = ["T20"]
|
||||
"!src/**.py" = [ # Only enforce extended ruff rules for code in src/
|
||||
"B", # flake8-bugbear
|
||||
"C4", # flake8-comprehensions
|
||||
|
|
@ -221,12 +228,14 @@ known-first-party = ["fastmcp"]
|
|||
"INP", # flake8-no-pep420
|
||||
"ISC", # flake8-implicit-str-concat
|
||||
"LOG", # flake8-logging
|
||||
"PERF", # perflint
|
||||
"PIE", # flake8-pie
|
||||
"PLE", # pylint-error
|
||||
"RSE", # flake8-raise
|
||||
"RUF", # Ruff-specific
|
||||
"SIM", # flake8-simplify
|
||||
"SLOT", # flake8-slots
|
||||
"T20", # flake8-print
|
||||
"TID", # flake8-tidy-imports
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ def _tool_function_source(tool: mcp.types.Tool) -> str:
|
|||
|
||||
# Build call arguments, using parsed versions for JSON params
|
||||
call_arg_parts = []
|
||||
for prop_name, _ in properties.items():
|
||||
for prop_name in properties:
|
||||
safe_name = _to_python_identifier(prop_name)
|
||||
if any(pn == prop_name for pn, _ in json_params):
|
||||
call_arg_parts.append(f"{prop_name!r}: {safe_name}_parsed")
|
||||
|
|
@ -313,8 +313,7 @@ def generate_cli_script(
|
|||
lines.append("from rich.console import Console")
|
||||
lines.append("")
|
||||
lines.append("from fastmcp import Client")
|
||||
for imp in sorted(extra_imports):
|
||||
lines.append(imp)
|
||||
lines.extend(sorted(extra_imports))
|
||||
lines.append("")
|
||||
|
||||
# --- Transport config ---
|
||||
|
|
@ -506,8 +505,7 @@ def generate_cli_script(
|
|||
"# ---------------------------------------------------------------------------"
|
||||
)
|
||||
|
||||
for tool in tools:
|
||||
lines.append(_tool_function_source(tool))
|
||||
lines.extend(_tool_function_source(tool) for tool in tools)
|
||||
|
||||
# --- Entry point ---
|
||||
lines.append("")
|
||||
|
|
|
|||
|
|
@ -47,8 +47,7 @@ def generate_goose_deeplink(
|
|||
extension_id = _slugify(name)
|
||||
|
||||
params: list[str] = [f"cmd={quote(command, safe='')}"]
|
||||
for arg in args:
|
||||
params.append(f"arg={quote(arg, safe='')}")
|
||||
params.extend(f"arg={quote(arg, safe='')}" for arg in args)
|
||||
params.append(f"id={quote(extension_id, safe='')}")
|
||||
params.append(f"name={quote(name, safe='')}")
|
||||
params.append(f"description={quote(description, safe='')}")
|
||||
|
|
|
|||
|
|
@ -216,12 +216,11 @@ class AnthropicSamplingHandler:
|
|||
# Extract text content from the result
|
||||
result_content: str | list[TextBlockParam] = ""
|
||||
if item.content:
|
||||
text_blocks: list[TextBlockParam] = []
|
||||
for sub_item in item.content:
|
||||
if isinstance(sub_item, TextContent):
|
||||
text_blocks.append(
|
||||
TextBlockParam(type="text", text=sub_item.text)
|
||||
)
|
||||
text_blocks: list[TextBlockParam] = [
|
||||
TextBlockParam(type="text", text=sub_item.text)
|
||||
for sub_item in item.content
|
||||
if isinstance(sub_item, TextContent)
|
||||
]
|
||||
if len(text_blocks) == 1:
|
||||
result_content = text_blocks[0]["text"]
|
||||
elif text_blocks:
|
||||
|
|
@ -270,12 +269,11 @@ class AnthropicSamplingHandler:
|
|||
if isinstance(content, ToolResultContent):
|
||||
result_content_str: str | list[TextBlockParam] = ""
|
||||
if content.content:
|
||||
text_parts: list[TextBlockParam] = []
|
||||
for item in content.content:
|
||||
if isinstance(item, TextContent):
|
||||
text_parts.append(
|
||||
TextBlockParam(type="text", text=item.text)
|
||||
)
|
||||
text_parts: list[TextBlockParam] = [
|
||||
TextBlockParam(type="text", text=item.text)
|
||||
for item in content.content
|
||||
if isinstance(item, TextContent)
|
||||
]
|
||||
if len(text_parts) == 1:
|
||||
result_content_str = text_parts[0]["text"]
|
||||
elif text_parts:
|
||||
|
|
|
|||
|
|
@ -280,9 +280,9 @@ def _convert_messages_to_google_genai_content(
|
|||
|
||||
# Handle list content (tool calls + results)
|
||||
if isinstance(content, list):
|
||||
parts: list[Part] = []
|
||||
for item in content:
|
||||
parts.append(_sampling_content_to_google_genai_part(item))
|
||||
parts: list[Part] = [
|
||||
_sampling_content_to_google_genai_part(item) for item in content
|
||||
]
|
||||
|
||||
if message.role == "user":
|
||||
google_messages.append(UserContent(parts=parts))
|
||||
|
|
|
|||
|
|
@ -231,10 +231,11 @@ class OpenAISamplingHandler:
|
|||
# Collect tool results (added after assistant message)
|
||||
content_text = ""
|
||||
if item.content:
|
||||
result_texts = []
|
||||
for sub_item in item.content:
|
||||
if isinstance(sub_item, TextContent):
|
||||
result_texts.append(sub_item.text)
|
||||
result_texts = [
|
||||
sub_item.text
|
||||
for sub_item in item.content
|
||||
if isinstance(sub_item, TextContent)
|
||||
]
|
||||
content_text = "\n".join(result_texts)
|
||||
tool_messages.append(
|
||||
ChatCompletionToolMessageParam(
|
||||
|
|
|
|||
|
|
@ -173,9 +173,11 @@ def _walk_prefab_tools(server: FastMCP) -> list[Tool]:
|
|||
if isinstance(inner, FastMCPApp):
|
||||
sources.append(inner._local)
|
||||
for src in sources:
|
||||
for component in src._components.values():
|
||||
if isinstance(component, Tool) and _is_prefab_tool(component):
|
||||
results.append(component)
|
||||
results.extend(
|
||||
component
|
||||
for component in src._components.values()
|
||||
if isinstance(component, Tool) and _is_prefab_tool(component)
|
||||
)
|
||||
|
||||
# Recurse into aggregate children
|
||||
from fastmcp.server.providers.aggregate import AggregateProvider
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class PromptsAsTools(Transform):
|
|||
|
||||
result: list[dict[str, Any]] = []
|
||||
for p in prompts:
|
||||
result.append(
|
||||
result.append( # noqa: PERF401
|
||||
{
|
||||
"name": p.name,
|
||||
"description": p.description,
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class ResourcesAsTools(Transform):
|
|||
result: list[dict[str, Any]] = []
|
||||
|
||||
for r in resources:
|
||||
result.append(
|
||||
result.append( # noqa: PERF401
|
||||
{
|
||||
"uri": str(r.uri),
|
||||
"name": r.name,
|
||||
|
|
@ -120,7 +120,7 @@ class ResourcesAsTools(Transform):
|
|||
)
|
||||
|
||||
for t in templates:
|
||||
result.append(
|
||||
result.append( # noqa: PERF401
|
||||
{
|
||||
"uri_template": t.uri_template,
|
||||
"name": t.name,
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ async def inspect_fastmcp_v2(mcp: FastMCP[Any]) -> FastMCPInfo:
|
|||
# Extract detailed prompt information
|
||||
prompt_infos = []
|
||||
for prompt in prompts_list:
|
||||
prompt_infos.append(
|
||||
prompt_infos.append( # noqa: PERF401
|
||||
PromptInfo(
|
||||
key=prompt.key,
|
||||
name=prompt.name or prompt.key,
|
||||
|
|
@ -156,7 +156,7 @@ async def inspect_fastmcp_v2(mcp: FastMCP[Any]) -> FastMCPInfo:
|
|||
# Extract detailed resource information
|
||||
resource_infos = []
|
||||
for resource in resources_list:
|
||||
resource_infos.append(
|
||||
resource_infos.append( # noqa: PERF401
|
||||
ResourceInfo(
|
||||
key=resource.key,
|
||||
uri=str(resource.uri),
|
||||
|
|
@ -178,7 +178,7 @@ async def inspect_fastmcp_v2(mcp: FastMCP[Any]) -> FastMCPInfo:
|
|||
# Extract detailed template information
|
||||
template_infos = []
|
||||
for template in templates_list:
|
||||
template_infos.append(
|
||||
template_infos.append( # noqa: PERF401
|
||||
TemplateInfo(
|
||||
key=template.key,
|
||||
uri_template=template.uri_template,
|
||||
|
|
@ -258,7 +258,7 @@ async def inspect_fastmcp_v1(mcp: FastMCP1x) -> FastMCPInfo:
|
|||
# Extract detailed tool information from MCP Tool objects
|
||||
tool_infos = []
|
||||
for mcp_tool in mcp_tools:
|
||||
tool_infos.append(
|
||||
tool_infos.append( # noqa: PERF401
|
||||
ToolInfo(
|
||||
key=mcp_tool.name,
|
||||
name=mcp_tool.name,
|
||||
|
|
@ -301,7 +301,7 @@ async def inspect_fastmcp_v1(mcp: FastMCP1x) -> FastMCPInfo:
|
|||
# Extract detailed resource information from MCP Resource objects
|
||||
resource_infos = []
|
||||
for mcp_resource in mcp_resources:
|
||||
resource_infos.append(
|
||||
resource_infos.append( # noqa: PERF401
|
||||
ResourceInfo(
|
||||
key=str(mcp_resource.uri),
|
||||
uri=str(mcp_resource.uri),
|
||||
|
|
@ -321,7 +321,7 @@ async def inspect_fastmcp_v1(mcp: FastMCP1x) -> FastMCPInfo:
|
|||
# Extract detailed template information from MCP ResourceTemplate objects
|
||||
template_infos = []
|
||||
for mcp_template in mcp_templates:
|
||||
template_infos.append(
|
||||
template_infos.append( # noqa: PERF401
|
||||
TemplateInfo(
|
||||
key=str(mcp_template.uriTemplate),
|
||||
uri_template=str(mcp_template.uriTemplate),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue