core: Put Python version as a project requirement so it is considered by ruff (#26608)

Ruff doesn't know about the python version in
`[tool.poetry.dependencies]`. It can get it from
`project.requires-python`.

Notes:
* poetry seems to have issues getting the python constraints from
`requires-python` and using `python` in per dependency constraints. So I
had to duplicate the info. I will open an issue on poetry.
* `inspect.isclass()` doesn't work correctly with `GenericAlias`
(`list[...]`, `dict[..., ...]`) on Python <3.11 so I added some `not
isinstance(type, GenericAlias)` checks:

Python 3.11
```pycon
>>> import inspect
>>> inspect.isclass(list)
True
>>> inspect.isclass(list[str])
False
```

Python 3.9
```pycon
>>> import inspect
>>> inspect.isclass(list)
True
>>> inspect.isclass(list[str])
True
```

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
This commit is contained in:
Christophe Bornet
2024-09-18 16:37:57 +02:00
committed by GitHub
parent 0f07cf61da
commit a47b332841
162 changed files with 920 additions and 1002 deletions

View File

@@ -1,4 +1,4 @@
from typing import AsyncIterator, List
from collections.abc import AsyncIterator
import pytest
@@ -15,11 +15,11 @@ from langchain_core.utils.aiter import abatch_iterate
],
)
async def test_abatch_iterate(
input_size: int, input_iterable: List[str], expected_output: List[str]
input_size: int, input_iterable: list[str], expected_output: list[str]
) -> None:
"""Test batching function."""
async def _to_async_iterable(iterable: List[str]) -> AsyncIterator[str]:
async def _to_async_iterable(iterable: list[str]) -> AsyncIterator[str]:
for item in iterable:
yield item

View File

@@ -1,20 +1,13 @@
# mypy: disable-error-code="annotation-unchecked"
import sys
import typing
from collections.abc import Iterable, Mapping, MutableMapping, Sequence
from typing import Annotated as ExtensionsAnnotated
from typing import (
Any,
Callable,
Dict,
Iterable,
List,
Literal,
Mapping,
MutableMapping,
MutableSet,
Optional,
Sequence,
Set,
Tuple,
Type,
Union,
)
from typing import TypedDict as TypingTypedDict
@@ -22,9 +15,6 @@ from typing import TypedDict as TypingTypedDict
import pytest
from pydantic import BaseModel as BaseModelV2Maybe # pydantic: ignore
from pydantic import Field as FieldV2Maybe # pydantic: ignore
from typing_extensions import (
Annotated as ExtensionsAnnotated,
)
from typing_extensions import (
TypedDict as ExtensionsTypedDict,
)
@@ -47,7 +37,7 @@ from langchain_core.utils.function_calling import (
@pytest.fixture()
def pydantic() -> Type[BaseModel]:
def pydantic() -> type[BaseModel]:
class dummy_function(BaseModel):
"""dummy function"""
@@ -102,7 +92,7 @@ def dummy_tool() -> BaseTool:
arg2: Literal["bar", "baz"] = Field(..., description="one of 'bar', 'baz'")
class DummyFunction(BaseTool):
args_schema: Type[BaseModel] = Schema
args_schema: type[BaseModel] = Schema
name: str = "dummy_function"
description: str = "dummy function"
@@ -127,7 +117,7 @@ def dummy_structured_tool() -> StructuredTool:
@pytest.fixture()
def dummy_pydantic() -> Type[BaseModel]:
def dummy_pydantic() -> type[BaseModel]:
class dummy_function(BaseModel):
"""dummy function"""
@@ -138,7 +128,7 @@ def dummy_pydantic() -> Type[BaseModel]:
@pytest.fixture()
def dummy_pydantic_v2() -> Type[BaseModelV2Maybe]:
def dummy_pydantic_v2() -> type[BaseModelV2Maybe]:
class dummy_function(BaseModelV2Maybe):
"""dummy function"""
@@ -151,7 +141,7 @@ def dummy_pydantic_v2() -> Type[BaseModelV2Maybe]:
@pytest.fixture()
def dummy_typing_typed_dict() -> Type:
def dummy_typing_typed_dict() -> type:
class dummy_function(TypingTypedDict):
"""dummy function"""
@@ -162,7 +152,7 @@ def dummy_typing_typed_dict() -> Type:
@pytest.fixture()
def dummy_typing_typed_dict_docstring() -> Type:
def dummy_typing_typed_dict_docstring() -> type:
class dummy_function(TypingTypedDict):
"""dummy function
@@ -178,7 +168,7 @@ def dummy_typing_typed_dict_docstring() -> Type:
@pytest.fixture()
def dummy_extensions_typed_dict() -> Type:
def dummy_extensions_typed_dict() -> type:
class dummy_function(ExtensionsTypedDict):
"""dummy function"""
@@ -189,7 +179,7 @@ def dummy_extensions_typed_dict() -> Type:
@pytest.fixture()
def dummy_extensions_typed_dict_docstring() -> Type:
def dummy_extensions_typed_dict_docstring() -> type:
class dummy_function(ExtensionsTypedDict):
"""dummy function
@@ -205,7 +195,7 @@ def dummy_extensions_typed_dict_docstring() -> Type:
@pytest.fixture()
def json_schema() -> Dict:
def json_schema() -> dict:
return {
"title": "dummy_function",
"description": "dummy function",
@@ -246,18 +236,18 @@ class DummyWithClassMethod:
def test_convert_to_openai_function(
pydantic: Type[BaseModel],
pydantic: type[BaseModel],
function: Callable,
dummy_structured_tool: StructuredTool,
dummy_tool: BaseTool,
json_schema: Dict,
json_schema: dict,
Annotated_function: Callable,
dummy_pydantic: Type[BaseModel],
dummy_pydantic: type[BaseModel],
runnable: Runnable,
dummy_typing_typed_dict: Type,
dummy_typing_typed_dict_docstring: Type,
dummy_extensions_typed_dict: Type,
dummy_extensions_typed_dict_docstring: Type,
dummy_typing_typed_dict: type,
dummy_typing_typed_dict_docstring: type,
dummy_extensions_typed_dict: type,
dummy_extensions_typed_dict_docstring: type,
) -> None:
expected = {
"name": "dummy_function",
@@ -436,7 +426,7 @@ def test_function_optional_param() -> None:
def func5(
a: Optional[str],
b: str,
c: Optional[List[Optional[str]]],
c: Optional[list[Optional[str]]],
) -> None:
"""A test function"""
pass
@@ -544,7 +534,7 @@ def test__convert_typed_dict_to_openai_function(
class SubTool(TypedDict):
"""Subtool docstring"""
args: Annotated[Dict[str, Any], {}, "this does bar"] # noqa: F722 # type: ignore
args: Annotated[dict[str, Any], {}, "this does bar"] # noqa: F722 # type: ignore
class Tool(TypedDict):
"""Docstring
@@ -555,18 +545,18 @@ def test__convert_typed_dict_to_openai_function(
arg1: str
arg2: Union[int, str, bool]
arg3: Optional[List[SubTool]]
arg3: Optional[list[SubTool]]
arg4: Annotated[Literal["bar", "baz"], ..., "this does foo"] # noqa: F722
arg5: Annotated[Optional[float], None]
arg6: Annotated[
Optional[Sequence[Mapping[str, Tuple[Iterable[Any], SubTool]]]], []
Optional[Sequence[Mapping[str, tuple[Iterable[Any], SubTool]]]], []
]
arg7: Annotated[List[SubTool], ...]
arg8: Annotated[Tuple[SubTool], ...]
arg7: Annotated[list[SubTool], ...]
arg8: Annotated[tuple[SubTool], ...]
arg9: Annotated[Sequence[SubTool], ...]
arg10: Annotated[Iterable[SubTool], ...]
arg11: Annotated[Set[SubTool], ...]
arg12: Annotated[Dict[str, SubTool], ...]
arg11: Annotated[set[SubTool], ...]
arg12: Annotated[dict[str, SubTool], ...]
arg13: Annotated[Mapping[str, SubTool], ...]
arg14: Annotated[MutableMapping[str, SubTool], ...]
arg15: Annotated[bool, False, "flag"] # noqa: F821 # type: ignore
@@ -775,9 +765,9 @@ def test__convert_typed_dict_to_openai_function(
@pytest.mark.parametrize("typed_dict", [ExtensionsTypedDict, TypingTypedDict])
def test__convert_typed_dict_to_openai_function_fail(typed_dict: Type) -> None:
def test__convert_typed_dict_to_openai_function_fail(typed_dict: type) -> None:
class Tool(typed_dict):
arg1: MutableSet # Pydantic 2 supports this, but pydantic v1 does not.
arg1: typing.MutableSet # Pydantic 2 supports this, but pydantic v1 does not.
# Error should be raised since we're using v1 code path here
with pytest.raises(TypeError):

View File

@@ -1,5 +1,3 @@
from typing import List
import pytest
from langchain_core.utils.iter import batch_iterate
@@ -15,7 +13,7 @@ from langchain_core.utils.iter import batch_iterate
],
)
def test_batch_iterate(
input_size: int, input_iterable: List[str], expected_output: List[str]
input_size: int, input_iterable: list[str], expected_output: list[str]
) -> None:
"""Test batching function."""
assert list(batch_iterate(input_size, input_iterable)) == expected_output

View File

@@ -1,6 +1,6 @@
"""Test for some custom pydantic decorators."""
from typing import Any, Dict, List, Optional
from typing import Any, Optional
import pytest
from pydantic import ConfigDict
@@ -24,7 +24,7 @@ def test_pre_init_decorator() -> None:
y: int
@pre_init
def validator(cls, v: Dict[str, Any]) -> Dict[str, Any]:
def validator(cls, v: dict[str, Any]) -> dict[str, Any]:
v["y"] = v["x"] + 1
return v
@@ -45,7 +45,7 @@ def test_pre_init_decorator_with_more_defaults() -> None:
d: int = Field(default_factory=lambda: 3)
@pre_init
def validator(cls, v: Dict[str, Any]) -> Dict[str, Any]:
def validator(cls, v: dict[str, Any]) -> dict[str, Any]:
assert v["a"] == 1
assert v["b"] is None
assert v["c"] == 2
@@ -69,7 +69,7 @@ def test_with_aliases() -> None:
)
@pre_init
def validator(cls, v: Dict[str, Any]) -> Dict[str, Any]:
def validator(cls, v: dict[str, Any]) -> dict[str, Any]:
v["z"] = v["x"]
return v
@@ -142,7 +142,7 @@ def test_with_field_metadata() -> None:
from pydantic import Field as FieldV2
class Foo(BaseModelV2):
x: List[int] = FieldV2(
x: list[int] = FieldV2(
description="List of integers", min_length=10, max_length=15
)

View File

@@ -2,7 +2,7 @@ import os
import re
from contextlib import AbstractContextManager, nullcontext
from copy import deepcopy
from typing import Any, Callable, Dict, Optional, Tuple, Type, Union
from typing import Any, Callable, Optional, Union
from unittest.mock import patch
import pytest
@@ -32,9 +32,9 @@ from langchain_core.utils.utils import secret_from_env
)
def test_check_package_version(
package: str,
check_kwargs: Dict[str, Optional[str]],
check_kwargs: dict[str, Optional[str]],
actual_version: str,
expected: Optional[Tuple[Type[Exception], str]],
expected: Optional[tuple[type[Exception], str]],
) -> None:
with patch("langchain_core.utils.utils.version", return_value=actual_version):
if expected is None: