Skip to content

core: Cleanup Pydantic models and handle deprecation warnings #30799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 20, 2025

Conversation

cbornet
Copy link
Collaborator

@cbornet cbornet commented Apr 12, 2025

  • Simplified Pydantic handling since Pydantic v1 is not supported anymore.
  • Replace use of deprecated v1 methods by corresponding v2 methods.
  • Remove use of other deprecated methods.
  • Activate mypy errors on deprecated methods use.

Copy link

vercel bot commented Apr 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
langchain ⬜️ Ignored (Inspect) Visit Preview Jun 20, 2025 2:34pm

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. 🤖:nit Small modifications/deletions, fixes, deps or improvements to existing code or docs labels Apr 12, 2025
@cbornet cbornet force-pushed the pydantic-cleanup branch 3 times, most recently from 7529366 to 5fcb2bb Compare April 12, 2025 01:11
@cbornet cbornet requested a review from eyurtsev April 12, 2025 01:12
@cbornet cbornet force-pushed the pydantic-cleanup branch 3 times, most recently from 14905a4 to 6b9bb2c Compare April 13, 2025 15:10
@@ -183,6 +122,9 @@ def pre_init(func: Callable) -> Any:
with warnings.catch_warnings():
warnings.filterwarnings(action="ignore", category=PydanticDeprecationWarning)

# Ideally we would use @model_validator(mode="before") but this would change the
# order of the validators. See https://github.com/pydantic/pydantic/discussions/7434.
# So we keep root_validator for backward compatibility.
Copy link
Collaborator Author

@cbornet cbornet Apr 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One possibility would be to deprecate pre_init and create a new decorator, for instance before_init, that uses model_validator.
WDYT ?

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Apr 13, 2025
@sydney-runkle
Copy link
Collaborator

I would love to drop v1 support (would clean up the codebase a lot). Need to chat with the team about this depending on download #s, etc.

@cbornet
Copy link
Collaborator Author

cbornet commented Apr 18, 2025

Note: LangChain already dropped support for Pydantic v1. There remains some models using pydantic.v1 namespace of Pydantic v2.

@cbornet cbornet force-pushed the pydantic-cleanup branch from 3c2f2ba to f0a5d4a Compare May 2, 2025 19:18
@cbornet cbornet force-pushed the pydantic-cleanup branch from f0a5d4a to df8b952 Compare May 13, 2025 08:55
@eyurtsev eyurtsev self-assigned this May 15, 2025
Copy link
Collaborator

@eyurtsev eyurtsev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good! Main thing is that let's avoid renaming out top level dict() into model_dump(). It's our own interface, I don't want to make a breaking change here, unless there's a compelling reason (i.e., bug)

@@ -1307,7 +1307,7 @@ def _llm_type(self) -> str:
"""Return type of chat model."""

@override
def dict(self, **kwargs: Any) -> dict:
def model_dump(self, **kwargs: Any) -> dict:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dict is a langchain defined rather than pydantic defined method in this case.

Users likely have custom serialization code that will break if they to use dict

Copy link
Collaborator Author

@cbornet cbornet May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure ? When I look at the dict() inheritance, I find pydantic.BaseModel.dict().
So to be correct when we replace usage of the deprecated BaseChatModel.dict() by BaseChatModel.model_dump(), we have to do the override in model_dump rather than in dict.
In Pydantic v2, dict is deprecated and just calls model_dump which is the replacement.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the goal is to mirror the Pydantic API here. I'm OK with this shadowing and overriding the dict in Pydantic.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure to understand: do you want me to rollback the change here ?
BTW, I don't know if I was clear enough but overriding model_dump isn't a breaking change for users that are calling dict as dict is just an alias for model_dump. It would be breaking only for users that were calling model_dump.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's going to happen once pydantic 3 is released? dict() gets removed from Pydantic. I don't think it means that we have to force langchain users to use model_dump(), instead i'd prefer that we have users keep on using dict(). I don't want users to assume that pydantic's underlying API is usable for arbitrary langchain abstractions

Copy link
Collaborator Author

@cbornet cbornet Jun 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. But dict is an unfortunate name for a method as it conflicts with the builtin dict (this is probably why Pydantic renamed it). And it also conflicts with the Pydantic dict giving us a warning. It would be nice to rename it in LangChain too with a LangChain deprecation cycle (we could use asdict which looks familiar from dataclasses or model_dump which would tie to Pydantic again for good or bad). WDYT ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's going to happen once pydantic 3 is released?

About that we could override both dict and model_dump. So even if it disappears from Pydantic, we still have it in LangChain.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed to use asdict. LMK if you prefer to use model_dump (with dict still overridden and LangChain's deprecated).

@@ -331,7 +331,7 @@ def _prompt_type(self) -> str:
"""Return the prompt type key."""
raise NotImplementedError

def dict(self, **kwargs: Any) -> dict:
def model_dump(self, **kwargs: Any) -> dict:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should stay as dict for now

@cbornet cbornet force-pushed the pydantic-cleanup branch 2 times, most recently from 21a75f8 to 47382b2 Compare May 20, 2025 10:57
@cbornet cbornet force-pushed the pydantic-cleanup branch from afd2794 to 7e08db2 Compare June 3, 2025 09:08
Copy link

codspeed-hq bot commented Jun 3, 2025

CodSpeed WallTime Performance Report

Merging #30799 will degrade performances by 56.46%

Comparing cbornet:pydantic-cleanup (a2567b2) with master (29e17fb)

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

Summary

❌ 1 regressions
✅ 12 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
test_import_time[InMemoryRateLimiter] 70 ms 160.7 ms -56.46%

@override
def dict(self, **kwargs: Any) -> dict:
return self.asdict()

def asdict(self) -> typing.Dict[str, Any]: # noqa: UP006
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once dict is removed, we can use the builtin dict instead of typing.Dict and remove the noqa

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we keep dict() as is for now and not introduce asdict()? I'd like to avoid any interface changes as part of this PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, done. I'll open a separate PR for the dict conflict issue.

@override
def dict(self, **kwargs: Any) -> dict:
return self.asdict()

def asdict(self) -> typing.Dict[str, Any]: # noqa: UP006
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LMK if you prefer an independent asdict or a tied to Pydantic model_dump.

Copy link

codspeed-hq bot commented Jun 3, 2025

CodSpeed Instrumentation Performance Report

Merging #30799 will not alter performance

Comparing cbornet:pydantic-cleanup (a2567b2) with master (29e17fb)

Summary

✅ 13 untouched benchmarks

@cbornet cbornet force-pushed the pydantic-cleanup branch from 7e08db2 to c9cb97f Compare June 3, 2025 09:16
@cbornet cbornet force-pushed the pydantic-cleanup branch 3 times, most recently from 18f3c7b to 91b407a Compare June 6, 2025 11:52
@cbornet cbornet force-pushed the pydantic-cleanup branch from 91b407a to 1a7f483 Compare June 6, 2025 11:55
@cbornet cbornet requested a review from eyurtsev June 6, 2025 11:55
@cbornet
Copy link
Collaborator Author

cbornet commented Jun 16, 2025

@eyurtsev I rolled-back the changes on the dict method.
Do you think it could now be merged ?

@dosubot dosubot bot added the lgtm PR looks good. Use to confirm that a PR is ready for merging. label Jun 20, 2025
@eyurtsev eyurtsev merged commit 7e046ea into langchain-ai:master Jun 20, 2025
66 checks passed
@cbornet cbornet deleted the pydantic-cleanup branch June 20, 2025 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm PR looks good. Use to confirm that a PR is ready for merging. 🤖:nit Small modifications/deletions, fixes, deps or improvements to existing code or docs size:XL This PR changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants