core: Improve mypy config (#30737)

* Cleanup mypy config
* Add mypy `strict` rules except `disallow_any_generics`,
`warn_return_any` and `strict_equality` (TODO)
* Add mypy `strict_byte` rule
* Add mypy support for PEP702 `@deprecated` decorator
* Bump mypy version to 1.15

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
This commit is contained in:
Christophe Bornet 2025-04-11 22:35:13 +02:00 committed by GitHub
parent bb2c2fd885
commit 42944f3499
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
60 changed files with 222 additions and 237 deletions

View File

@ -225,10 +225,8 @@ def beta(
new_doc = f".. beta::\n {details}\n\n{old_doc}\n" new_doc = f".. beta::\n {details}\n\n{old_doc}\n"
if inspect.iscoroutinefunction(obj): if inspect.iscoroutinefunction(obj):
finalized = finalize(awarning_emitting_wrapper, new_doc) return finalize(awarning_emitting_wrapper, new_doc)
else: return finalize(warning_emitting_wrapper, new_doc)
finalized = finalize(warning_emitting_wrapper, new_doc)
return cast("T", finalized)
return beta return beta

View File

@ -152,7 +152,10 @@ def deprecated(
_package: str = package, _package: str = package,
) -> T: ) -> T:
"""Implementation of the decorator returned by `deprecated`.""" """Implementation of the decorator returned by `deprecated`."""
from langchain_core.utils.pydantic import FieldInfoV1, FieldInfoV2 from langchain_core.utils.pydantic import ( # type: ignore[attr-defined]
FieldInfoV1,
FieldInfoV2,
)
def emit_warning() -> None: def emit_warning() -> None:
"""Emit the warning.""" """Emit the warning."""
@ -395,10 +398,8 @@ def deprecated(
""" """
if inspect.iscoroutinefunction(obj): if inspect.iscoroutinefunction(obj):
finalized = finalize(awarning_emitting_wrapper, new_doc) return finalize(awarning_emitting_wrapper, new_doc)
else: return finalize(warning_emitting_wrapper, new_doc)
finalized = finalize(warning_emitting_wrapper, new_doc)
return cast("T", finalized)
return deprecate return deprecate

View File

@ -2408,7 +2408,7 @@ def _configure(
run_tree.trace_id, run_tree.trace_id,
run_tree.dotted_order, run_tree.dotted_order,
) )
handler.run_map[str(run_tree.id)] = cast("Run", run_tree) handler.run_map[str(run_tree.id)] = run_tree
for var, inheritable, handler_class, env_var in _configure_hooks: for var, inheritable, handler_class, env_var in _configure_hooks:
create_one = ( create_one = (
env_var is not None env_var is not None

View File

@ -80,7 +80,7 @@ class BaseLoader(ABC): # noqa: B024
iterator = await run_in_executor(None, self.lazy_load) iterator = await run_in_executor(None, self.lazy_load)
done = object() done = object()
while True: while True:
doc = await run_in_executor(None, next, iterator, done) # type: ignore[call-arg, arg-type] doc = await run_in_executor(None, next, iterator, done)
if doc is done: if doc is done:
break break
yield doc # type: ignore[misc] yield doc # type: ignore[misc]

View File

@ -52,7 +52,7 @@ class FakeEmbeddings(Embeddings, BaseModel):
"""The size of the embedding vector.""" """The size of the embedding vector."""
def _get_embedding(self) -> list[float]: def _get_embedding(self) -> list[float]:
import numpy as np # type: ignore[import-not-found, import-untyped] import numpy as np
return list(np.random.default_rng().normal(size=self.size)) return list(np.random.default_rng().normal(size=self.size))
@ -109,7 +109,7 @@ class DeterministicFakeEmbedding(Embeddings, BaseModel):
"""The size of the embedding vector.""" """The size of the embedding vector."""
def _get_embedding(self, seed: int) -> list[float]: def _get_embedding(self, seed: int) -> list[float]:
import numpy as np # type: ignore[import-not-found, import-untyped] import numpy as np
# set the seed for the random generator # set the seed for the random generator
rng = np.random.default_rng(seed) rng = np.random.default_rng(seed)

View File

@ -23,7 +23,7 @@ def set_verbose(value: bool) -> None: # noqa: FBT001
value: The new value for the `verbose` global setting. value: The new value for the `verbose` global setting.
""" """
try: try:
import langchain # type: ignore[import] import langchain # type: ignore[import-not-found]
# We're about to run some deprecated code, don't report warnings from it. # We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get # The user called the correct (non-deprecated) code path and shouldn't get
@ -57,7 +57,7 @@ def get_verbose() -> bool:
The value of the `verbose` global setting. The value of the `verbose` global setting.
""" """
try: try:
import langchain # type: ignore[import] import langchain
# We're about to run some deprecated code, don't report warnings from it. # We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get # The user called the correct (non-deprecated) code path and shouldn't get
@ -96,7 +96,7 @@ def set_debug(value: bool) -> None: # noqa: FBT001
value: The new value for the `debug` global setting. value: The new value for the `debug` global setting.
""" """
try: try:
import langchain # type: ignore[import] import langchain
# We're about to run some deprecated code, don't report warnings from it. # We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get # The user called the correct (non-deprecated) code path and shouldn't get
@ -128,7 +128,7 @@ def get_debug() -> bool:
The value of the `debug` global setting. The value of the `debug` global setting.
""" """
try: try:
import langchain # type: ignore[import] import langchain
# We're about to run some deprecated code, don't report warnings from it. # We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get # The user called the correct (non-deprecated) code path and shouldn't get
@ -164,7 +164,7 @@ def set_llm_cache(value: Optional["BaseCache"]) -> None:
value: The new LLM cache to use. If `None`, the LLM cache is disabled. value: The new LLM cache to use. If `None`, the LLM cache is disabled.
""" """
try: try:
import langchain # type: ignore[import] import langchain
# We're about to run some deprecated code, don't report warnings from it. # We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get # The user called the correct (non-deprecated) code path and shouldn't get
@ -198,7 +198,7 @@ def get_llm_cache() -> "BaseCache":
The value of the `llm_cache` global setting. The value of the `llm_cache` global setting.
""" """
try: try:
import langchain # type: ignore[import] import langchain
# We're about to run some deprecated code, don't report warnings from it. # We're about to run some deprecated code, don't report warnings from it.
# The user called the correct (non-deprecated) code path and shouldn't get # The user called the correct (non-deprecated) code path and shouldn't get

View File

@ -394,7 +394,7 @@ def index(
if cleanup == "scoped_full": if cleanup == "scoped_full":
scoped_full_cleanup_source_ids.add(source_id) scoped_full_cleanup_source_ids.add(source_id)
# source ids cannot be None after for loop above. # source ids cannot be None after for loop above.
source_ids = cast("Sequence[str]", source_ids) # type: ignore[assignment] source_ids = cast("Sequence[str]", source_ids)
exists_batch = record_manager.exists([doc.uid for doc in hashed_docs]) exists_batch = record_manager.exists([doc.uid for doc in hashed_docs])

View File

@ -61,7 +61,7 @@ def get_tokenizer() -> Any:
every time it is called. every time it is called.
""" """
try: try:
from transformers import GPT2TokenizerFast # type: ignore[import] from transformers import GPT2TokenizerFast # type: ignore[import-not-found]
except ImportError as e: except ImportError as e:
msg = ( msg = (
"Could not import transformers python package. " "Could not import transformers python package. "

View File

@ -853,7 +853,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
run_manager.on_llm_end( run_manager.on_llm_end(
LLMResult( LLMResult(
generations=[res.generations], # type: ignore[list-item, union-attr] generations=[res.generations], # type: ignore[list-item, union-attr]
llm_output=res.llm_output, # type: ignore[list-item, union-attr] llm_output=res.llm_output, # type: ignore[union-attr]
) )
) )
for run_manager, res in zip(run_managers, results) for run_manager, res in zip(run_managers, results)
@ -1107,7 +1107,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
None, None,
next, next,
iterator, iterator,
done, # type: ignore[call-arg, arg-type] done,
) )
if item is done: if item is done:
break break

View File

@ -455,7 +455,7 @@ class BaseLLM(BaseLanguageModel[str], ABC):
inputs[i : i + max_concurrency] inputs[i : i + max_concurrency]
for i in range(0, len(inputs), max_concurrency) for i in range(0, len(inputs), max_concurrency)
] ]
config = [{**c, "max_concurrency": None} for c in config] # type: ignore[misc] config = [{**c, "max_concurrency": None} for c in config]
return [ return [
output output
for i, batch in enumerate(batches) for i, batch in enumerate(batches)
@ -501,7 +501,7 @@ class BaseLLM(BaseLanguageModel[str], ABC):
inputs[i : i + max_concurrency] inputs[i : i + max_concurrency]
for i in range(0, len(inputs), max_concurrency) for i in range(0, len(inputs), max_concurrency)
] ]
config = [{**c, "max_concurrency": None} for c in config] # type: ignore[misc] config = [{**c, "max_concurrency": None} for c in config]
return [ return [
output output
for i, batch in enumerate(batches) for i, batch in enumerate(batches)
@ -746,7 +746,7 @@ class BaseLLM(BaseLanguageModel[str], ABC):
None, None,
next, next,
iterator, iterator,
done, # type: ignore[call-arg, arg-type] done,
) )
if item is done: if item is done:
break break
@ -1231,7 +1231,7 @@ class BaseLLM(BaseLanguageModel[str], ABC):
stop, stop,
run_managers, # type: ignore[arg-type] run_managers, # type: ignore[arg-type]
new_arg_supported=bool(new_arg_supported), new_arg_supported=bool(new_arg_supported),
**kwargs, # type: ignore[arg-type] **kwargs,
) )
if len(missing_prompts) > 0: if len(missing_prompts) > 0:
run_managers = await asyncio.gather( run_managers = await asyncio.gather(
@ -1253,7 +1253,7 @@ class BaseLLM(BaseLanguageModel[str], ABC):
stop, stop,
run_managers, # type: ignore[arg-type] run_managers, # type: ignore[arg-type]
new_arg_supported=bool(new_arg_supported), new_arg_supported=bool(new_arg_supported),
**kwargs, # type: ignore[arg-type] **kwargs,
) )
llm_output = await aupdate_cache( llm_output = await aupdate_cache(
self.cache, self.cache,

View File

@ -119,7 +119,7 @@ class BaseMessage(Serializable):
"""Concatenate this message with another message.""" """Concatenate this message with another message."""
from langchain_core.prompts.chat import ChatPromptTemplate from langchain_core.prompts.chat import ChatPromptTemplate
prompt = ChatPromptTemplate(messages=[self]) # type: ignore[call-arg] prompt = ChatPromptTemplate(messages=[self])
return prompt + other return prompt + other
def pretty_repr( def pretty_repr(
@ -165,7 +165,7 @@ def merge_content(
if isinstance(merged, str): if isinstance(merged, str):
# If the next chunk is also a string, then merge them naively # If the next chunk is also a string, then merge them naively
if isinstance(content, str): if isinstance(content, str):
merged = cast("str", merged) + content merged += content
# If the next chunk is a list, add the current to the start of the list # If the next chunk is a list, add the current to the start of the list
else: else:
merged = [merged] + content # type: ignore[assignment,operator] merged = [merged] + content # type: ignore[assignment,operator]
@ -215,7 +215,7 @@ class BaseMessageChunk(BaseMessage):
# If both are (subclasses of) BaseMessageChunk, # If both are (subclasses of) BaseMessageChunk,
# concat into a single BaseMessageChunk # concat into a single BaseMessageChunk
return self.__class__( # type: ignore[call-arg] return self.__class__(
id=self.id, id=self.id,
type=self.type, type=self.type,
content=merge_content(self.content, other.content), content=merge_content(self.content, other.content),

View File

@ -237,7 +237,7 @@ def _create_message_from_message_type(
if additional_kwargs: if additional_kwargs:
if response_metadata := additional_kwargs.pop("response_metadata", None): if response_metadata := additional_kwargs.pop("response_metadata", None):
kwargs["response_metadata"] = response_metadata kwargs["response_metadata"] = response_metadata
kwargs["additional_kwargs"] = additional_kwargs # type: ignore[assignment] kwargs["additional_kwargs"] = additional_kwargs
additional_kwargs.update(additional_kwargs.pop("additional_kwargs", {})) additional_kwargs.update(additional_kwargs.pop("additional_kwargs", {}))
if id is not None: if id is not None:
kwargs["id"] = id kwargs["id"] = id
@ -889,7 +889,7 @@ def trim_messages(
return sum(token_counter(msg) for msg in messages) # type: ignore[arg-type, misc] return sum(token_counter(msg) for msg in messages) # type: ignore[arg-type, misc]
else: else:
list_token_counter = token_counter # type: ignore[assignment] list_token_counter = token_counter
else: else:
msg = ( msg = (
f"'token_counter' expected to be a model that implements " f"'token_counter' expected to be a model that implements "

View File

@ -6,7 +6,7 @@ import json
from json import JSONDecodeError from json import JSONDecodeError
from typing import Annotated, Any, Optional, TypeVar, Union from typing import Annotated, Any, Optional, TypeVar, Union
import jsonpatch # type: ignore[import] import jsonpatch # type: ignore[import-untyped]
import pydantic import pydantic
from pydantic import SkipValidation from pydantic import SkipValidation

View File

@ -5,7 +5,7 @@ import json
from types import GenericAlias from types import GenericAlias
from typing import Any, Optional, Union from typing import Any, Optional, Union
import jsonpatch # type: ignore[import] import jsonpatch # type: ignore[import-untyped]
from pydantic import BaseModel, model_validator from pydantic import BaseModel, model_validator
from typing_extensions import override from typing_extensions import override

View File

@ -50,7 +50,7 @@ class LLMResult(BaseModel):
run: Optional[list[RunInfo]] = None run: Optional[list[RunInfo]] = None
"""List of metadata info for model call for each input.""" """List of metadata info for model call for each input."""
type: Literal["LLMResult"] = "LLMResult" # type: ignore[assignment] type: Literal["LLMResult"] = "LLMResult"
"""Type is used exclusively for serialization purposes.""" """Type is used exclusively for serialization purposes."""
def flatten(self) -> list[LLMResult]: def flatten(self) -> list[LLMResult]:

View File

@ -129,7 +129,7 @@ class BaseMessagePromptTemplate(Serializable, ABC):
Returns: Returns:
Combined prompt template. Combined prompt template.
""" """
prompt = ChatPromptTemplate(messages=[self]) # type: ignore[call-arg] prompt = ChatPromptTemplate(messages=[self])
return prompt + other return prompt + other
@ -1033,23 +1033,23 @@ class ChatPromptTemplate(BaseChatPromptTemplate):
if isinstance(other, ChatPromptTemplate): if isinstance(other, ChatPromptTemplate):
return ChatPromptTemplate(messages=self.messages + other.messages).partial( return ChatPromptTemplate(messages=self.messages + other.messages).partial(
**partials **partials
) # type: ignore[call-arg] )
if isinstance( if isinstance(
other, (BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTemplate) other, (BaseMessagePromptTemplate, BaseMessage, BaseChatPromptTemplate)
): ):
return ChatPromptTemplate(messages=self.messages + [other]).partial( return ChatPromptTemplate(messages=self.messages + [other]).partial(
**partials **partials
) # type: ignore[call-arg] )
if isinstance(other, (list, tuple)): if isinstance(other, (list, tuple)):
_other = ChatPromptTemplate.from_messages(other) _other = ChatPromptTemplate.from_messages(other)
return ChatPromptTemplate(messages=self.messages + _other.messages).partial( return ChatPromptTemplate(messages=self.messages + _other.messages).partial(
**partials **partials
) # type: ignore[call-arg] )
if isinstance(other, str): if isinstance(other, str):
prompt = HumanMessagePromptTemplate.from_template(other) prompt = HumanMessagePromptTemplate.from_template(other)
return ChatPromptTemplate(messages=self.messages + [prompt]).partial( return ChatPromptTemplate(messages=self.messages + [prompt]).partial(
**partials **partials
) # type: ignore[call-arg] )
msg = f"Unsupported operand type for +: {type(other)}" msg = f"Unsupported operand type for +: {type(other)}"
raise NotImplementedError(msg) raise NotImplementedError(msg)
@ -1138,7 +1138,7 @@ class ChatPromptTemplate(BaseChatPromptTemplate):
Returns: Returns:
a chat prompt template. a chat prompt template.
""" """
return cls( # type: ignore[call-arg] return cls(
messages=[ messages=[
ChatMessagePromptTemplate.from_template(template, role=role) ChatMessagePromptTemplate.from_template(template, role=role)
for role, template in string_messages for role, template in string_messages

View File

@ -116,7 +116,7 @@ class ImagePromptTemplate(BasePromptTemplate[ImageURL]):
output: ImageURL = {"url": url} output: ImageURL = {"url": url}
if detail: if detail:
# Don't check literal values here: let the API check them # Don't check literal values here: let the API check them
output["detail"] = detail # type: ignore[typeddict-item] output["detail"] = detail
return output return output
async def aformat(self, **kwargs: Any) -> ImageURL: async def aformat(self, **kwargs: Any) -> ImageURL:

View File

@ -297,7 +297,7 @@ class PromptTemplate(StringPromptTemplate):
return cls( return cls(
input_variables=input_variables, input_variables=input_variables,
template=template, template=template,
template_format=template_format, # type: ignore[arg-type] template_format=template_format,
partial_variables=_partial_variables, partial_variables=_partial_variables,
**kwargs, **kwargs,
) )

View File

@ -18,7 +18,7 @@ from langchain_core._api.deprecation import warn_deprecated
try: try:
from pydantic.v1 import * # noqa: F403 from pydantic.v1 import * # noqa: F403
except ImportError: except ImportError:
from pydantic import * # noqa: F403 from pydantic import * # type: ignore[assignment,no-redef] # noqa: F403
try: try:

View File

@ -5,7 +5,7 @@ from langchain_core._api import warn_deprecated
try: try:
from pydantic.v1.dataclasses import * # noqa: F403 from pydantic.v1.dataclasses import * # noqa: F403
except ImportError: except ImportError:
from pydantic.dataclasses import * # noqa: F403 from pydantic.dataclasses import * # type: ignore[no-redef] # noqa: F403
warn_deprecated( warn_deprecated(
"0.3.0", "0.3.0",

View File

@ -5,7 +5,7 @@ from langchain_core._api import warn_deprecated
try: try:
from pydantic.v1.main import * # noqa: F403 from pydantic.v1.main import * # noqa: F403
except ImportError: except ImportError:
from pydantic.main import * # noqa: F403 from pydantic.main import * # type: ignore[assignment,no-redef] # noqa: F403
warn_deprecated( warn_deprecated(
"0.3.0", "0.3.0",

View File

@ -30,6 +30,7 @@ from pydantic import ConfigDict
from typing_extensions import Self, TypedDict, override from typing_extensions import Self, TypedDict, override
from langchain_core._api import deprecated from langchain_core._api import deprecated
from langchain_core.callbacks import Callbacks
from langchain_core.documents import Document from langchain_core.documents import Document
from langchain_core.runnables import ( from langchain_core.runnables import (
Runnable, Runnable,
@ -43,7 +44,6 @@ if TYPE_CHECKING:
from langchain_core.callbacks.manager import ( from langchain_core.callbacks.manager import (
AsyncCallbackManagerForRetrieverRun, AsyncCallbackManagerForRetrieverRun,
CallbackManagerForRetrieverRun, CallbackManagerForRetrieverRun,
Callbacks,
) )
RetrieverInput = str RetrieverInput = str
@ -160,10 +160,10 @@ class BaseRetriever(RunnableSerializable[RetrieverInput, RetrieverOutput], ABC):
stacklevel=4, stacklevel=4,
) )
swap = cls.get_relevant_documents swap = cls.get_relevant_documents
cls.get_relevant_documents = ( # type: ignore[assignment] cls.get_relevant_documents = ( # type: ignore[method-assign]
BaseRetriever.get_relevant_documents BaseRetriever.get_relevant_documents
) )
cls._get_relevant_documents = swap # type: ignore[assignment] cls._get_relevant_documents = swap # type: ignore[method-assign]
if ( if (
hasattr(cls, "aget_relevant_documents") hasattr(cls, "aget_relevant_documents")
and cls.aget_relevant_documents != BaseRetriever.aget_relevant_documents and cls.aget_relevant_documents != BaseRetriever.aget_relevant_documents
@ -175,10 +175,10 @@ class BaseRetriever(RunnableSerializable[RetrieverInput, RetrieverOutput], ABC):
stacklevel=4, stacklevel=4,
) )
aswap = cls.aget_relevant_documents aswap = cls.aget_relevant_documents
cls.aget_relevant_documents = ( # type: ignore[assignment] cls.aget_relevant_documents = ( # type: ignore[method-assign]
BaseRetriever.aget_relevant_documents BaseRetriever.aget_relevant_documents
) )
cls._aget_relevant_documents = aswap # type: ignore[assignment] cls._aget_relevant_documents = aswap # type: ignore[method-assign]
parameters = signature(cls._get_relevant_documents).parameters parameters = signature(cls._get_relevant_documents).parameters
cls._new_arg_supported = parameters.get("run_manager") is not None cls._new_arg_supported = parameters.get("run_manager") is not None
if ( if (

View File

@ -489,7 +489,7 @@ class Runnable(Generic[Input, Output], ABC):
include = include or [] include = include or []
config_specs = self.config_specs config_specs = self.config_specs
configurable = ( configurable = (
create_model_v2( # type: ignore[call-overload] create_model_v2(
"Configurable", "Configurable",
field_definitions={ field_definitions={
spec.id: ( spec.id: (
@ -514,9 +514,7 @@ class Runnable(Generic[Input, Output], ABC):
if field_name in [i for i in include if i != "configurable"] if field_name in [i for i in include if i != "configurable"]
}, },
} }
return create_model_v2( # type: ignore[call-overload] return create_model_v2(self.get_name("Config"), field_definitions=all_fields)
self.get_name("Config"), field_definitions=all_fields
)
def get_config_jsonschema( def get_config_jsonschema(
self, *, include: Optional[Sequence[str]] = None self, *, include: Optional[Sequence[str]] = None
@ -1543,7 +1541,7 @@ class Runnable(Generic[Input, Output], ABC):
config=cast( config=cast(
"RunnableConfig", "RunnableConfig",
{**(config or {}), **kwargs}, {**(config or {}), **kwargs},
), # type: ignore[misc] ),
kwargs={}, kwargs={},
) )
@ -1931,8 +1929,8 @@ class Runnable(Generic[Input, Output], ABC):
"Output", "Output",
context.run( context.run(
call_func_with_variable_args, # type: ignore[arg-type] call_func_with_variable_args, # type: ignore[arg-type]
func, # type: ignore[arg-type] func,
input, # type: ignore[arg-type] input,
config, config,
run_manager, run_manager,
**kwargs, **kwargs,
@ -2194,7 +2192,7 @@ class Runnable(Generic[Input, Output], ABC):
cast("_StreamingCallbackHandler", h) cast("_StreamingCallbackHandler", h)
for h in run_manager.handlers for h in run_manager.handlers
# instance check OK here, it's a mixin # instance check OK here, it's a mixin
if isinstance(h, _StreamingCallbackHandler) # type: ignore[misc] if isinstance(h, _StreamingCallbackHandler)
), ),
None, None,
): ):
@ -2299,7 +2297,7 @@ class Runnable(Generic[Input, Output], ABC):
cast("_StreamingCallbackHandler", h) cast("_StreamingCallbackHandler", h)
for h in run_manager.handlers for h in run_manager.handlers
# instance check OK here, it's a mixin # instance check OK here, it's a mixin
if isinstance(h, _StreamingCallbackHandler) # type: ignore[misc] if isinstance(h, _StreamingCallbackHandler)
), ),
None, None,
): ):
@ -2318,7 +2316,7 @@ class Runnable(Generic[Input, Output], ABC):
final_output = chunk final_output = chunk
else: else:
try: try:
final_output = final_output + chunk # type: ignore[operator] final_output = final_output + chunk
except TypeError: except TypeError:
final_output = chunk final_output = chunk
final_output_supported = False final_output_supported = False
@ -2601,7 +2599,7 @@ def _seq_input_schema(
next_input_schema = _seq_input_schema(steps[1:], config) next_input_schema = _seq_input_schema(steps[1:], config)
if not issubclass(next_input_schema, RootModel): if not issubclass(next_input_schema, RootModel):
# it's a dict as expected # it's a dict as expected
return create_model_v2( # type: ignore[call-overload] return create_model_v2(
"RunnableSequenceInput", "RunnableSequenceInput",
field_definitions={ field_definitions={
k: (v.annotation, v.default) k: (v.annotation, v.default)
@ -2628,7 +2626,7 @@ def _seq_output_schema(
prev_output_schema = _seq_output_schema(steps[:-1], config) prev_output_schema = _seq_output_schema(steps[:-1], config)
if not issubclass(prev_output_schema, RootModel): if not issubclass(prev_output_schema, RootModel):
# it's a dict as expected # it's a dict as expected
return create_model_v2( # type: ignore[call-overload] return create_model_v2(
"RunnableSequenceOutput", "RunnableSequenceOutput",
field_definitions={ field_definitions={
**{ **{
@ -2646,7 +2644,7 @@ def _seq_output_schema(
if not issubclass(prev_output_schema, RootModel): if not issubclass(prev_output_schema, RootModel):
# it's a dict as expected # it's a dict as expected
if isinstance(last.keys, list): if isinstance(last.keys, list):
return create_model_v2( # type: ignore[call-overload] return create_model_v2(
"RunnableSequenceOutput", "RunnableSequenceOutput",
field_definitions={ field_definitions={
k: (v.annotation, v.default) k: (v.annotation, v.default)
@ -2655,7 +2653,7 @@ def _seq_output_schema(
}, },
) )
field = prev_output_schema.model_fields[last.keys] field = prev_output_schema.model_fields[last.keys]
return create_model_v2( # type: ignore[call-overload] return create_model_v2(
"RunnableSequenceOutput", root=(field.annotation, field.default) "RunnableSequenceOutput", root=(field.annotation, field.default)
) )
@ -3625,7 +3623,7 @@ class RunnableParallel(RunnableSerializable[Input, dict[str, Any]]):
for s in self.steps__.values() for s in self.steps__.values()
): ):
# This is correct, but pydantic typings/mypy don't think so. # This is correct, but pydantic typings/mypy don't think so.
return create_model_v2( # type: ignore[call-overload] return create_model_v2(
self.get_name("Input"), self.get_name("Input"),
field_definitions={ field_definitions={
k: (v.annotation, v.default) k: (v.annotation, v.default)
@ -4084,7 +4082,7 @@ class RunnableGenerator(Runnable[Input, Output]):
func_for_name: Callable = atransform func_for_name: Callable = atransform
if is_async_generator(transform): if is_async_generator(transform):
self._atransform = transform # type: ignore[assignment] self._atransform = transform
func_for_name = transform func_for_name = transform
elif inspect.isgeneratorfunction(transform): elif inspect.isgeneratorfunction(transform):
self._transform = transform self._transform = transform
@ -4211,7 +4209,7 @@ class RunnableGenerator(Runnable[Input, Output]):
input, input,
self._transform, # type: ignore[arg-type] self._transform, # type: ignore[arg-type]
config, config,
**kwargs, # type: ignore[arg-type] **kwargs,
) )
@override @override
@ -4815,7 +4813,7 @@ class RunnableLambda(Runnable[Input, Output]):
if inspect.isgeneratorfunction(self.func): if inspect.isgeneratorfunction(self.func):
output: Optional[Output] = None output: Optional[Output] = None
for chunk in call_func_with_variable_args( for chunk in call_func_with_variable_args(
self.func, cast("Input", final), config, run_manager, **kwargs self.func, final, config, run_manager, **kwargs
): ):
yield chunk yield chunk
if output is None: if output is None:
@ -4827,7 +4825,7 @@ class RunnableLambda(Runnable[Input, Output]):
output = chunk output = chunk
else: else:
output = call_func_with_variable_args( output = call_func_with_variable_args(
self.func, cast("Input", final), config, run_manager, **kwargs self.func, final, config, run_manager, **kwargs
) )
# If the output is a Runnable, use its stream output # If the output is a Runnable, use its stream output
@ -4936,7 +4934,7 @@ class RunnableLambda(Runnable[Input, Output]):
"AsyncIterator[Output]", "AsyncIterator[Output]",
acall_func_with_variable_args( acall_func_with_variable_args(
cast("Callable", afunc), cast("Callable", afunc),
cast("Input", final), final,
config, config,
run_manager, run_manager,
**kwargs, **kwargs,
@ -4953,7 +4951,7 @@ class RunnableLambda(Runnable[Input, Output]):
else: else:
output = await acall_func_with_variable_args( output = await acall_func_with_variable_args(
cast("Callable", afunc), cast("Callable", afunc),
cast("Input", final), final,
config, config,
run_manager, run_manager,
**kwargs, **kwargs,

View File

@ -114,7 +114,7 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
_branches = [] _branches = []
for branch in branches[:-1]: for branch in branches[:-1]:
if not isinstance(branch, (tuple, list)): # type: ignore[arg-type] if not isinstance(branch, (tuple, list)):
msg = ( msg = (
f"RunnableBranch branches must be " f"RunnableBranch branches must be "
f"tuples or lists, not {type(branch)}" f"tuples or lists, not {type(branch)}"

View File

@ -10,7 +10,6 @@ from typing import (
Any, Any,
Optional, Optional,
Union, Union,
cast,
) )
from pydantic import BaseModel, ConfigDict from pydantic import BaseModel, ConfigDict
@ -183,7 +182,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
for runnable in self.runnables: for runnable in self.runnables:
try: try:
if self.exception_key and last_error is not None: if self.exception_key and last_error is not None:
input[self.exception_key] = last_error input[self.exception_key] = last_error # type: ignore[index]
child_config = patch_config(config, callbacks=run_manager.get_child()) child_config = patch_config(config, callbacks=run_manager.get_child())
with set_config_context(child_config) as context: with set_config_context(child_config) as context:
output = context.run( output = context.run(
@ -237,7 +236,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
for runnable in self.runnables: for runnable in self.runnables:
try: try:
if self.exception_key and last_error is not None: if self.exception_key and last_error is not None:
input[self.exception_key] = last_error input[self.exception_key] = last_error # type: ignore[index]
child_config = patch_config(config, callbacks=run_manager.get_child()) child_config = patch_config(config, callbacks=run_manager.get_child())
with set_config_context(child_config) as context: with set_config_context(child_config) as context:
coro = context.run(runnable.ainvoke, input, config, **kwargs) coro = context.run(runnable.ainvoke, input, config, **kwargs)
@ -328,12 +327,12 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
if not return_exceptions: if not return_exceptions:
first_to_raise = first_to_raise or output first_to_raise = first_to_raise or output
else: else:
handled_exceptions[i] = cast("BaseException", output) handled_exceptions[i] = output
run_again.pop(i) run_again.pop(i)
elif isinstance(output, self.exceptions_to_handle): elif isinstance(output, self.exceptions_to_handle):
if self.exception_key: if self.exception_key:
input[self.exception_key] = output # type: ignore[index] input[self.exception_key] = output # type: ignore[index]
handled_exceptions[i] = cast("BaseException", output) handled_exceptions[i] = output
else: else:
run_managers[i].on_chain_end(output) run_managers[i].on_chain_end(output)
to_return[i] = output to_return[i] = output
@ -425,12 +424,12 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
if not return_exceptions: if not return_exceptions:
first_to_raise = first_to_raise or output first_to_raise = first_to_raise or output
else: else:
handled_exceptions[i] = cast("BaseException", output) handled_exceptions[i] = output
run_again.pop(i) run_again.pop(i)
elif isinstance(output, self.exceptions_to_handle): elif isinstance(output, self.exceptions_to_handle):
if self.exception_key: if self.exception_key:
input[self.exception_key] = output # type: ignore[index] input[self.exception_key] = output # type: ignore[index]
handled_exceptions[i] = cast("BaseException", output) handled_exceptions[i] = output
else: else:
to_return[i] = output to_return[i] = output
await run_managers[i].on_chain_end(output) await run_managers[i].on_chain_end(output)
@ -482,7 +481,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
for runnable in self.runnables: for runnable in self.runnables:
try: try:
if self.exception_key and last_error is not None: if self.exception_key and last_error is not None:
input[self.exception_key] = last_error input[self.exception_key] = last_error # type: ignore[index]
child_config = patch_config(config, callbacks=run_manager.get_child()) child_config = patch_config(config, callbacks=run_manager.get_child())
with set_config_context(child_config) as context: with set_config_context(child_config) as context:
stream = context.run( stream = context.run(
@ -546,7 +545,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
for runnable in self.runnables: for runnable in self.runnables:
try: try:
if self.exception_key and last_error is not None: if self.exception_key and last_error is not None:
input[self.exception_key] = last_error input[self.exception_key] = last_error # type: ignore[index]
child_config = patch_config(config, callbacks=run_manager.get_child()) child_config = patch_config(config, callbacks=run_manager.get_child())
with set_config_context(child_config) as context: with set_config_context(child_config) as context:
stream = runnable.astream( stream = runnable.astream(
@ -574,7 +573,7 @@ class RunnableWithFallbacks(RunnableSerializable[Input, Output]):
async for chunk in stream: async for chunk in stream:
yield chunk yield chunk
try: try:
output = output + chunk # type: ignore[operator] output = output + chunk
except TypeError: except TypeError:
output = None output = None
except BaseException as e: except BaseException as e:

View File

@ -288,7 +288,7 @@ class Graph:
"target": stable_node_ids[edge.target], "target": stable_node_ids[edge.target],
} }
if edge.data is not None: if edge.data is not None:
edge_dict["data"] = edge.data edge_dict["data"] = edge.data # type: ignore[assignment]
if edge.conditional: if edge.conditional:
edge_dict["conditional"] = True edge_dict["conditional"] = True
edges.append(edge_dict) edges.append(edge_dict)

View File

@ -167,9 +167,9 @@ def _build_sugiyama_layout(
vertices: Mapping[str, str], edges: Sequence[LangEdge] vertices: Mapping[str, str], edges: Sequence[LangEdge]
) -> Any: ) -> Any:
try: try:
from grandalf.graphs import Edge, Graph, Vertex # type: ignore[import] from grandalf.graphs import Edge, Graph, Vertex # type: ignore[import-untyped]
from grandalf.layouts import SugiyamaLayout # type: ignore[import] from grandalf.layouts import SugiyamaLayout # type: ignore[import-untyped]
from grandalf.routing import ( # type: ignore[import] from grandalf.routing import ( # type: ignore[import-untyped]
EdgeViewer, EdgeViewer,
route_with_lines, route_with_lines,
) )

View File

@ -305,7 +305,7 @@ async def _render_mermaid_using_pyppeteer(
) -> bytes: ) -> bytes:
"""Renders Mermaid graph using Pyppeteer.""" """Renders Mermaid graph using Pyppeteer."""
try: try:
from pyppeteer import launch # type: ignore[import] from pyppeteer import launch # type: ignore[import-not-found]
except ImportError as e: except ImportError as e:
msg = "Install Pyppeteer to use the Pyppeteer method: `pip install pyppeteer`." msg = "Install Pyppeteer to use the Pyppeteer method: `pip install pyppeteer`."
raise ImportError(msg) from e raise ImportError(msg) from e
@ -377,7 +377,7 @@ def _render_mermaid_using_api(
) -> bytes: ) -> bytes:
"""Renders Mermaid graph using the Mermaid.INK API.""" """Renders Mermaid graph using the Mermaid.INK API."""
try: try:
import requests # type: ignore[import] import requests
except ImportError as e: except ImportError as e:
msg = ( msg = (
"Install the `requests` module to use the Mermaid.INK API: " "Install the `requests` module to use the Mermaid.INK API: "

View File

@ -135,7 +135,7 @@ class PngDrawer:
:param output_path: The path to save the PNG. If None, PNG bytes are returned. :param output_path: The path to save the PNG. If None, PNG bytes are returned.
""" """
try: try:
import pygraphviz as pgv # type: ignore[import] import pygraphviz as pgv # type: ignore[import-not-found]
except ImportError as exc: except ImportError as exc:
msg = "Install pygraphviz to draw graphs: `pip install pygraphviz`." msg = "Install pygraphviz to draw graphs: `pip install pygraphviz`."
raise ImportError(msg) from exc raise ImportError(msg) from exc

View File

@ -388,7 +388,7 @@ class RunnableWithMessageHistory(RunnableBindingBase):
module_name=self.__class__.__module__, module_name=self.__class__.__module__,
root=(Sequence[BaseMessage], ...), root=(Sequence[BaseMessage], ...),
) )
return create_model_v2( # type: ignore[call-overload] return create_model_v2(
"RunnableWithChatHistoryInput", "RunnableWithChatHistoryInput",
field_definitions=fields, field_definitions=fields,
module_name=self.__class__.__module__, module_name=self.__class__.__module__,

View File

@ -455,9 +455,7 @@ class RunnableAssign(RunnableSerializable[dict[str, Any], dict[str, Any]]):
for name, field_info in map_output_schema.model_fields.items(): for name, field_info in map_output_schema.model_fields.items():
fields[name] = (field_info.annotation, field_info.default) fields[name] = (field_info.annotation, field_info.default)
return create_model_v2( # type: ignore[call-overload] return create_model_v2("RunnableAssignOutput", field_definitions=fields)
"RunnableAssignOutput", field_definitions=fields
)
if not issubclass(map_output_schema, RootModel): if not issubclass(map_output_schema, RootModel):
# ie. only map output is a dict # ie. only map output is a dict
# ie. input type is either unknown or inferred incorrectly # ie. input type is either unknown or inferred incorrectly

View File

@ -20,8 +20,9 @@ from tenacity import (
) )
from typing_extensions import TypedDict, override from typing_extensions import TypedDict, override
from langchain_core.runnables.base import Input, Output, RunnableBindingBase from langchain_core.runnables.base import RunnableBindingBase
from langchain_core.runnables.config import RunnableConfig, patch_config from langchain_core.runnables.config import RunnableConfig, patch_config
from langchain_core.runnables.utils import Input, Output
if TYPE_CHECKING: if TYPE_CHECKING:
from langchain_core.callbacks.manager import ( from langchain_core.callbacks.manager import (

View File

@ -17,8 +17,6 @@ from pydantic import ConfigDict
from typing_extensions import TypedDict, override from typing_extensions import TypedDict, override
from langchain_core.runnables.base import ( from langchain_core.runnables.base import (
Input,
Output,
Runnable, Runnable,
RunnableSerializable, RunnableSerializable,
coerce_to_runnable, coerce_to_runnable,
@ -30,6 +28,8 @@ from langchain_core.runnables.config import (
) )
from langchain_core.runnables.utils import ( from langchain_core.runnables.utils import (
ConfigurableFieldSpec, ConfigurableFieldSpec,
Input,
Output,
gather_with_concurrency, gather_with_concurrency,
get_unique_config_specs, get_unique_config_specs,
) )

View File

@ -141,7 +141,7 @@ def coro_with_context(
The coroutine with the context. The coroutine with the context.
""" """
if asyncio_accepts_context(): if asyncio_accepts_context():
return asyncio.create_task(coro, context=context) # type: ignore[arg-type,call-arg] return asyncio.create_task(coro, context=context) # type: ignore[arg-type,call-arg,unused-ignore]
if create_task: if create_task:
return asyncio.create_task(coro) # type: ignore[arg-type] return asyncio.create_task(coro) # type: ignore[arg-type]
return coro return coro

View File

@ -132,9 +132,7 @@ class Tool(BaseTool):
self, name: str, func: Optional[Callable], description: str, **kwargs: Any self, name: str, func: Optional[Callable], description: str, **kwargs: Any
) -> None: ) -> None:
"""Initialize tool.""" """Initialize tool."""
super().__init__( # type: ignore[call-arg] super().__init__(name=name, func=func, description=description, **kwargs)
name=name, func=func, description=description, **kwargs
)
@classmethod @classmethod
def from_function( def from_function(

View File

@ -162,7 +162,7 @@ class EvaluatorCallbackHandler(BaseTracer):
if isinstance(results, EvaluationResult): if isinstance(results, EvaluationResult):
results_ = [results] results_ = [results]
elif isinstance(results, dict) and "results" in results: elif isinstance(results, dict) and "results" in results:
results_ = cast("list[EvaluationResult]", results["results"]) results_ = results["results"]
else: else:
msg = ( msg = (
f"Invalid evaluation result type {type(results)}." f"Invalid evaluation result type {type(results)}."

View File

@ -787,8 +787,6 @@ async def _astream_events_implementation_v1(
root_metadata = config.get("metadata", {}) root_metadata = config.get("metadata", {})
root_name = config.get("run_name", runnable.get_name()) root_name = config.get("run_name", runnable.get_name())
# Ignoring mypy complaint about too many different union combinations
# This arises because many of the argument types are unions
async for log in _astream_log_implementation( async for log in _astream_log_implementation(
runnable, runnable,
input, input,

View File

@ -17,7 +17,7 @@ from typing import (
overload, overload,
) )
import jsonpatch # type: ignore[import] import jsonpatch # type: ignore[import-untyped]
from typing_extensions import NotRequired, TypedDict, override from typing_extensions import NotRequired, TypedDict, override
from langchain_core.load import dumps from langchain_core.load import dumps
@ -618,7 +618,7 @@ async def _astream_log_implementation(
The implementation has been factored out (at least temporarily) as both The implementation has been factored out (at least temporarily) as both
astream_log and astream_events relies on it. astream_log and astream_events relies on it.
""" """
import jsonpatch # type: ignore[import] import jsonpatch
from langchain_core.callbacks.base import BaseCallbackManager from langchain_core.callbacks.base import BaseCallbackManager
from langchain_core.tracers.log_stream import ( from langchain_core.tracers.log_stream import (

View File

@ -313,7 +313,7 @@ def _convert_any_typed_dicts_to_pydantic(
subscriptable_origin = _py_38_safe_origin(origin) subscriptable_origin = _py_38_safe_origin(origin)
type_args = tuple( type_args = tuple(
_convert_any_typed_dicts_to_pydantic(arg, depth=depth + 1, visited=visited) _convert_any_typed_dicts_to_pydantic(arg, depth=depth + 1, visited=visited)
for arg in type_args # type: ignore[index] for arg in type_args
) )
return subscriptable_origin[type_args] # type: ignore[index] return subscriptable_origin[type_args] # type: ignore[index]
return type_ return type_

View File

@ -383,7 +383,7 @@ if IS_PYDANTIC_V2:
) -> Union[dict[str, FieldInfoV2], dict[str, FieldInfoV1]]: ) -> Union[dict[str, FieldInfoV2], dict[str, FieldInfoV1]]:
"""Get the field names of a Pydantic model.""" """Get the field names of a Pydantic model."""
if hasattr(model, "model_fields"): if hasattr(model, "model_fields"):
return model.model_fields # type: ignore[call-overload,arg-type] return model.model_fields
if hasattr(model, "__fields__"): if hasattr(model, "__fields__"):
return model.__fields__ # type: ignore[return-value] return model.__fields__ # type: ignore[return-value]
@ -597,7 +597,7 @@ def create_model_v2(
Returns: Returns:
Type[BaseModel]: The created model. Type[BaseModel]: The created model.
""" """
field_definitions = cast("dict[str, Any]", field_definitions or {}) # type: ignore[no-redef] field_definitions = field_definitions or {}
if root: if root:
if field_definitions: if field_definitions:
@ -635,7 +635,7 @@ def create_model_v2(
if name.startswith("model"): if name.startswith("model"):
capture_warnings = True capture_warnings = True
with warnings.catch_warnings() if capture_warnings else nullcontext(): # type: ignore[attr-defined] with warnings.catch_warnings() if capture_warnings else nullcontext():
if capture_warnings: if capture_warnings:
warnings.filterwarnings(action="ignore") warnings.filterwarnings(action="ignore")
try: try:

View File

@ -31,10 +31,9 @@ lint = [
"ruff<0.12.0,>=0.11.2", "ruff<0.12.0,>=0.11.2",
] ]
typing = [ typing = [
"mypy<1.11,>=1.10", "mypy<1.16,>=1.15",
"types-pyyaml<7.0.0.0,>=6.0.12.2", "types-pyyaml<7.0.0.0,>=6.0.12.2",
"types-requests<3.0.0.0,>=2.28.11.5", "types-requests<3.0.0.0,>=2.28.11.5",
"types-jinja2<3.0.0,>=2.11.9",
"langchain-text-splitters", "langchain-text-splitters",
] ]
dev = [ dev = [
@ -68,11 +67,16 @@ langchain-text-splitters = { path = "../text-splitters" }
[tool.mypy] [tool.mypy]
exclude = [ "notebooks", "examples", "example_data", "langchain_core/pydantic", "tests/unit_tests/utils/test_function_calling.py",] strict = "True"
disallow_untyped_defs = "True" strict_bytes = "True"
[[tool.mypy.overrides]] enable_error_code = "deprecated"
module = [ "numpy", "pytest",] report_deprecated_as_note = "True"
ignore_missing_imports = true
# TODO: activate for 'strict' checking
disallow_any_generics = "False"
warn_return_any = "False"
strict_equality = "False"
[tool.ruff] [tool.ruff]
target-version = "py39" target-version = "py39"

View File

@ -49,7 +49,7 @@ async def test_async_callbacks_in_sync(benchmark: BenchmarkFixture) -> None:
infinite_cycle = cycle([AIMessage(content=" ".join(["hello", "goodbye"] * 500))]) infinite_cycle = cycle([AIMessage(content=" ".join(["hello", "goodbye"] * 500))])
model = GenericFakeChatModel(messages=infinite_cycle) model = GenericFakeChatModel(messages=infinite_cycle)
@benchmark @benchmark # type: ignore[misc]
def sync_callbacks() -> None: def sync_callbacks() -> None:
for _ in range(5): for _ in range(5):
for _ in model.stream("meow", {"callbacks": [MyCustomAsyncHandler()]}): for _ in model.stream("meow", {"callbacks": [MyCustomAsyncHandler()]}):

View File

@ -49,6 +49,6 @@ from pytest_benchmark.fixture import BenchmarkFixture # type: ignore[import-unt
) )
@pytest.mark.benchmark @pytest.mark.benchmark
def test_import_time(benchmark: BenchmarkFixture, import_path: str) -> None: def test_import_time(benchmark: BenchmarkFixture, import_path: str) -> None:
@benchmark @benchmark # type: ignore[misc]
def import_in_subprocess() -> None: def import_in_subprocess() -> None:
subprocess.run([sys.executable, "-c", import_path], check=False) subprocess.run([sys.executable, "-c", import_path], check=False)

View File

@ -1,5 +1,4 @@
from langchain_core.callbacks.base import BaseCallbackHandler from langchain_core.callbacks.base import BaseCallbackHandler, BaseCallbackManager
from langchain_core.callbacks.manager import BaseCallbackManager
def test_remove_handler() -> None: def test_remove_handler() -> None:

View File

@ -1,5 +1,5 @@
from collections.abc import Iterable from collections.abc import Iterable
from typing import Any, Optional, cast from typing import Any, Optional
from typing_extensions import override from typing_extensions import override
@ -132,7 +132,7 @@ def test_from_examples() -> None:
assert selector.vectorstore_kwargs == {"vs_foo": "vs_bar"} assert selector.vectorstore_kwargs == {"vs_foo": "vs_bar"}
assert isinstance(selector.vectorstore, DummyVectorStore) assert isinstance(selector.vectorstore, DummyVectorStore)
vector_store = cast("DummyVectorStore", selector.vectorstore) vector_store = selector.vectorstore
assert vector_store.embeddings is embeddings assert vector_store.embeddings is embeddings
assert vector_store.init_arg == "some_init_arg" assert vector_store.init_arg == "some_init_arg"
assert vector_store.texts == ["bar"] assert vector_store.texts == ["bar"]
@ -158,7 +158,7 @@ async def test_afrom_examples() -> None:
assert selector.vectorstore_kwargs == {"vs_foo": "vs_bar"} assert selector.vectorstore_kwargs == {"vs_foo": "vs_bar"}
assert isinstance(selector.vectorstore, DummyVectorStore) assert isinstance(selector.vectorstore, DummyVectorStore)
vector_store = cast("DummyVectorStore", selector.vectorstore) vector_store = selector.vectorstore
assert vector_store.embeddings is embeddings assert vector_store.embeddings is embeddings
assert vector_store.init_arg == "some_init_arg" assert vector_store.init_arg == "some_init_arg"
assert vector_store.texts == ["bar"] assert vector_store.texts == ["bar"]
@ -212,7 +212,7 @@ def test_mmr_from_examples() -> None:
assert selector.vectorstore_kwargs == {"vs_foo": "vs_bar"} assert selector.vectorstore_kwargs == {"vs_foo": "vs_bar"}
assert isinstance(selector.vectorstore, DummyVectorStore) assert isinstance(selector.vectorstore, DummyVectorStore)
vector_store = cast("DummyVectorStore", selector.vectorstore) vector_store = selector.vectorstore
assert vector_store.embeddings is embeddings assert vector_store.embeddings is embeddings
assert vector_store.init_arg == "some_init_arg" assert vector_store.init_arg == "some_init_arg"
assert vector_store.texts == ["bar"] assert vector_store.texts == ["bar"]
@ -240,7 +240,7 @@ async def test_mmr_afrom_examples() -> None:
assert selector.vectorstore_kwargs == {"vs_foo": "vs_bar"} assert selector.vectorstore_kwargs == {"vs_foo": "vs_bar"}
assert isinstance(selector.vectorstore, DummyVectorStore) assert isinstance(selector.vectorstore, DummyVectorStore)
vector_store = cast("DummyVectorStore", selector.vectorstore) vector_store = selector.vectorstore
assert vector_store.embeddings is embeddings assert vector_store.embeddings is embeddings
assert vector_store.init_arg == "some_init_arg" assert vector_store.init_arg == "some_init_arg"
assert vector_store.texts == ["bar"] assert vector_store.texts == ["bar"]

View File

@ -1,5 +1,5 @@
from collections.abc import AsyncIterator, Iterable from collections.abc import AsyncIterator, Iterable
from typing import TypeVar, cast from typing import TypeVar
from langchain_core.output_parsers.list import ( from langchain_core.output_parsers.list import (
CommaSeparatedListOutputParser, CommaSeparatedListOutputParser,
@ -101,7 +101,7 @@ def test_numbered_list() -> None:
(text2, ["apple", "banana", "cherry"]), (text2, ["apple", "banana", "cherry"]),
(text3, []), (text3, []),
]: ]:
expectedlist = [[a] for a in cast("list[str]", expected)] expectedlist = [[a] for a in expected]
assert parser.parse(text) == expected assert parser.parse(text) == expected
assert add(parser.transform(t for t in text)) == (expected or None) assert add(parser.transform(t for t in text)) == (expected or None)
assert list(parser.transform(t for t in text)) == expectedlist assert list(parser.transform(t for t in text)) == expectedlist
@ -137,7 +137,7 @@ def test_markdown_list() -> None:
(text2, ["apple", "banana", "cherry"]), (text2, ["apple", "banana", "cherry"]),
(text3, []), (text3, []),
]: ]:
expectedlist = [[a] for a in cast("list[str]", expected)] expectedlist = [[a] for a in expected]
assert parser.parse(text) == expected assert parser.parse(text) == expected
assert add(parser.transform(t for t in text)) == (expected or None) assert add(parser.transform(t for t in text)) == (expected or None)
assert list(parser.transform(t for t in text)) == expectedlist assert list(parser.transform(t for t in text)) == expectedlist
@ -240,7 +240,7 @@ async def test_numbered_list_async() -> None:
(text2, ["apple", "banana", "cherry"]), (text2, ["apple", "banana", "cherry"]),
(text3, []), (text3, []),
]: ]:
expectedlist = [[a] for a in cast("list[str]", expected)] expectedlist = [[a] for a in expected]
assert await parser.aparse(text) == expected assert await parser.aparse(text) == expected
assert await aadd(parser.atransform(aiter_from_iter(t for t in text))) == ( assert await aadd(parser.atransform(aiter_from_iter(t for t in text))) == (
expected or None expected or None
@ -283,7 +283,7 @@ async def test_markdown_list_async() -> None:
(text2, ["apple", "banana", "cherry"]), (text2, ["apple", "banana", "cherry"]),
(text3, []), (text3, []),
]: ]:
expectedlist = [[a] for a in cast("list[str]", expected)] expectedlist = [[a] for a in expected]
assert await parser.aparse(text) == expected assert await parser.aparse(text) == expected
assert await aadd(parser.atransform(aiter_from_iter(t for t in text))) == ( assert await aadd(parser.atransform(aiter_from_iter(t for t in text))) == (
expected or None expected or None

View File

@ -578,7 +578,7 @@ def test_parse_with_different_pydantic_2_proper() -> None:
# Can't get pydantic to work here due to the odd typing of tryig to support # Can't get pydantic to work here due to the odd typing of tryig to support
# both v1 and v2 in the same codebase. # both v1 and v2 in the same codebase.
parser = PydanticToolsParser(tools=[Forecast]) # type: ignore[list-item] parser = PydanticToolsParser(tools=[Forecast])
message = AIMessage( message = AIMessage(
content="", content="",
tool_calls=[ tool_calls=[
@ -613,7 +613,7 @@ def test_parse_with_different_pydantic_1_proper() -> None:
# Can't get pydantic to work here due to the odd typing of tryig to support # Can't get pydantic to work here due to the odd typing of tryig to support
# both v1 and v2 in the same codebase. # both v1 and v2 in the same codebase.
parser = PydanticToolsParser(tools=[Forecast]) # type: ignore[list-item] parser = PydanticToolsParser(tools=[Forecast])
message = AIMessage( message = AIMessage(
content="", content="",
tool_calls=[ tool_calls=[

View File

@ -6,7 +6,7 @@ from typing import Any, Union, cast
import pytest import pytest
from packaging import version from packaging import version
from pydantic import ValidationError from pydantic import ValidationError
from syrupy import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from langchain_core._api.deprecation import ( from langchain_core._api.deprecation import (
LangChainPendingDeprecationWarning, LangChainPendingDeprecationWarning,
@ -15,6 +15,7 @@ from langchain_core.load import dumpd, load
from langchain_core.messages import ( from langchain_core.messages import (
AIMessage, AIMessage,
BaseMessage, BaseMessage,
ChatMessage,
HumanMessage, HumanMessage,
SystemMessage, SystemMessage,
get_buffer_string, get_buffer_string,
@ -24,7 +25,6 @@ from langchain_core.prompts import PromptTemplate
from langchain_core.prompts.chat import ( from langchain_core.prompts.chat import (
AIMessagePromptTemplate, AIMessagePromptTemplate,
BaseMessagePromptTemplate, BaseMessagePromptTemplate,
ChatMessage,
ChatMessagePromptTemplate, ChatMessagePromptTemplate,
ChatPromptTemplate, ChatPromptTemplate,
HumanMessagePromptTemplate, HumanMessagePromptTemplate,
@ -82,7 +82,7 @@ def chat_prompt_template(
"""Create a chat prompt template.""" """Create a chat prompt template."""
return ChatPromptTemplate( return ChatPromptTemplate(
input_variables=["foo", "bar", "context"], input_variables=["foo", "bar", "context"],
messages=messages, # type: ignore[arg-type] messages=messages,
) )
@ -403,12 +403,12 @@ def test_chat_invalid_input_variables_extra() -> None:
), ),
): ):
ChatPromptTemplate( ChatPromptTemplate(
messages=messages, # type: ignore[arg-type] messages=messages,
input_variables=["foo"], input_variables=["foo"],
validate_template=True, # type: ignore[arg-type] validate_template=True,
) )
assert ( assert (
ChatPromptTemplate(messages=messages, input_variables=["foo"]).input_variables # type: ignore[arg-type] ChatPromptTemplate(messages=messages, input_variables=["foo"]).input_variables
== [] == []
) )
@ -420,19 +420,19 @@ def test_chat_invalid_input_variables_missing() -> None:
match=re.escape("Got mismatched input_variables. Expected: {'foo'}. Got: []"), match=re.escape("Got mismatched input_variables. Expected: {'foo'}. Got: []"),
): ):
ChatPromptTemplate( ChatPromptTemplate(
messages=messages, # type: ignore[arg-type] messages=messages,
input_variables=[], input_variables=[],
validate_template=True, # type: ignore[arg-type] validate_template=True,
) )
assert ChatPromptTemplate( assert ChatPromptTemplate(
messages=messages, # type: ignore[arg-type] messages=messages,
input_variables=[], # type: ignore[arg-type] input_variables=[],
).input_variables == ["foo"] ).input_variables == ["foo"]
def test_infer_variables() -> None: def test_infer_variables() -> None:
messages = [HumanMessagePromptTemplate.from_template("{foo}")] messages = [HumanMessagePromptTemplate.from_template("{foo}")]
prompt = ChatPromptTemplate(messages=messages) # type: ignore[arg-type, call-arg] prompt = ChatPromptTemplate(messages=messages)
assert prompt.input_variables == ["foo"] assert prompt.input_variables == ["foo"]
@ -443,7 +443,7 @@ def test_chat_valid_with_partial_variables() -> None:
) )
] ]
prompt = ChatPromptTemplate( prompt = ChatPromptTemplate(
messages=messages, # type: ignore[arg-type] messages=messages,
input_variables=["question", "context"], input_variables=["question", "context"],
partial_variables={"formatins": "some structure"}, partial_variables={"formatins": "some structure"},
) )
@ -457,9 +457,9 @@ def test_chat_valid_infer_variables() -> None:
"Do something with {question} using {context} giving it like {formatins}" "Do something with {question} using {context} giving it like {formatins}"
) )
] ]
prompt = ChatPromptTemplate( # type: ignore[call-arg] prompt = ChatPromptTemplate(
messages=messages, # type: ignore[arg-type] messages=messages,
partial_variables={"formatins": "some structure"}, # type: ignore[arg-type] partial_variables={"formatins": "some structure"},
) )
assert set(prompt.input_variables) == {"question", "context"} assert set(prompt.input_variables) == {"question", "context"}
assert prompt.partial_variables == {"formatins": "some structure"} assert prompt.partial_variables == {"formatins": "some structure"}

View File

@ -6,7 +6,7 @@ from unittest import mock
import pytest import pytest
from packaging import version from packaging import version
from syrupy import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from langchain_core.prompts.prompt import PromptTemplate from langchain_core.prompts.prompt import PromptTemplate
from langchain_core.prompts.string import PromptTemplateFormat from langchain_core.prompts.string import PromptTemplateFormat

View File

@ -8,7 +8,7 @@ from typing import (
import pytest import pytest
from pydantic import BaseModel from pydantic import BaseModel
from syrupy import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from typing_extensions import override from typing_extensions import override
from langchain_core.callbacks import CallbackManagerForLLMRun from langchain_core.callbacks import CallbackManagerForLLMRun

View File

@ -2,7 +2,7 @@ from typing import Any, Optional
from packaging import version from packaging import version
from pydantic import BaseModel from pydantic import BaseModel
from syrupy import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from typing_extensions import override from typing_extensions import override
from langchain_core.language_models import FakeListLLM from langchain_core.language_models import FakeListLLM
@ -10,7 +10,8 @@ from langchain_core.output_parsers.list import CommaSeparatedListOutputParser
from langchain_core.output_parsers.string import StrOutputParser from langchain_core.output_parsers.string import StrOutputParser
from langchain_core.output_parsers.xml import XMLOutputParser from langchain_core.output_parsers.xml import XMLOutputParser
from langchain_core.prompts.prompt import PromptTemplate from langchain_core.prompts.prompt import PromptTemplate
from langchain_core.runnables.base import Runnable, RunnableConfig from langchain_core.runnables import RunnableConfig
from langchain_core.runnables.base import Runnable
from langchain_core.runnables.graph import Edge, Graph, Node from langchain_core.runnables.graph import Edge, Graph, Node
from langchain_core.runnables.graph_mermaid import _escape_node_label from langchain_core.runnables.graph_mermaid import _escape_node_label
from langchain_core.utils.pydantic import ( from langchain_core.utils.pydantic import (

View File

@ -40,4 +40,6 @@ def test_all_imports() -> None:
def test_imports_for_specific_funcs() -> None: def test_imports_for_specific_funcs() -> None:
"""Test that a few specific imports in more internal namespaces.""" """Test that a few specific imports in more internal namespaces."""
# create_model implementation has been moved to langchain_core.utils.pydantic # create_model implementation has been moved to langchain_core.utils.pydantic
from langchain_core.runnables.utils import create_model # noqa: F401 from langchain_core.runnables.utils import ( # type: ignore[attr-defined] # noqa: F401
create_model,
)

View File

@ -20,7 +20,7 @@ from freezegun import freeze_time
from packaging import version from packaging import version
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from syrupy import SnapshotAssertion from syrupy.assertion import SnapshotAssertion
from typing_extensions import TypedDict, override from typing_extensions import TypedDict, override
from langchain_core.callbacks.manager import ( from langchain_core.callbacks.manager import (
@ -557,7 +557,7 @@ def test_lambda_schemas(snapshot: SnapshotAssertion) -> None:
} }
second_lambda = lambda x, y: (x["hello"], x["bye"], y["bah"]) # noqa: E731 second_lambda = lambda x, y: (x["hello"], x["bye"], y["bah"]) # noqa: E731
assert RunnableLambda(second_lambda).get_input_jsonschema() == { # type: ignore[arg-type] assert RunnableLambda(second_lambda).get_input_jsonschema() == {
"title": "RunnableLambdaInput", "title": "RunnableLambdaInput",
"type": "object", "type": "object",
"properties": {"hello": {"title": "Hello"}, "bye": {"title": "Bye"}}, "properties": {"hello": {"title": "Hello"}, "bye": {"title": "Bye"}},
@ -1012,7 +1012,7 @@ def test_passthrough_tap(mocker: MockerFixture) -> None:
seq: Runnable = RunnablePassthrough(mock) | fake | RunnablePassthrough(mock) seq: Runnable = RunnablePassthrough(mock) | fake | RunnablePassthrough(mock)
assert seq.invoke("hello", my_kwarg="value") == 5 # type: ignore[call-arg] assert seq.invoke("hello", my_kwarg="value") == 5
assert mock.call_args_list == [ assert mock.call_args_list == [
mocker.call("hello", my_kwarg="value"), mocker.call("hello", my_kwarg="value"),
mocker.call(5), mocker.call(5),
@ -4488,7 +4488,7 @@ def test_runnable_branch_invoke() -> None:
branch = RunnableBranch[int, int]( branch = RunnableBranch[int, int](
(lambda x: x > 100, raise_value_error), (lambda x: x > 100, raise_value_error),
# mypy cannot infer types from the lambda # mypy cannot infer types from the lambda
(lambda x: x > 0 and x < 5, lambda x: x + 1), # type: ignore[misc] (lambda x: x > 0 and x < 5, lambda x: x + 1),
(lambda x: x > 5, lambda x: x * 10), (lambda x: x > 5, lambda x: x * 10),
lambda x: x - 1, lambda x: x - 1,
) )

View File

@ -2759,9 +2759,7 @@ async def test_custom_event_root_dispatch_with_in_tool() -> None:
return x + 1 return x + 1
# Ignoring type due to @tool not returning correct type annotations # Ignoring type due to @tool not returning correct type annotations
events = await _collect_events( events = await _collect_events(foo.astream_events({"x": 2}, version="v2"))
foo.astream_events({"x": 2}, version="v2") # type: ignore[attr-defined]
)
_assert_events_equal_allow_superset_metadata( _assert_events_equal_allow_superset_metadata(
events, events,
[ [

View File

@ -163,13 +163,13 @@ async def test_config_traceable_async_handoff() -> None:
def my_great_grandchild_function(a: int) -> int: def my_great_grandchild_function(a: int) -> int:
return my_great_great_grandchild_function(a) return my_great_great_grandchild_function(a)
@RunnableLambda # type: ignore[arg-type,attr-defined] @RunnableLambda # type: ignore[arg-type]
async def my_grandchild_function(a: int) -> int: async def my_grandchild_function(a: int) -> int:
return my_great_grandchild_function.invoke(a) return my_great_grandchild_function.invoke(a)
@traceable @traceable
async def my_child_function(a: int) -> int: async def my_child_function(a: int) -> int:
return await my_grandchild_function.ainvoke(a) * 3 # type: ignore[arg-type,attr-defined] return await my_grandchild_function.ainvoke(a) * 3 # type: ignore[arg-type]
@traceable() @traceable()
async def my_function(a: int) -> int: async def my_function(a: int) -> int:
@ -337,7 +337,7 @@ class TestRunnableSequenceParallelTraceNesting:
assert posts[i]["name"] == name assert posts[i]["name"] == name
dotted_order = posts[i]["dotted_order"] dotted_order = posts[i]["dotted_order"]
if prev_dotted_order is not None and not str( if prev_dotted_order is not None and not str(
expected_parents[name] expected_parents[name] # type: ignore[index]
).startswith("RunnableParallel"): ).startswith("RunnableParallel"):
assert dotted_order > prev_dotted_order, ( assert dotted_order > prev_dotted_order, (
f"{name} not after {name_order[i - 1]}" f"{name} not after {name_order[i - 1]}"

View File

@ -435,8 +435,8 @@ def test_message_chunk_to_message() -> None:
expected = AIMessage( expected = AIMessage(
content="I am", content="I am",
tool_calls=[ tool_calls=[
create_tool_call(name="tool1", args={"a": 1}, id="1"), # type: ignore[arg-type] create_tool_call(name="tool1", args={"a": 1}, id="1"),
create_tool_call(name="tool2", args={}, id="2"), # type: ignore[arg-type] create_tool_call(name="tool2", args={}, id="2"),
], ],
invalid_tool_calls=[ invalid_tool_calls=[
create_invalid_tool_call(name="tool3", args=None, id="3", error=None), create_invalid_tool_call(name="tool3", args=None, id="3", error=None),

View File

@ -907,7 +907,7 @@ def test_validation_error_handling_non_validation_error(
async def _arun(self) -> str: async def _arun(self) -> str:
return "dummy" return "dummy"
_tool = _RaiseNonValidationErrorTool(handle_validation_error=handler) # type: ignore[call-arg] _tool = _RaiseNonValidationErrorTool(handle_validation_error=handler)
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
_tool.run({}) _tool.run({})
@ -972,7 +972,7 @@ async def test_async_validation_error_handling_non_validation_error(
async def _arun(self) -> str: async def _arun(self) -> str:
return "dummy" return "dummy"
_tool = _RaiseNonValidationErrorTool(handle_validation_error=handler) # type: ignore[call-arg] _tool = _RaiseNonValidationErrorTool(handle_validation_error=handler)
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
await _tool.arun({}) await _tool.arun({})
@ -1901,7 +1901,7 @@ def test_args_schema_explicitly_typed() -> None:
# type ignoring here since we're allowing overriding a type # type ignoring here since we're allowing overriding a type
# signature of pydantic.v1.BaseModel with pydantic.BaseModel # signature of pydantic.v1.BaseModel with pydantic.BaseModel
# for pydantic 2! # for pydantic 2!
args_schema: type[BaseModel] = Foo # type: ignore[assignment] args_schema: type[BaseModel] = Foo
def _run(self, *args: Any, **kwargs: Any) -> str: def _run(self, *args: Any, **kwargs: Any) -> str:
return "foo" return "foo"
@ -2157,7 +2157,7 @@ def test_tool_annotations_preserved() -> None:
"""Tool docstring.""" """Tool docstring."""
return "foo" return "foo"
schema = my_tool.get_input_schema() # type: ignore[attr-defined] schema = my_tool.get_input_schema()
func = my_tool.func # type: ignore[attr-defined] func = my_tool.func # type: ignore[attr-defined]

View File

@ -1,4 +1,3 @@
# mypy: disable-error-code="annotation-unchecked"
import sys import sys
import typing import typing
from collections.abc import Iterable, Mapping, MutableMapping, Sequence from collections.abc import Iterable, Mapping, MutableMapping, Sequence
@ -15,12 +14,11 @@ from typing import TypedDict as TypingTypedDict
import pytest import pytest
from pydantic import BaseModel as BaseModelV2Maybe # pydantic: ignore from pydantic import BaseModel as BaseModelV2Maybe # pydantic: ignore
from pydantic import Field as FieldV2Maybe # pydantic: ignore from pydantic import Field as FieldV2Maybe # pydantic: ignore
from typing_extensions import ( from typing_extensions import TypeAlias
TypedDict as ExtensionsTypedDict, from typing_extensions import TypedDict as ExtensionsTypedDict
)
try: try:
from typing import Annotated as TypingAnnotated # type: ignore[attr-defined] from typing import Annotated as TypingAnnotated
except ImportError: except ImportError:
TypingAnnotated = ExtensionsAnnotated TypingAnnotated = ExtensionsAnnotated
@ -387,8 +385,8 @@ def test_convert_to_openai_function(
assert actual == runnable_expected assert actual == runnable_expected
# Test simple Tool # Test simple Tool
def my_function(input_string: str) -> str: def my_function(_: str) -> str:
pass return ""
tool = Tool( tool = Tool(
name="dummy_function", name="dummy_function",
@ -738,20 +736,25 @@ def test_tool_outputs() -> None:
assert not response.tool_calls assert not response.tool_calls
@pytest.mark.parametrize("use_extension_typed_dict", [True, False]) @pytest.mark.parametrize(
@pytest.mark.parametrize("use_extension_annotated", [True, False]) "typed_dict",
[ExtensionsTypedDict, TypingTypedDict],
ids=["typing_extensions.TypedDict", "typing.TypedDict"],
)
@pytest.mark.parametrize(
"annotated",
[ExtensionsAnnotated, TypingAnnotated],
ids=["typing_extensions.Annotated", "typing.Annotated"],
)
def test__convert_typed_dict_to_openai_function( def test__convert_typed_dict_to_openai_function(
*, use_extension_typed_dict: bool, use_extension_annotated: bool typed_dict: TypeAlias, annotated: TypeAlias
) -> None: ) -> None:
typed_dict = ExtensionsTypedDict if use_extension_typed_dict else TypingTypedDict class SubTool(typed_dict): # type: ignore[misc]
annotated = TypingAnnotated if use_extension_annotated else TypingAnnotated
class SubTool(typed_dict):
"""Subtool docstring.""" """Subtool docstring."""
args: annotated[dict[str, Any], {}, "this does bar"] # noqa: F722 args: annotated[dict[str, Any], {}, "this does bar"] # noqa: F722
class Tool(typed_dict): class Tool(typed_dict): # type: ignore[misc]
"""Docstring. """Docstring.
Args: Args:
@ -981,7 +984,7 @@ def test__convert_typed_dict_to_openai_function(
@pytest.mark.parametrize("typed_dict", [ExtensionsTypedDict, TypingTypedDict]) @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): class Tool(typed_dict): # type: ignore[misc]
arg1: typing.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 # Error should be raised since we're using v1 code path here
@ -994,11 +997,12 @@ def test__convert_typed_dict_to_openai_function_fail(typed_dict: type) -> None:
) )
def test_convert_union_type_py_39() -> None: def test_convert_union_type_py_39() -> None:
@tool @tool
def magic_function(input: int | str) -> str: # noqa: FA102 def magic_function(value: int | str) -> str: # type: ignore[syntax,unused-ignore] # noqa: ARG001,FA102
"""Compute a magic function.""" """Compute a magic function."""
return ""
result = convert_to_openai_function(magic_function) result = convert_to_openai_function(magic_function)
assert result["parameters"]["properties"]["input"] == { assert result["parameters"]["properties"]["value"] == {
"anyOf": [{"type": "integer"}, {"type": "string"}] "anyOf": [{"type": "integer"}, {"type": "string"}]
} }

View File

@ -56,7 +56,6 @@ def test_pre_init_decorator_with_more_defaults() -> None:
return v return v
# Try to create an instance of Foo # Try to create an instance of Foo
# nothing is required, but mypy can't track the default for `c`
Foo() Foo()
@ -177,7 +176,7 @@ def test_fields_pydantic_v1() -> None:
x: int x: int
fields = get_fields(Foo) fields = get_fields(Foo)
assert fields == {"x": Foo.model_fields["x"]} # type: ignore[index] assert fields == {"x": Foo.model_fields["x"]}
@pytest.mark.skipif(not IS_PYDANTIC_V2, reason="Only tests Pydantic v2") @pytest.mark.skipif(not IS_PYDANTIC_V2, reason="Only tests Pydantic v2")

View File

@ -980,7 +980,6 @@ test = [
typing = [ typing = [
{ name = "langchain-text-splitters" }, { name = "langchain-text-splitters" },
{ name = "mypy" }, { name = "mypy" },
{ name = "types-jinja2" },
{ name = "types-pyyaml" }, { name = "types-pyyaml" },
{ name = "types-requests" }, { name = "types-requests" },
] ]
@ -1025,8 +1024,7 @@ test = [
test-integration = [] test-integration = []
typing = [ typing = [
{ name = "langchain-text-splitters", directory = "../text-splitters" }, { name = "langchain-text-splitters", directory = "../text-splitters" },
{ name = "mypy", specifier = ">=1.10,<1.11" }, { name = "mypy", specifier = ">=1.15,<1.16" },
{ name = "types-jinja2", specifier = ">=2.11.9,<3.0.0" },
{ name = "types-pyyaml", specifier = ">=6.0.12.2,<7.0.0.0" }, { name = "types-pyyaml", specifier = ">=6.0.12.2,<7.0.0.0" },
{ name = "types-requests", specifier = ">=2.28.11.5,<3.0.0.0" }, { name = "types-requests", specifier = ">=2.28.11.5,<3.0.0.0" },
] ]
@ -1244,36 +1242,46 @@ wheels = [
[[package]] [[package]]
name = "mypy" name = "mypy"
version = "1.10.1" version = "1.15.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "mypy-extensions" }, { name = "mypy-extensions" },
{ name = "tomli", marker = "python_full_version < '3.11'" }, { name = "tomli", marker = "python_full_version < '3.11'" },
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/c7/b9/81e4c6dbb1ec1e72503de3ff2c5fe4b7f224e04613b670f8b9004cd8a4dd/mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0", size = 3022304 } sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/56/24/8a179de3ed98e1882f640d431db25a17fc5813258fded79674e475501f87/mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02", size = 10817694 }, { url = "https://files.pythonhosted.org/packages/68/f8/65a7ce8d0e09b6329ad0c8d40330d100ea343bd4dd04c4f8ae26462d0a17/mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13", size = 10738433 },
{ url = "https://files.pythonhosted.org/packages/f3/80/1675d07cfb4cc12bedcb5bb426f256d8c8da3668cbf300121e39333f0c96/mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7", size = 9975362 }, { url = "https://files.pythonhosted.org/packages/b4/95/9c0ecb8eacfe048583706249439ff52105b3f552ea9c4024166c03224270/mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559", size = 9861472 },
{ url = "https://files.pythonhosted.org/packages/d5/a0/684ebd636f258bdd263b12be46dd4e1ed33ac73a76d590b209c026e3c65f/mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a", size = 12728032 }, { url = "https://files.pythonhosted.org/packages/84/09/9ec95e982e282e20c0d5407bc65031dfd0f0f8ecc66b69538296e06fcbee/mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b", size = 11611424 },
{ url = "https://files.pythonhosted.org/packages/f3/c8/1f881f08e93ea8165113ab0fad490262b0466d0c2616c13c1bb85741ff87/mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9", size = 12797751 }, { url = "https://files.pythonhosted.org/packages/78/13/f7d14e55865036a1e6a0a69580c240f43bc1f37407fe9235c0d4ef25ffb0/mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3", size = 12365450 },
{ url = "https://files.pythonhosted.org/packages/4a/d3/46c81d90576e2e766144c0e436fa397a7387092fe29c6ef964f91d92778d/mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d", size = 9398835 }, { url = "https://files.pythonhosted.org/packages/48/e1/301a73852d40c241e915ac6d7bcd7fedd47d519246db2d7b86b9d7e7a0cb/mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b", size = 12551765 },
{ url = "https://files.pythonhosted.org/packages/38/cf/0645128c6edf70eb9b9687ad42fcb61ea344a7927ed2b78ce2275282fe87/mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a", size = 10740526 }, { url = "https://files.pythonhosted.org/packages/77/ba/c37bc323ae5fe7f3f15a28e06ab012cd0b7552886118943e90b15af31195/mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828", size = 9274701 },
{ url = "https://files.pythonhosted.org/packages/19/c9/10842953066265e6063c41a85bbee3b877501947c970ea84a1db5f11d32e/mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84", size = 9898375 }, { url = "https://files.pythonhosted.org/packages/03/bc/f6339726c627bd7ca1ce0fa56c9ae2d0144604a319e0e339bdadafbbb599/mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", size = 10662338 },
{ url = "https://files.pythonhosted.org/packages/e4/9e/551e897f67c5d67aa1976bc3b4951f297d1daf07250c421bb045b2613350/mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f", size = 12602338 }, { url = "https://files.pythonhosted.org/packages/e2/90/8dcf506ca1a09b0d17555cc00cd69aee402c203911410136cd716559efe7/mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", size = 9787540 },
{ url = "https://files.pythonhosted.org/packages/2b/a4/55e3635253e5fa7051674dd5a67582f08b0ba8823e1fdbf7241ed5b32d4e/mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b", size = 12680741 }, { url = "https://files.pythonhosted.org/packages/05/05/a10f9479681e5da09ef2f9426f650d7b550d4bafbef683b69aad1ba87457/mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", size = 11538051 },
{ url = "https://files.pythonhosted.org/packages/7a/cc/aa881ad051f99915887db0b5de8facc0e224295be22f92178c8f77fd8359/mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e", size = 9393661 }, { url = "https://files.pythonhosted.org/packages/e9/9a/1f7d18b30edd57441a6411fcbc0c6869448d1a4bacbaee60656ac0fc29c8/mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", size = 12286751 },
{ url = "https://files.pythonhosted.org/packages/5d/86/3c3bdaccc3cbd1372acb15667a2c2cb773523a710a22e2748cbda9a7c1e2/mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7", size = 10864022 }, { url = "https://files.pythonhosted.org/packages/72/af/19ff499b6f1dafcaf56f9881f7a965ac2f474f69f6f618b5175b044299f5/mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", size = 12421783 },
{ url = "https://files.pythonhosted.org/packages/ec/05/7c87b26b6a769b70f6c0b8a6daef01fc6f3ae566df89a2fa9d04f690b0d3/mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3", size = 9857795 }, { url = "https://files.pythonhosted.org/packages/96/39/11b57431a1f686c1aed54bf794870efe0f6aeca11aca281a0bd87a5ad42c/mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", size = 9265618 },
{ url = "https://files.pythonhosted.org/packages/ff/b5/cbccba4dca9703c4c467171e7f61ea6a1a75eae991208aa5bc7d49807f91/mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e", size = 12647633 }, { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981 },
{ url = "https://files.pythonhosted.org/packages/02/3c/1f5e57c8cfab4299f7189821ae8bb4896e8e623a04d293fd32e32eb0e617/mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04", size = 12730251 }, { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175 },
{ url = "https://files.pythonhosted.org/packages/f9/20/d33608e8dc3bc0f5966fc1f6c2d16671f0725dcca279beec47c3e19afd9d/mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31", size = 9491734 }, { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675 },
{ url = "https://files.pythonhosted.org/packages/50/00/86bb2f6c5b58fc6f360dd4cb5c0666dc67c05007c2cddcc694528a59a604/mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3", size = 10813338 }, { url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020 },
{ url = "https://files.pythonhosted.org/packages/33/b0/20c9f6dcbfb312d1804a81f4a39e0b401fe614dc0de580249b6deb07d053/mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf", size = 9968141 }, { url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582 },
{ url = "https://files.pythonhosted.org/packages/aa/87/ec65c45b2e5160203a680b0f79e459fbe9c192f9eff501c3fec82bef3be5/mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531", size = 12724186 }, { url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614 },
{ url = "https://files.pythonhosted.org/packages/c5/5c/f61c876647036d572a1434f0251257a04f2a7bd038c718b28fa5ca699515/mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3", size = 12796640 }, { url = "https://files.pythonhosted.org/packages/6a/9b/fd2e05d6ffff24d912f150b87db9e364fa8282045c875654ce7e32fffa66/mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", size = 10788592 },
{ url = "https://files.pythonhosted.org/packages/69/09/5cd3609d18cf27ec84f380a92b3da695f84781de119d68db69d274c3d1ee/mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f", size = 9396105 }, { url = "https://files.pythonhosted.org/packages/74/37/b246d711c28a03ead1fd906bbc7106659aed7c089d55fe40dd58db812628/mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", size = 9753611 },
{ url = "https://files.pythonhosted.org/packages/2b/ee/d53a3d4792a09b6cd757978951d6dcf8b10825a8b8522b68e9b5eb53b9a1/mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a", size = 2580108 }, { url = "https://files.pythonhosted.org/packages/a6/ac/395808a92e10cfdac8003c3de9a2ab6dc7cde6c0d2a4df3df1b815ffd067/mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", size = 11438443 },
{ url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541 },
{ url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348 },
{ url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648 },
{ url = "https://files.pythonhosted.org/packages/5a/fa/79cf41a55b682794abe71372151dbbf856e3008f6767057229e6649d294a/mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078", size = 10737129 },
{ url = "https://files.pythonhosted.org/packages/d3/33/dd8feb2597d648de29e3da0a8bf4e1afbda472964d2a4a0052203a6f3594/mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba", size = 9856335 },
{ url = "https://files.pythonhosted.org/packages/e4/b5/74508959c1b06b96674b364ffeb7ae5802646b32929b7701fc6b18447592/mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5", size = 11611935 },
{ url = "https://files.pythonhosted.org/packages/6c/53/da61b9d9973efcd6507183fdad96606996191657fe79701b2c818714d573/mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b", size = 12365827 },
{ url = "https://files.pythonhosted.org/packages/c1/72/965bd9ee89540c79a25778cc080c7e6ef40aa1eeac4d52cec7eae6eb5228/mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2", size = 12541924 },
{ url = "https://files.pythonhosted.org/packages/46/d0/f41645c2eb263e6c77ada7d76f894c580c9ddb20d77f0c24d34273a4dab2/mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980", size = 9271176 },
{ url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777 },
] ]
[[package]] [[package]]
@ -2569,27 +2577,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 },
] ]
[[package]]
name = "types-jinja2"
version = "2.11.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "types-markupsafe" },
]
sdist = { url = "https://files.pythonhosted.org/packages/46/c4/b82309bfed8195de7997672deac301bd6f5bd5cbb6a3e392b7fe780d7852/types-Jinja2-2.11.9.tar.gz", hash = "sha256:dbdc74a40aba7aed520b7e4d89e8f0fe4286518494208b35123bcf084d4b8c81", size = 13302 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/b0/e79d84748f1d34304f13191424348a719c3febaa3493835370fe9528e1e6/types_Jinja2-2.11.9-py3-none-any.whl", hash = "sha256:60a1e21e8296979db32f9374d8a239af4cb541ff66447bb915d8ad398f9c63b2", size = 18190 },
]
[[package]]
name = "types-markupsafe"
version = "1.1.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/39/31/b5f059142d058aec41e913d8e0eff0a967e7bc46f9a2ba2f31bc11cff059/types-MarkupSafe-1.1.10.tar.gz", hash = "sha256:85b3a872683d02aea3a5ac2a8ef590193c344092032f58457287fbf8e06711b1", size = 2986 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/bc/d6/b8effb1c48539260a5eb4196afc55efac4ea1684a4991977555eb266b2ef/types_MarkupSafe-1.1.10-py3-none-any.whl", hash = "sha256:ca2bee0f4faafc45250602567ef38d533e877d2ddca13003b319c551ff5b3cc5", size = 3998 },
]
[[package]] [[package]]
name = "types-python-dateutil" name = "types-python-dateutil"
version = "2.9.0.20241206" version = "2.9.0.20241206"