Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ async def run_with_resilience(
endpoint_key: str,
operation: Callable[_P, Awaitable[_T]],
*args: _P.args,
max_attempts: int,
max_attempts: int, # ty: ignore[invalid-paramspec]
deadline_at: float | None = None,
**kwargs: _P.kwargs,
) -> _T:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async def run_with_resilience(
endpoint_key: str,
operation: Callable[_P, Awaitable[_T]],
*args: _P.args,
max_attempts: int,
max_attempts: int, # ty: ignore[invalid-paramspec]
deadline_at: float | None,
**kwargs: _P.kwargs,
) -> _T:
Expand Down Expand Up @@ -202,7 +202,7 @@ async def _run_once(
endpoint_key: str,
operation: Callable[_P, Awaitable[_T]],
*args: _P.args,
attempt: int,
attempt: int, # ty: ignore[invalid-paramspec]
**kwargs: _P.kwargs,
) -> _T:
controller = await self._get_controller(endpoint_key)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ async def test_rubric_compute_scores_emits_numeric_score_and_label(self, mocker:

def test_unique_scores_allows_empty_scores_for_constructed_model(self):
metric = LLMJudgeMetric.model_construct(model=_make_model(), scores=[], _fields_set={"model", "scores"})
assert metric.unique_scores() is metric # type: ignore[call-non-callable] # Pydantic model_validator descriptor
assert metric.unique_scores() is metric # ty: ignore[call-non-callable] # Pydantic model_validator descriptor

def test_string_prompt_template_bypasses_reserved_key_validation(self):
metric = LLMJudgeMetric(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def test_api_key_none_when_no_secret(self):

def test_extra_fields_forbidden(self):
with pytest.raises(ValueError):
Agent(url="http://agent.test", name="test", format=AgentFormat.NEMO_AGENT_TOOLKIT, extra_field="bad") # type: ignore[call-arg]
Agent(url="http://agent.test", name="test", format=AgentFormat.NEMO_AGENT_TOOLKIT, extra_field="bad") # ty: ignore[unknown-argument]

def test_generic_with_trajectory_path(self):
agent = Agent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def _extract_default(info: FieldInfo) -> Any:
return info.default
if info.default_factory is not None:
try:
return info.default_factory() # type: ignore[call-arg]
return info.default_factory() # ty: ignore[missing-argument]
except TypeError:
# Pydantic supports validated_data-aware factories; we can't
# safely call those at CLI-build time. Treat as required so
Expand Down Expand Up @@ -451,7 +451,7 @@ def _optional_of(tp: object) -> Any:
runtime value. Delegating to ``__getitem__`` here keeps the annotation
correct without tripping static type checkers.
"""
return Optional[tp] # type: ignore[valid-type]
return Optional[tp] # ty: ignore[invalid-type-form]


def make_field_param(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ class NemoFunction(_NamedPlugin, Generic[SpecT]):
# ``spec_schema`` to ``type[GreetSpec]`` for type-checkers and IDEs.
# PEP 526 forbids type variables inside ``ClassVar``, so the suppression
# here is the standard escape hatch for the otherwise-correct shape.
spec_schema: ClassVar[type[SpecT]] # type: ignore[misc]
spec_schema: ClassVar[type[SpecT]] # ty: ignore[invalid-type-form]

# ------------------------------------------------------------------ #
# Endpoint override #
Expand Down
2 changes: 1 addition & 1 deletion packages/nemo_platform_plugin/tests/test_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def test_returns_1_for_none_return(self, monkeypatch, tmp_path: Path) -> None:
class _Job(NemoJob):
name = "forgot-return"

def run(self, config: dict) -> dict: # type: ignore[return]
def run(self, config: dict) -> dict: # ty: ignore[empty-body]
# Intentionally no return — most plausible failure mode.
pass

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_with_request_id() -> None:
def test_kw_only_construction() -> None:
"""Workspace must be passed by keyword — the dataclass is ``kw_only``."""
with pytest.raises(TypeError):
FunctionContext("default") # type: ignore[misc] — intentional misuse
FunctionContext("default") # ty: ignore[missing-argument,too-many-positional-arguments] — intentional misuse


def test_field_set_is_minimal() -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ def test_config_id_reference(self):

def test_config_type_required(self):
with pytest.raises(ValidationError):
MiddlewareCall(name="nemo-switchyard") # type: ignore[call-arg]
MiddlewareCall(name="nemo-switchyard") # ty: ignore[missing-argument]


# ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion packages/nemo_platform_plugin/tests/test_job_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ def test_results_is_required(self, tmp_path: Path) -> None:
# Omitting ``results`` raises at construction; the dataclass
# enforces it (no silent ``None`` handed to the job).
with pytest.raises(TypeError, match="results"):
JobContext(workspace="ws", storage=_make_storage(tmp_path)) # type: ignore[call-arg]
JobContext(workspace="ws", storage=_make_storage(tmp_path)) # ty: ignore[missing-argument]
6 changes: 3 additions & 3 deletions packages/nmp_testing/src/nmp/testing/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,9 +545,9 @@ async def _run() -> None:
if client_type is TestClient:
yield client
elif client_type is AsyncNeMoPlatform:
yield async_sdk
yield async_sdk # ty: ignore[invalid-yield]
elif client_type is EntityClient:
yield entity_client
yield entity_client # ty: ignore[invalid-yield]
elif client_type is ClientContext:
yield ClientContext(
sdk=sdk,
Expand All @@ -557,6 +557,6 @@ async def _run() -> None:
access_log=access_log_instance,
)
else:
yield sdk
yield sdk # ty: ignore[invalid-yield]

app.dependency_overrides.clear()
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def docker_build(
typer.Exit: On build failure.
"""
try:
from python_on_whales import docker # type: ignore[unresolved-import]
from python_on_whales import docker # ty: ignore[unresolved-import]
except ImportError:
typer.echo(
"Error: 'python-on-whales' is required for building images. "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def _load_pyproject(pyproject: Path | None) -> dict:
try:
import tomllib
except ModuleNotFoundError:
import tomli as tomllib # type: ignore[no-redef]
import tomli as tomllib # ty: ignore[unresolved-import]
# Only swallow the *parse* failure: a malformed ``pyproject.toml`` should
# not stop a build that is otherwise valid (we fall back to filename-based
# name resolution, env-var version, etc.). ``OSError`` (permission /
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def docker_push(
typer.Exit: On tag or push failure.
"""
try:
from python_on_whales import docker # type: ignore[unresolved-import]
from python_on_whales import docker # ty: ignore[unresolved-import]
except ImportError:
typer.echo(
"Error: 'python-on-whales' is required for publishing images. "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import threading
from contextlib import contextmanager
from functools import wraps
from typing import Generator
from typing import Generator, TypeVar

_LOGGER_NAME = "nemo_platform.anonymizer"
_HANDLER_MARKER = "_nemo_anonymizer_sdk_handler"
Expand Down Expand Up @@ -68,7 +68,10 @@ def _ensure_logging_handler() -> Generator[None, None, None]:
_saved_propagate = None


def with_logging(cls: type) -> type:
_ClsT = TypeVar("_ClsT", bound=type)


def with_logging(cls: _ClsT) -> _ClsT:
"""Wrap public methods so SDK logging is configured on demand."""
for name, method in vars(cls).items():
if name.startswith("_") or isinstance(method, (staticmethod, classmethod)):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _render_to_terminal(
if analysis is not None and hasattr(analysis, "to_report"):
try:
console.print()
analysis.to_report() # type: ignore[attr-defined]
analysis.to_report() # ty: ignore[call-non-callable]
except Exception as exc: # pragma: no cover - defensive
console.print(f"[yellow]Could not render analysis report: {exc}[/yellow]")

Expand Down Expand Up @@ -202,7 +202,7 @@ def _save_results(
analysis = self._analysis
if analysis is not None and hasattr(analysis, "to_report"):
try:
analysis.to_report(save_path=results_dir / "report.html") # type: ignore[attr-defined]
analysis.to_report(save_path=results_dir / "report.html") # ty: ignore[call-non-callable]
except Exception as exc: # pragma: no cover - defensive
console.print(f"[yellow]Could not save analysis report: {exc}[/yellow]")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import logging
from contextlib import contextmanager
from functools import wraps
from typing import Generator
from typing import Generator, TypeVar

from data_designer.logging import _make_stream_formatter

Expand Down Expand Up @@ -34,7 +34,10 @@ def _ensure_logging_handler() -> Generator[None, None, None]:
dd_logger.removeHandler(handler)


def with_logging(cls: type) -> type:
_ClsT = TypeVar("_ClsT", bound=type)
Comment thread
matthewgrossman marked this conversation as resolved.
Resolved


def with_logging(cls: _ClsT) -> _ClsT:
"""Wrap public methods so SDK logging is configured on demand.

This ensures logging is configured for every public method call without
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def _never_config() -> DeploymentConfig:
return DeploymentConfig(
name="echo-cfg",
workspace="itest",
restart_policy="Never",
restart_policy="Never", # ty: ignore[unknown-argument]
containers=[Container(name="main", image="alpine:3.20", command=["echo"], args=["hello"])],
)

Expand All @@ -57,7 +57,7 @@ def _always_http_config() -> DeploymentConfig:
return DeploymentConfig(
name="http-cfg",
workspace="itest",
restart_policy="Always",
restart_policy="Always", # ty: ignore[unknown-argument]
containers=[
Container(
name="main",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ async def test_puller_server_prerequisite_chain(docker_registry: ExecutorRegistr
puller_cfg = DeploymentConfig(
name="puller-cfg",
workspace="itest",
restart_policy="OnFailure",
restart_policy="OnFailure", # ty: ignore[unknown-argument]
containers=[
Container(
name="puller",
Expand All @@ -98,14 +98,14 @@ async def test_puller_server_prerequisite_chain(docker_registry: ExecutorRegistr
server_cfg = DeploymentConfig(
name="server-cfg",
workspace="itest",
restart_policy="Always",
restart_policy="Always", # ty: ignore[unknown-argument]
containers=[
Container(
name="server",
image="alpine:3.20",
command=["sleep"],
args=["3600"],
volumeMounts=[VolumeMount(name="weights", mountPath="/data", read_only=True)],
volumeMounts=[VolumeMount(name="weights", mountPath="/data", read_only=True)], # ty: ignore[unknown-argument]
)
],
volumeMounts=[VolumeMount(name="weights", mountPath="/data")],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def sample_config(*, restart_policy: RestartPolicy = "Always") -> DeploymentConf
args=["hello"],
)
],
restart_policy=restart_policy,
restart_policy=restart_policy, # ty: ignore[unknown-argument]
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@pytest.mark.asyncio
async def test_http_probe_without_host_url_not_ready() -> None:
container = MagicMock()
probe = Probe(http_get=HTTPGetAction(path="/health", port=8080))
probe = Probe(http_get=HTTPGetAction(path="/health", port=8080)) # ty: ignore[unknown-argument]

ready, reason = await check_readiness_probe(
container=container,
Expand All @@ -30,7 +30,7 @@ async def test_http_probe_without_host_url_not_ready() -> None:
@pytest.mark.asyncio
async def test_tcp_probe_without_host_url_not_ready() -> None:
container = MagicMock()
probe = Probe(tcp_socket=TCPSocketAction(port=8080))
probe = Probe(tcp_socket=TCPSocketAction(port=8080)) # ty: ignore[unknown-argument]

ready, reason = await check_readiness_probe(
container=container,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ dev = [
"notebook>=7.5.6",
"aiohttp>=3.13.4",
"ipykernel>=6.29.5",
"ty==0.0.17",
"ty==0.0.56",
"hatchling>=1.26.3",
"nmp-testing",
"mlflow-skinny>=3.11.1,<3.12.0", # Optional dep for fine-tuning (shipped in training images); skinny variant to test API surface without bloating uv.lock
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions services/studio/src/nmp/studio/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Mapping
from html import escape
from pathlib import Path
from typing import List
from typing import ClassVar, List

from fastapi import FastAPI, Request, status
from fastapi.responses import HTMLResponse
Expand Down Expand Up @@ -51,7 +51,7 @@ class StudioService(Service[StudioConfig]):
- env_replacements: Runtime values to inject into the UI bundle (cached)
"""

dependencies: list[str] = []
dependencies: ClassVar[list[str]] = []

def __init__(self):
"""Initialize the studio service."""
Expand Down
20 changes: 10 additions & 10 deletions tools/lint/lint-python-types.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ set -euo pipefail
# Generate error reports by running `make reports` in script/ty_issues_report.
# Counts reflect the violation count at the time of suppression.
ci_ignored_rules=(
invalid-argument-type # 148
unused-ignore-comment # 14
unresolved-attribute # 141
not-subscriptable # 19
invalid-assignment # 9
invalid-return-type # 11
invalid-method-override # 4
no-matching-overload # 9
unsupported-operator # 6
invalid-argument-type # 204
unused-ignore-comment # 14
unresolved-attribute # 72
not-subscriptable # 31
invalid-assignment # 30
invalid-return-type # 18
invalid-method-override # 18
no-matching-overload # 2
unsupported-operator # 2
)

ignore_args=()
for rule in "${ci_ignored_rules[@]}"; do
ignore_args+=(--ignore "$rule")
done

uv run --frozen ty check "${ignore_args[@]}"
uv run --frozen ty check --exit-zero-on-warning "${ignore_args[@]}"
2 changes: 1 addition & 1 deletion tools/mcp-dev-tools/nmp_dev_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from pathlib import Path
from typing import Any

from fastmcp import FastMCP
from fastmcp import FastMCP # ty: ignore[unresolved-import]

# Configure logging
logging.basicConfig(
Expand Down
Loading