Skip to content

✨ Use Pydantic for parameter validation#1831

Draft
svlandeg wants to merge 75 commits into
fastapi:masterfrom
svlandeg:feat/pydantic
Draft

✨ Use Pydantic for parameter validation#1831
svlandeg wants to merge 75 commits into
fastapi:masterfrom
svlandeg:feat/pydantic

Conversation

@svlandeg

@svlandeg svlandeg commented Jun 10, 2026

Copy link
Copy Markdown
Member

WIP: please don't comment/review yet, this will still change a lot.

Description

Make Pydantic a required dependency and rely on it for parameter validation.

  • Type-specific stuff is in the new module param_types.py
  • Pydantic-specific adapter stuff is in the new module adapters.py
  • Coercion contracts are in the new module coercion.py

How to review this

  • Probably read all of the below first 👇
  • Note that _click/types.py and typer/_types.py are deleted
  • First look at typer/param_types.py, then typer/adapters.py, then typer/coercion.py
  • Look at the changes in typer/core.py
  • Check all other changes in typer/*.py
  • Check all changes in typer/_click/*.py
  • Check all changes in the test suite & documentation

Extended/improved functionality

  • More date time formats are now supported by default, instead of just the three [%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S]
  • Started moving towards a TyperParameter, not quite finished yet with some ugly imports from within _click but we'll deal with those in follow-up work

Tests with same behaviour on master

  • Added test_bool_convert_valid to ensure that the "bool" conversion has remained the same for all kinds of inputs.
  • Rewrote several tests to use Typer public API instead of internals

Breaking changes

(more or less in order of breakingness from most to least)

  • Removed support for click_type and open bounds through min_open and max_open. This greatly simplifies the code base while still providing an alternative by setting parser instead.
  • metavar variables now show up as the Python type lowercased and in <>, so "<str>" instead of "TEXT" and "<int>" instead of "INTEGER" etc.
  • When not providing a default for DateTime, only one example is shown in the metavar column (%Y-%m-%d instead of [%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S]) even though all three (and more) will work. It's not just those three anymore, so it felt arbitrary to show 3 out of n. We can decide to reverse the change and keep showing those three formats though.
  • Validation error messages have changed from Click's to Pydantic's phrasing. This mostly requires updating test suites and otherwise shouldn't impact users too badly.
  • Removed repr functionality of param.type. This wasn't really used except for the tests that were recently added in ➖ Vendor Click and streamline Typer's functionality and code base #1774.

Bug fixes (also breaking bwd compat)

  • def main(age: int = typer.Option(15.3)) will now throw a validation error by Pydantic instead of int(15.3) converting it to 15. I consider this a bug fix instead of a regression, and have added a test test_int_rejects_float_default for it.
  • Types are now inferred from the default if the parameter is untyped. Fixes Default value of `False` cast to `'False'` and is thus True #942, cf. new test test_default_infers_param_type.

Decision points

  • _parse_cli_bool was created to ensure we still parse "" as False and to strip whitespace from something like " True ". This is just to mimic old Click behaviour. If we don't do this preprocessing (cleaner code base), the empty string and the non-stripped strings won't pass Pydantic validation and it would be slightly breaking.

AI Disclaimer

Cursor was used as a micro-managed junior. Every edit was reviewed & understood by me.

TODO

  • Properly explain Pydantic dep in the docs
  • Update the tutorial, focus on display of types & metavar
  • Fix coverage

Checklist

  • I added tests for the change.
  • Coverage stays at 100%.
  • The documentation explains the change if needed.

@svlandeg svlandeg added the feature New feature, enhancement or request label Jun 10, 2026
("No", False),
],
)
def test_bool_convert_valid(cli_value: str, expected: bool) -> None:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This test currently mimics master behaviour 100%.

@svlandeg svlandeg self-assigned this Jun 10, 2026
@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

📝 Docs preview

Last commit 9c3ddd8 at: https://6603338f.typertiangolo.pages.dev

@github-actions github-actions Bot added the conflicts Automatically generated when a PR has a merge conflict label Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has a merge conflict that needs to be resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflicts Automatically generated when a PR has a merge conflict feature New feature, enhancement or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants