core: Add ruff rules ANN (type annotations) (#29271)

See https://docs.astral.sh/ruff/rules/#flake8-annotations-ann
The interest compared to only mypy is that ruff is very fast at
detecting missing annotations.

ANN101 and ANN102 are deprecated so we ignore them 
ANN401 (no Any type) ignored to be in sync with mypy config

---------

Co-authored-by: ccurme <chester.curme@gmail.com>
This commit is contained in:
Christophe Bornet 2025-02-22 23:46:28 +01:00 committed by GitHub
parent 979a991dc2
commit f6d4fec4d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 52 additions and 29 deletions

View File

@ -156,28 +156,36 @@ def beta(
class _BetaProperty(property):
"""A beta property."""
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
def __init__(
self,
fget: Union[Callable[[Any], Any], None] = None,
fset: Union[Callable[[Any, Any], None], None] = None,
fdel: Union[Callable[[Any], None], None] = None,
doc: Union[str, None] = None,
) -> None:
super().__init__(fget, fset, fdel, doc)
self.__orig_fget = fget
self.__orig_fset = fset
self.__orig_fdel = fdel
def __get__(self, instance, owner=None):
def __get__(
self, instance: Any, owner: Union[type, None] = None
) -> Any:
if instance is not None or owner is not None:
emit_warning()
return self.fget(instance)
def __set__(self, instance, value):
def __set__(self, instance: Any, value: Any) -> None:
if instance is not None:
emit_warning()
return self.fset(instance, value)
def __delete__(self, instance):
def __delete__(self, instance: Any) -> None:
if instance is not None:
emit_warning()
return self.fdel(instance)
def __set_name__(self, owner, set_name):
def __set_name__(self, owner: Union[type, None], set_name: str) -> None:
nonlocal _name
if _name == "<lambda>":
_name = set_name

View File

@ -270,28 +270,40 @@ def deprecated(
class _DeprecatedProperty(property):
"""A deprecated property."""
def __init__(self, fget=None, fset=None, fdel=None, doc=None): # type: ignore[no-untyped-def]
def __init__(
self,
fget: Union[Callable[[Any], Any], None] = None,
fset: Union[Callable[[Any, Any], None], None] = None,
fdel: Union[Callable[[Any], None], None] = None,
doc: Union[str, None] = None,
) -> None:
super().__init__(fget, fset, fdel, doc)
self.__orig_fget = fget
self.__orig_fset = fset
self.__orig_fdel = fdel
def __get__(self, instance, owner=None): # type: ignore[no-untyped-def]
def __get__(
self, instance: Any, owner: Union[type, None] = None
) -> Any:
if instance is not None or owner is not None:
emit_warning()
if self.fget is None:
return None
return self.fget(instance)
def __set__(self, instance, value): # type: ignore[no-untyped-def]
def __set__(self, instance: Any, value: Any) -> None:
if instance is not None:
emit_warning()
return self.fset(instance, value)
if self.fset is not None:
self.fset(instance, value)
def __delete__(self, instance): # type: ignore[no-untyped-def]
def __delete__(self, instance: Any) -> None:
if instance is not None:
emit_warning()
return self.fdel(instance)
if self.fdel is not None:
self.fdel(instance)
def __set_name__(self, owner, set_name): # type: ignore[no-untyped-def]
def __set_name__(self, owner: Union[type, None], set_name: str) -> None:
nonlocal _name
if _name == "<lambda>":
_name = set_name

View File

@ -4641,7 +4641,7 @@ class RunnableLambda(Runnable[Input, Output]):
)
@wraps(func)
async def f(*args, **kwargs): # type: ignore[no-untyped-def]
async def f(*args: Any, **kwargs: Any) -> Any:
return await run_in_executor(config, func, *args, **kwargs)
afunc = f
@ -4889,7 +4889,7 @@ class RunnableLambda(Runnable[Input, Output]):
)
@wraps(func)
async def f(*args, **kwargs): # type: ignore[no-untyped-def]
async def f(*args: Any, **kwargs: Any) -> Any:
return await run_in_executor(config, func, *args, **kwargs)
afunc = f

View File

@ -6,7 +6,7 @@ import functools
import importlib
import os
import warnings
from collections.abc import Sequence
from collections.abc import Iterator, Sequence
from importlib.metadata import version
from typing import Any, Callable, Optional, Union, overload
@ -73,7 +73,7 @@ def raise_for_status_with_text(response: Response) -> None:
@contextlib.contextmanager
def mock_now(dt_value): # type: ignore
def mock_now(dt_value: datetime.datetime) -> Iterator[type]:
"""Context manager for mocking out datetime.now() in unit tests.
Args:
@ -91,9 +91,9 @@ def mock_now(dt_value): # type: ignore
"""Mock datetime.datetime.now() with a fixed datetime."""
@classmethod
def now(cls): # type: ignore
def now(cls, tz: Union[datetime.tzinfo, None] = None) -> "MockDateTime":
# Create a copy of dt_value.
return datetime.datetime(
return MockDateTime(
dt_value.year,
dt_value.month,
dt_value.day,
@ -105,11 +105,11 @@ def mock_now(dt_value): # type: ignore
)
real_datetime = datetime.datetime
datetime.datetime = MockDateTime
datetime.datetime = MockDateTime # type: ignore[misc]
try:
yield datetime.datetime
finally:
datetime.datetime = real_datetime
datetime.datetime = real_datetime # type: ignore[misc]
def guard_import(

View File

@ -77,8 +77,10 @@ target-version = "py39"
[tool.ruff.lint]
select = [ "ASYNC", "B", "C4", "COM", "DJ", "E", "EM", "EXE", "F", "FLY", "FURB", "I", "ICN", "INT", "LOG", "N", "NPY", "PD", "PIE", "Q", "RSE", "S", "SIM", "SLOT", "T10", "T201", "TID", "TRY", "UP", "W", "YTT",]
ignore = [ "COM812", "UP007", "S110", "S112",]
select = [ "ANN", "ASYNC", "B", "C4", "COM", "DJ", "E", "EM", "EXE", "F", "FLY", "FURB", "I", "ICN", "INT", "LOG", "N", "NPY", "PD", "PIE", "Q", "RSE", "S", "SIM", "SLOT", "T10", "T201", "TID", "TRY", "UP", "W", "YTT",]
ignore = [ "ANN401", "COM812", "UP007", "S110", "S112",]
flake8-annotations.allow-star-arg-any = true
flake8-annotations.mypy-init-return = true
[tool.coverage.run]
omit = [ "tests/*",]

View File

@ -567,7 +567,7 @@ def test_lambda_schemas(snapshot: SnapshotAssertion) -> None:
"required": ["bye", "hello"],
}
def get_value(input): # type: ignore[no-untyped-def]
def get_value(input): # type: ignore[no-untyped-def] # noqa: ANN001,ANN202
return input["variable_name"]
assert RunnableLambda(get_value).get_input_jsonschema() == {
@ -577,7 +577,7 @@ def test_lambda_schemas(snapshot: SnapshotAssertion) -> None:
"required": ["variable_name"],
}
async def aget_value(input): # type: ignore[no-untyped-def]
async def aget_value(input): # type: ignore[no-untyped-def] # noqa: ANN001,ANN202
return (input["variable_name"], input.get("another"))
assert RunnableLambda(aget_value).get_input_jsonschema() == {
@ -590,7 +590,7 @@ def test_lambda_schemas(snapshot: SnapshotAssertion) -> None:
"required": ["another", "variable_name"],
}
async def aget_values(input): # type: ignore[no-untyped-def]
async def aget_values(input): # type: ignore[no-untyped-def] # noqa: ANN001,ANN202
return {
"hello": input["variable_name"],
"bye": input["variable_name"],

View File

@ -9,6 +9,7 @@ from functools import partial
from itertools import cycle
from typing import (
Any,
Callable,
Optional,
cast,
)
@ -1902,10 +1903,10 @@ async def test_runnable_with_message_history() -> None:
# so we can raise them in this main thread
raised_errors = []
def collect_errors(fn): # type: ignore
def collect_errors(fn: Callable[..., Any]) -> Callable[..., Any]:
nonlocal raised_errors
def _get_output_messages(*args, **kwargs): # type: ignore
def _get_output_messages(*args: Any, **kwargs: Any) -> Any:
try:
return fn(*args, **kwargs)
except Exception as e:

View File

@ -465,7 +465,7 @@ def test_tree_is_constructed(parent_type: Literal["ls", "lc"]) -> None:
else:
@RunnableLambda
def parent(_) -> str: # type: ignore
def parent(_: Any) -> str:
return child.invoke("foo")
tracer = LangChainTracer()

View File

@ -2217,7 +2217,7 @@ def test_tool_args_schema_pydantic_v2_with_metadata() -> None:
)
@tool(args_schema=Foo)
def foo(x): # type: ignore[no-untyped-def]
def foo(x) -> list[int]: # type: ignore[no-untyped-def] # noqa: ANN001
"""Foo."""
return x