fix(types): clear all 10 pre-existing mypy errors
Master CI lint job runs both ruff and mypy. Previous commit cleaned ruff;
this knocks out the mypy backlog too so the parallel-queue PR can ship
fully green.
- fragments.py: FragmentLibrary defines a `list()` method, which shadows
the builtin in class-scope name resolution and broke `list[str]`
annotations in `resolve()`. Qualify with `builtins.list` (imported
under TYPE_CHECKING since it's static-only).
- remote.py: `result.get("civitai", result)` returns Any to mypy because
dict.get widens. Capture into a typed local first.
- cli.py:
- Drop redundant type re-annotation on `civitai_results` in the
non-remote branch (same name was annotated in the early-return
remote branch above; mypy treats class/module-scope re-annotation
as no-redef even when control flow rules out overlap).
- Guard `p.name is not None` before passing to `get_parameter_source`
(click stubs type Parameter.name as `str | None`).
- Parameterize bare `list | dict` in `_load_json_file_or_inline`.
- Widen `_write_sweep_manifest`'s template_path arg to `Path | None`
(callers already pass None when --list is used without --template);
serialize as empty string in manifest to keep schema stable.
- `# type: ignore[arg-type]` on the deprecated `tsr comfy generate`
delegator that passes a typer function where click.Command is
expected — duck-typed at runtime, only matters for the deprecation
shim.
Tests: 374 still passing. Ruff: clean. Mypy: clean.
This commit is contained in:
+16
-7
@@ -346,7 +346,10 @@ def search(
|
||||
return
|
||||
|
||||
key = api_key or load_api_key()
|
||||
civitai_results: dict[str, Any] | None = None
|
||||
# Reuse the name from the remote-mode branch above (which already returned)
|
||||
# without redeclaring its type — mypy treats class-scope re-annotation as
|
||||
# a no-redef even when control flow guarantees the branches don't overlap.
|
||||
civitai_results = None
|
||||
hf_results: list[dict[str, Any]] | None = None
|
||||
|
||||
# Search CivitAI
|
||||
@@ -946,7 +949,9 @@ def generate( # noqa: PLR0915
|
||||
{
|
||||
p.name
|
||||
for p in click_ctx.command.params
|
||||
if click_ctx.get_parameter_source(p.name) == click.core.ParameterSource.COMMANDLINE
|
||||
# click's Parameter.name is typed `str | None` in stubs but is always
|
||||
# a real string at runtime for any param that's been registered.
|
||||
if p.name is not None and click_ctx.get_parameter_source(p.name) == click.core.ParameterSource.COMMANDLINE
|
||||
}
|
||||
if hasattr(click_ctx, "get_parameter_source")
|
||||
else set()
|
||||
@@ -1709,7 +1714,7 @@ _STYLE_SWEEP_TEMPLATE_KEYS = {
|
||||
}
|
||||
|
||||
|
||||
def _load_json_file_or_inline(value: str | list | dict, *, what: str) -> Any:
|
||||
def _load_json_file_or_inline(value: str | list[Any] | dict[str, Any], *, what: str) -> Any:
|
||||
"""Load JSON from a file path or accept already-parsed inline data.
|
||||
|
||||
`value` may be a path string, a JSON string, or an already-parsed list/dict
|
||||
@@ -2188,14 +2193,16 @@ def style_sweep( # noqa: PLR0915
|
||||
|
||||
def _write_sweep_manifest(
|
||||
out_dir: Path,
|
||||
template_path: Path,
|
||||
template_path: Path | None,
|
||||
styles_origin: str,
|
||||
results: list[dict[str, Any]],
|
||||
) -> Path:
|
||||
"""Write the per-sweep manifest JSON. Returns the path."""
|
||||
manifest_path = out_dir / "_sweep.json"
|
||||
manifest: dict[str, Any] = {
|
||||
"template": str(template_path),
|
||||
# template_path is None when --list is used with only --styles (no template
|
||||
# required). Serialize as empty string to keep manifest schema stable.
|
||||
"template": str(template_path) if template_path is not None else "",
|
||||
"styles_source": styles_origin,
|
||||
"results": results,
|
||||
}
|
||||
@@ -3628,8 +3635,10 @@ def comfy_generate(
|
||||
) -> None:
|
||||
"""[Deprecated] Use 'tsr generate' instead. All features have been merged into the top-level command."""
|
||||
console.print("[yellow]Warning: 'tsr comfy generate' is deprecated. Use 'tsr generate' instead.[/yellow]")
|
||||
# Delegate to the unified generate command via context invocation
|
||||
ctx = typer.Context(generate)
|
||||
# Delegate to the unified generate command via context invocation.
|
||||
# typer.Context expects a click.Command, but passing the typer function directly
|
||||
# works at runtime via duck-typing — keeping it for back-compat with deprecated alias.
|
||||
ctx = typer.Context(generate) # type: ignore[arg-type]
|
||||
generate(
|
||||
ctx=ctx,
|
||||
prompt=prompt,
|
||||
|
||||
+12
-2
@@ -16,9 +16,16 @@ from __future__ import annotations
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path # noqa: TC003 # used in runtime return annotations exposed to typer
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from tensors.config import DATA_DIR
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# Qualified `builtins.list` is referenced in annotations inside FragmentLibrary
|
||||
# because the class defines a method named `list` that shadows the builtin
|
||||
# at class-scope name resolution. Static-only — not needed at runtime.
|
||||
import builtins
|
||||
|
||||
# Restrict fragment names to a safe subset so they can't escape the storage dir
|
||||
# via path traversal and so file listings stay tidy.
|
||||
_NAME_RE = re.compile(r"^[A-Za-z0-9_.-]+$")
|
||||
@@ -132,8 +139,11 @@ class FragmentLibrary:
|
||||
*,
|
||||
name: str | None = None,
|
||||
inline: str | None = None,
|
||||
extra: list[str] | None = None,
|
||||
) -> list[str]:
|
||||
# NOTE: `builtins.list` qualifier needed because this class defines a
|
||||
# `list()` method below, which shadows the builtin in class-scope name
|
||||
# resolution. Affects mypy/pyright even with `from __future__ import annotations`.
|
||||
extra: builtins.list[str] | None = None,
|
||||
) -> builtins.list[str]:
|
||||
"""Merge a named fragment with an inline CSV string and optional extras.
|
||||
|
||||
Resolution order (first match wins per duplicate): named → inline → extra.
|
||||
|
||||
+2
-1
@@ -209,7 +209,8 @@ def remote_search(
|
||||
response.raise_for_status()
|
||||
result: dict[str, Any] = response.json()
|
||||
# The remote API wraps CivitAI results under "civitai" key
|
||||
return result.get("civitai", result)
|
||||
civitai_section: dict[str, Any] = result.get("civitai", result)
|
||||
return civitai_section
|
||||
except httpx.HTTPStatusError as e:
|
||||
if console:
|
||||
console.print(f"[red]Remote API error: {e.response.status_code}[/red]")
|
||||
|
||||
Reference in New Issue
Block a user