From f22af6248c93df08b553e9a264f6367797e0fddb Mon Sep 17 00:00:00 2001 From: Elior Nataf Lackritz Date: Thu, 6 Aug 2026 17:38:31 -0400 Subject: [PATCH] chore: enable RUF100 and clear unused noqa directives (#8546) Follow-up to review on #8540, where a stale `# noqa: E402` slipped past me and Sydney spotted it by eye. This turns on the rule that catches that automatically. `RUF100` flags a `noqa` that suppresses nothing. `sdk-py` already had it through its blanket `RUF` selection; this adds it to the other seven packages and clears what it finds. ### The 33 it flags, all autofixed **Blanket `# noqa` on docstring-closing lines** (4, in `checkpoint-postgres` and `checkpoint-sqlite`). `E501` is in `lint.ignore` for those packages, so nothing was being suppressed: ```diff - """ # noqa + """ ``` **`# noqa: F821` on `anext(aiter_)`** (2). Left over from Python 3.9 support. `anext` became a builtin in 3.10, which is the floor now, so `F821` no longer fires: ```diff - anext(aiter_), # type: ignore[arg-type] # noqa: F821 + anext(aiter_), # type: ignore[arg-type] ``` **Suppressions naming rules the package does not enable** (27), across `langgraph`, `prebuilt` and `checkpoint-sqlite`: `FBT001`, `FBT002`, `TC002`, `BLE001`, `ANN001`, `ANN002`, `ANN003`, `E501`, `F401`. Mostly copied between packages whose rule sets differ. ### One measurement note If you check these numbers yourself, use `--extend-select`: ``` ruff check --select RUF100 . # 81, misleading ruff check --extend-select RUF100 . # 33, real ``` With a bare `--select`, ruff treats every other rule as disabled, so every suppression for another rule looks unused. I quoted 81 before catching that. ### Verified `checkpoint-sqlite` 118 passed, `prebuilt` 284 passed, `langgraph` 1968 passed, `checkpoint-postgres` 264 passed on PG 15 and 16. `make lint` clean in every package. Independent of #8540 and #8537, so it can land in any order. --- libs/checkpoint-conformance/pyproject.toml | 1 + .../langgraph/checkpoint/postgres/__init__.py | 2 +- .../langgraph/checkpoint/postgres/aio.py | 2 +- .../langgraph/checkpoint/postgres/shallow.py | 4 ++-- libs/checkpoint-postgres/pyproject.toml | 1 + .../langgraph/checkpoint/sqlite/__init__.py | 4 ++-- .../langgraph/checkpoint/sqlite/aio.py | 2 +- libs/checkpoint-sqlite/pyproject.toml | 1 + .../tests/test_conformance_delta.py | 6 +++--- .../tests/test_delta_channel_migration.py | 12 ++++++------ .../tests/test_get_delta_channel_history.py | 12 ++++++------ libs/checkpoint/pyproject.toml | 1 + libs/cli/pyproject.toml | 1 + libs/langgraph/langgraph/_internal/_pydantic.py | 4 ++-- libs/langgraph/langgraph/_internal/_serde.py | 2 +- libs/langgraph/langgraph/errors.py | 2 +- libs/langgraph/langgraph/graph/state.py | 2 +- libs/langgraph/pyproject.toml | 2 +- libs/langgraph/tests/test_config_async.py | 8 ++++---- libs/prebuilt/langgraph/prebuilt/tool_node.py | 8 ++++---- libs/prebuilt/pyproject.toml | 2 +- libs/prebuilt/tests/test_on_tool_call.py | 2 +- 22 files changed, 43 insertions(+), 38 deletions(-) diff --git a/libs/checkpoint-conformance/pyproject.toml b/libs/checkpoint-conformance/pyproject.toml index 2d9a0701f..1a57cec5b 100644 --- a/libs/checkpoint-conformance/pyproject.toml +++ b/libs/checkpoint-conformance/pyproject.toml @@ -58,6 +58,7 @@ lint.select = [ "UP", # pyupgrade "B", # flake8-bugbear "I", # isort + "RUF100", # unused noqa directive ] lint.ignore = ["E501", "B008"] target-version = "py310" diff --git a/libs/checkpoint-postgres/langgraph/checkpoint/postgres/__init__.py b/libs/checkpoint-postgres/langgraph/checkpoint/postgres/__init__.py index 18186d89b..d519fa772 100644 --- a/libs/checkpoint-postgres/langgraph/checkpoint/postgres/__init__.py +++ b/libs/checkpoint-postgres/langgraph/checkpoint/postgres/__init__.py @@ -223,7 +223,7 @@ class PostgresSaver(BasePostgresSaver): >>> checkpoint_tuple = memory.get_tuple(config) >>> print(checkpoint_tuple) CheckpointTuple(...) - """ # noqa + """ thread_id = config["configurable"]["thread_id"] checkpoint_id = get_checkpoint_id(config) checkpoint_ns = config["configurable"].get("checkpoint_ns", "") diff --git a/libs/checkpoint-postgres/langgraph/checkpoint/postgres/aio.py b/libs/checkpoint-postgres/langgraph/checkpoint/postgres/aio.py index 09fb964d5..b02e0b164 100644 --- a/libs/checkpoint-postgres/langgraph/checkpoint/postgres/aio.py +++ b/libs/checkpoint-postgres/langgraph/checkpoint/postgres/aio.py @@ -573,7 +573,7 @@ class AsyncPostgresSaver(BasePostgresSaver): while True: try: yield asyncio.run_coroutine_threadsafe( - anext(aiter_), # type: ignore[arg-type] # noqa: F821 + anext(aiter_), # type: ignore[arg-type] self.loop, ).result() except StopAsyncIteration: diff --git a/libs/checkpoint-postgres/langgraph/checkpoint/postgres/shallow.py b/libs/checkpoint-postgres/langgraph/checkpoint/postgres/shallow.py index 90fc95e74..350b20bb5 100644 --- a/libs/checkpoint-postgres/langgraph/checkpoint/postgres/shallow.py +++ b/libs/checkpoint-postgres/langgraph/checkpoint/postgres/shallow.py @@ -334,7 +334,7 @@ class ShallowPostgresSaver(BasePostgresSaver): >>> checkpoint_tuple = memory.get_tuple(config) >>> print(checkpoint_tuple) CheckpointTuple(...) - """ # noqa + """ thread_id = config["configurable"]["thread_id"] checkpoint_ns = config["configurable"].get("checkpoint_ns", "") args = (thread_id, checkpoint_ns) @@ -885,7 +885,7 @@ class AsyncShallowPostgresSaver(BasePostgresSaver): while True: try: yield asyncio.run_coroutine_threadsafe( - anext(aiter_), # type: ignore[arg-type] # noqa: F821 + anext(aiter_), # type: ignore[arg-type] self.loop, ).result() except StopAsyncIteration: diff --git a/libs/checkpoint-postgres/pyproject.toml b/libs/checkpoint-postgres/pyproject.toml index 864ba2c00..964882621 100644 --- a/libs/checkpoint-postgres/pyproject.toml +++ b/libs/checkpoint-postgres/pyproject.toml @@ -65,6 +65,7 @@ lint.select = [ "B", # flake8-bugbear "I", # isort "PLC0415", # import-outside-top-level + "RUF100", # unused noqa directive "UP", # pyupgrade ] lint.ignore = ["E501", "B008"] diff --git a/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/__init__.py b/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/__init__.py index 6ca2448d0..3259ff150 100644 --- a/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/__init__.py +++ b/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/__init__.py @@ -77,7 +77,7 @@ class SqliteSaver(BaseCheckpointSaver[str]): >>> result = graph.invoke(3, config) >>> graph.get_state(config) StateSnapshot(values=4, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '0c62ca34-ac19-445d-bbb0-5b4984975b2a'}}, parent_config=None) - """ # noqa + """ conn: sqlite3.Connection is_setup: bool @@ -222,7 +222,7 @@ class SqliteSaver(BaseCheckpointSaver[str]): >>> checkpoint_tuple = memory.get_tuple(config) >>> print(checkpoint_tuple) CheckpointTuple(...) - """ # noqa + """ checkpoint_ns = config["configurable"].get("checkpoint_ns", "") with self.cursor(transaction=False) as cur: # find the latest checkpoint for the thread_id diff --git a/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/aio.py b/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/aio.py index 368428c68..1ad0777c1 100644 --- a/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/aio.py +++ b/libs/checkpoint-sqlite/langgraph/checkpoint/sqlite/aio.py @@ -212,7 +212,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]): while True: try: yield asyncio.run_coroutine_threadsafe( - anext(aiter_), # type: ignore[arg-type] # noqa: F821 + anext(aiter_), # type: ignore[arg-type] self.loop, ).result() except StopAsyncIteration: diff --git a/libs/checkpoint-sqlite/pyproject.toml b/libs/checkpoint-sqlite/pyproject.toml index a9d6c945f..cd3d5ac26 100644 --- a/libs/checkpoint-sqlite/pyproject.toml +++ b/libs/checkpoint-sqlite/pyproject.toml @@ -63,6 +63,7 @@ lint.select = [ "B", # flake8-bugbear "I", # isort "PLC0415", # import-outside-top-level + "RUF100", # unused noqa directive "UP", # pyupgrade ] lint.ignore = ["E501", "B008"] diff --git a/libs/checkpoint-sqlite/tests/test_conformance_delta.py b/libs/checkpoint-sqlite/tests/test_conformance_delta.py index d900855d1..6171e7440 100644 --- a/libs/checkpoint-sqlite/tests/test_conformance_delta.py +++ b/libs/checkpoint-sqlite/tests/test_conformance_delta.py @@ -10,10 +10,10 @@ pytest.importorskip( ) pytest.importorskip("aiosqlite", reason="aiosqlite not installed") -from langgraph.checkpoint.conformance import validate # noqa: E402 -from langgraph.checkpoint.conformance.initializer import checkpointer_test # noqa: E402 +from langgraph.checkpoint.conformance import validate +from langgraph.checkpoint.conformance.initializer import checkpointer_test -from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver # noqa: E402 +from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver @pytest.mark.asyncio diff --git a/libs/checkpoint-sqlite/tests/test_delta_channel_migration.py b/libs/checkpoint-sqlite/tests/test_delta_channel_migration.py index c71f3b12c..f9f511c1e 100644 --- a/libs/checkpoint-sqlite/tests/test_delta_channel_migration.py +++ b/libs/checkpoint-sqlite/tests/test_delta_channel_migration.py @@ -29,13 +29,13 @@ pytest.importorskip("langgraph.channels.delta", reason="langgraph core not insta pytest.importorskip("langgraph.channels.binop", reason="langgraph core not installed") pytest.importorskip("langgraph.graph", reason="langgraph core not installed") -from langgraph.channels.binop import BinaryOperatorAggregate # type: ignore[import-untyped] # noqa: E402,I001 -from langgraph.channels.delta import DeltaChannel # type: ignore[import-untyped] # noqa: E402 -from langgraph.graph import END, START, StateGraph # type: ignore[import-untyped] # noqa: E402 -from typing_extensions import TypedDict # noqa: E402 +from langgraph.channels.binop import BinaryOperatorAggregate # type: ignore[import-untyped] # noqa: I001 +from langgraph.channels.delta import DeltaChannel # type: ignore[import-untyped] +from langgraph.graph import END, START, StateGraph # type: ignore[import-untyped] +from typing_extensions import TypedDict -from langgraph.checkpoint.sqlite import SqliteSaver # noqa: E402 -from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver # noqa: E402 +from langgraph.checkpoint.sqlite import SqliteSaver +from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver pytestmark = pytest.mark.anyio diff --git a/libs/checkpoint-sqlite/tests/test_get_delta_channel_history.py b/libs/checkpoint-sqlite/tests/test_get_delta_channel_history.py index 8e19c8b85..20c694223 100644 --- a/libs/checkpoint-sqlite/tests/test_get_delta_channel_history.py +++ b/libs/checkpoint-sqlite/tests/test_get_delta_channel_history.py @@ -32,13 +32,13 @@ from langchain_core.runnables import RunnableConfig pytest.importorskip("langgraph.channels.delta", reason="langgraph core not installed") pytest.importorskip("langgraph.graph", reason="langgraph core not installed") -from langgraph.channels.delta import DeltaChannel # type: ignore[import-untyped] # noqa: E402,I001 -from langgraph.checkpoint.serde.types import _DeltaSnapshot # noqa: E402 -from langgraph.graph import END, START, StateGraph # type: ignore[import-untyped] # noqa: E402 -from typing_extensions import TypedDict # noqa: E402 +from langgraph.channels.delta import DeltaChannel # type: ignore[import-untyped] # noqa: I001 +from langgraph.checkpoint.serde.types import _DeltaSnapshot +from langgraph.graph import END, START, StateGraph # type: ignore[import-untyped] +from typing_extensions import TypedDict -from langgraph.checkpoint.sqlite import SqliteSaver # noqa: E402 -from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver # noqa: E402 +from langgraph.checkpoint.sqlite import SqliteSaver +from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver pytestmark = pytest.mark.anyio diff --git a/libs/checkpoint/pyproject.toml b/libs/checkpoint/pyproject.toml index 8e03c391c..7ce16fbdc 100644 --- a/libs/checkpoint/pyproject.toml +++ b/libs/checkpoint/pyproject.toml @@ -59,6 +59,7 @@ lint.select = [ "UP", # pyupgrade "B", # flake8-bugbear "I", # isort + "RUF100", # unused noqa directive "UP", # pyupgrade ] lint.ignore = ["E501", "B008"] diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml index 7012daa22..6a2cd94fa 100644 --- a/libs/cli/pyproject.toml +++ b/libs/cli/pyproject.toml @@ -72,6 +72,7 @@ lint.select = [ "UP", # pyupgrade "B", # flake8-bugbear "I", # isort + "RUF100", # unused noqa directive "UP", # pyupgrade ] lint.ignore = ["E501", "B008"] diff --git a/libs/langgraph/langgraph/_internal/_pydantic.py b/libs/langgraph/langgraph/_internal/_pydantic.py index 0d93f085e..33319d0ee 100644 --- a/libs/langgraph/langgraph/_internal/_pydantic.py +++ b/libs/langgraph/langgraph/_internal/_pydantic.py @@ -68,7 +68,7 @@ def _create_root_model( def schema( cls: type[BaseModel], - by_alias: bool = True, # noqa: FBT001,FBT002 + by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE, ) -> dict[str, Any]: # Complains about schema not being defined in superclass @@ -80,7 +80,7 @@ def _create_root_model( def model_json_schema( cls: type[BaseModel], - by_alias: bool = True, # noqa: FBT001,FBT002 + by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE, schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, mode: JsonSchemaMode = "validation", diff --git a/libs/langgraph/langgraph/_internal/_serde.py b/libs/langgraph/langgraph/_internal/_serde.py index 775242a87..933f76ec5 100644 --- a/libs/langgraph/langgraph/_internal/_serde.py +++ b/libs/langgraph/langgraph/_internal/_serde.py @@ -22,7 +22,7 @@ from pydantic import BaseModel from typing_extensions import NotRequired, Required, is_typeddict try: - from langgraph.checkpoint.serde._msgpack import ( # noqa: F401 + from langgraph.checkpoint.serde._msgpack import ( STRICT_MSGPACK_ENABLED, ) except ImportError: diff --git a/libs/langgraph/langgraph/errors.py b/libs/langgraph/langgraph/errors.py index 47d30de08..65b57d61e 100644 --- a/libs/langgraph/langgraph/errors.py +++ b/libs/langgraph/langgraph/errors.py @@ -7,7 +7,7 @@ from typing import Any, Literal from warnings import warn # EmptyChannelError is re-exported from langgraph.channels.base -from langgraph.checkpoint.base import EmptyChannelError # noqa: F401 +from langgraph.checkpoint.base import EmptyChannelError from typing_extensions import deprecated from langgraph.types import Command, Interrupt diff --git a/libs/langgraph/langgraph/graph/state.py b/libs/langgraph/langgraph/graph/state.py index deb0e9e94..ca9c5be9e 100644 --- a/libs/langgraph/langgraph/graph/state.py +++ b/libs/langgraph/langgraph/graph/state.py @@ -995,7 +995,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]): Without type hints on the `path` function's return value (e.g., `-> Literal["foo", "__end__"]:`) or a path_map, the graph visualization assumes the edge could transition to any node in the graph. - """ # noqa: E501 + """ if self.compiled: logger.warning( "Adding an edge to a graph that has already been compiled. This will " diff --git a/libs/langgraph/pyproject.toml b/libs/langgraph/pyproject.toml index fba4ddeed..b579c7ebd 100644 --- a/libs/langgraph/pyproject.toml +++ b/libs/langgraph/pyproject.toml @@ -89,7 +89,7 @@ langgraph-sdk = { path = "../sdk-py", editable = true } langgraph-cli = { path = "../cli", editable = true } [tool.ruff] -lint.select = [ "E", "F", "I", "TID251", "UP" ] +lint.select = [ "E", "F", "I", "RUF100", "TID251", "UP" ] lint.ignore = [ "E501" ] line-length = 88 indent-width = 4 diff --git a/libs/langgraph/tests/test_config_async.py b/libs/langgraph/tests/test_config_async.py index 6ad51c5b2..13f922534 100644 --- a/libs/langgraph/tests/test_config_async.py +++ b/libs/langgraph/tests/test_config_async.py @@ -24,7 +24,7 @@ class _TrackingCallback(BaseCallbackHandler): def __init__(self) -> None: self.called = False - def on_chain_start(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003 + def on_chain_start(self, *args, **kwargs) -> None: self.called = True @@ -55,7 +55,7 @@ async def test_with_config_configurable_preserved_on_invoke() -> None: builder = StateGraph(dict) captured: dict = {} - def node(state, config): # noqa: ANN001 + def node(state, config): captured.update(config.get("configurable") or {}) return state @@ -79,7 +79,7 @@ async def test_with_config_metadata_preserved_on_invoke() -> None: builder = StateGraph(dict) captured: dict = {} - def node(state, config): # noqa: ANN001 + def node(state, config): captured.update(config.get("metadata") or {}) return state @@ -104,7 +104,7 @@ async def test_with_config_tags_preserved_on_invoke() -> None: builder = StateGraph(dict) captured: list = [] - def node(state, config): # noqa: ANN001 + def node(state, config): captured.extend(config.get("tags") or []) return state diff --git a/libs/prebuilt/langgraph/prebuilt/tool_node.py b/libs/prebuilt/langgraph/prebuilt/tool_node.py index 25d2425f9..95e161b90 100644 --- a/libs/prebuilt/langgraph/prebuilt/tool_node.py +++ b/libs/prebuilt/langgraph/prebuilt/tool_node.py @@ -87,8 +87,8 @@ from langgraph._internal._runnable import RunnableCallable from langgraph.errors import GraphBubbleUp from langgraph.graph.message import REMOVE_ALL_MESSAGES from langgraph.pregel._tools import _tool_call_writer -from langgraph.runtime import ExecutionInfo, ServerInfo # noqa: TC002 -from langgraph.store.base import BaseStore # noqa: TC002 +from langgraph.runtime import ExecutionInfo, ServerInfo +from langgraph.store.base import BaseStore from langgraph.types import Command, Send, StreamWriter from pydantic import BaseModel, ValidationError from typing_extensions import TypeVar, Unpack @@ -332,7 +332,7 @@ def msg_content_output(output: Any) -> str | list[dict]: # any existing ToolNode usage. try: return json.dumps(output, ensure_ascii=False) - except Exception: # noqa: BLE001 + except Exception: return str(output) @@ -736,7 +736,7 @@ class ToolNode(RunnableCallable): tool_node = ToolNode([my_tool], handle_tool_errors=handle_errors) ``` - """ # noqa: E501 + """ name: str = "tools" diff --git a/libs/prebuilt/pyproject.toml b/libs/prebuilt/pyproject.toml index b7a100db2..97558ae6a 100644 --- a/libs/prebuilt/pyproject.toml +++ b/libs/prebuilt/pyproject.toml @@ -75,7 +75,7 @@ addopts = "--strict-markers --strict-config --durations=5 -vv" asyncio_mode = "auto" [tool.ruff] -lint.select = [ "E", "F", "I", "TID251", "UP" ] +lint.select = [ "E", "F", "I", "RUF100", "TID251", "UP" ] lint.ignore = [ "E501" ] target-version = "py310" diff --git a/libs/prebuilt/tests/test_on_tool_call.py b/libs/prebuilt/tests/test_on_tool_call.py index f1143c96b..987369f95 100644 --- a/libs/prebuilt/tests/test_on_tool_call.py +++ b/libs/prebuilt/tests/test_on_tool_call.py @@ -1338,7 +1338,7 @@ def _config_with_channel_read( # Shape matches pregel's real partial: # functools.partial(local_read, scratchpad, channels, managed, task) - def _read(scratchpad, channels, managed, task, select, fresh): # noqa: ARG001 + def _read(scratchpad, channels, managed, task, select, fresh): if isinstance(select, str): return channel_values[select] return {k: channel_values[k] for k in select if k in channel_values}