Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
25a5c37
[FEATURE] Support for common pydantic types
lachaib Dec 21, 2023
57f0cb7
Update docs to refer to Python 3.7+ instead of 3.6+
svlandeg Jul 25, 2024
6039b4f
chore: remove email-validator from examples/testing dependencies
lachaib Jul 25, 2024
c38fefc
fix: correct is_pydantic_type for python 3.12
lachaib Jul 25, 2024
e0ad01b
Fix default value to URL instead of email
svlandeg Jul 26, 2024
0ff28ba
Clarify pydantic as additional extra dependency throughout the docs
svlandeg Jul 26, 2024
6dccd26
ignore type error for now
svlandeg Aug 26, 2024
10e7986
remove unnecessary ignore statement
svlandeg Sep 3, 2024
893d86e
simplify pydantic type conversion using pydantic.TypeAdapter
lachaib Sep 4, 2024
ac41a0c
Merge branch 'master' into lachaib/issue181
svlandeg Apr 4, 2025
7608cb4
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Apr 4, 2025
24daca1
Merge branch 'master' into lachaib/issue181
svlandeg Aug 28, 2025
3d967ca
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Aug 28, 2025
b1025d2
update docs to new format
svlandeg Aug 28, 2025
464e60f
Merge branch 'master' into lachaib/issue181
svlandeg Sep 1, 2025
a5636c6
Merge branch 'master' into lachaib/issue181
svlandeg Sep 22, 2025
f3fc8d7
Merge branch 'lachaib/issue181' of https://github.com/lachaib/typer i…
svlandeg Sep 22, 2025
ac92b0f
Merge branch 'master' into lachaib/issue181
svlandeg Sep 23, 2025
eff275d
ignore statement from coverage (as discussed)
svlandeg Oct 3, 2025
b573667
Merge branch 'master' into lachaib/issue181
svlandeg Oct 3, 2025
3ee2868
Merge branch 'master' into lachaib/issue181
svlandeg Nov 25, 2025
9d1ef99
update tutorial files to use explicit Typer()
svlandeg Nov 25, 2025
6fa8211
rename test files to be compatible with current master
svlandeg Jan 13, 2026
8550962
also fix renaming in markdown file
svlandeg Jan 13, 2026
8e0fb62
use new format to generalize test files with a fixture
svlandeg Jan 13, 2026
5282cad
Merge branch 'master' into lachaib/issue181
svlandeg Jan 13, 2026
4717696
sync uv.lock
svlandeg Jan 13, 2026
d59a36f
🎨 Auto format
pre-commit-ci-lite[bot] Jan 13, 2026
168a79e
use builtin tuple and list
svlandeg Jan 13, 2026
640957e
configure importlib to avoid conflicts
svlandeg Jan 13, 2026
cf3ab72
add pydantic also to tests requirements in pyproject.toml
svlandeg Jan 13, 2026
f7881f4
more fixes
svlandeg Jan 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Create and activate a <a href="https://typer.tiangolo.com/virtual-environments/"
```console
$ pip install typer
---> 100%
Successfully installed typer rich shellingham
Successfully installed typer rich shellingham pydantic
```

</div>
Expand Down Expand Up @@ -357,6 +357,7 @@ For a more complete example including more features, see the <a href="https://ty
By default it also comes with extra standard dependencies:

* <a href="https://rich.readthedocs.io/en/stable/index.html" class="external-link" target="_blank"><code>rich</code></a>: to show nicely formatted errors automatically.
* <a href="https://docs.pydantic.dev/latest/" class="external-link" target="_blank"><code>pydantic</code></a>: to support the usage of Pydantic types.
* <a href="https://github.com/sarugaku/shellingham" class="external-link" target="_blank"><code>shellingham</code></a>: to automatically detect the current shell when installing completion.
* With `shellingham` you can just use `--install-completion`.
* Without `shellingham`, you have to pass the name of the shell to install completion for, e.g. `--install-completion bash`.
Expand All @@ -377,7 +378,7 @@ pip install typer
pip install "typer-slim[standard]"
```

The `standard` extra dependencies are `rich` and `shellingham`.
The `standard` extra dependencies are `rich`, `shellingham` and `pydantic`.

**Note**: The `typer` command is only included in the `typer` package.

Expand Down
5 changes: 3 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Create and activate a <a href="https://typer.tiangolo.com/virtual-environments/"
```console
$ pip install typer
---> 100%
Successfully installed typer rich shellingham
Successfully installed typer rich shellingham pydantic
```

</div>
Expand Down Expand Up @@ -363,6 +363,7 @@ For a more complete example including more features, see the <a href="https://ty
By default it also comes with extra standard dependencies:

* <a href="https://rich.readthedocs.io/en/stable/index.html" class="external-link" target="_blank"><code>rich</code></a>: to show nicely formatted errors automatically.
* <a href="https://docs.pydantic.dev/latest/" class="external-link" target="_blank"><code>pydantic</code></a>: to support the usage of Pydantic types.
* <a href="https://github.com/sarugaku/shellingham" class="external-link" target="_blank"><code>shellingham</code></a>: to automatically detect the current shell when installing completion.
* With `shellingham` you can just use `--install-completion`.
* Without `shellingham`, you have to pass the name of the shell to install completion for, e.g. `--install-completion bash`.
Expand All @@ -383,7 +384,7 @@ pip install typer
pip install "typer-slim[standard]"
```

The `standard` extra dependencies are `rich` and `shellingham`.
The `standard` extra dependencies are `rich`, `shellingham` and `pydantic`.

**Note**: The `typer` command is only included in the `typer` package.

Expand Down
4 changes: 2 additions & 2 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ Updated docs [SubCommand Name and Help](https://typer.tiangolo.com/tutorial/subc

Now you don't need to install `typer[all]`. When you install `typer` it comes with the default optional dependencies and the `typer` command.

If you don't want the extra optional dependencies (`rich` and `shellingham`), you can install `typer-slim` instead.
If you don't want the extra optional dependencies (`rich`, `shellingham` and `pydantic`), you can install `typer-slim` instead.

You can also install `typer-slim[standard]`, which includes the default optional dependencies, but not the `typer` command.

Expand All @@ -699,7 +699,7 @@ By installing the latest version (`0.12.1`) it fixes it, for any previous versio

In version `0.12.0`, the `typer` package depends on `typer-slim[standard]` which includes the default dependencies (instead of `typer[all]`) and `typer-cli` (that provides the `typer` command).

If you don't want the extra optional dependencies (`rich` and `shellingham`), you can install `typer-slim` instead.
If you don't want the extra optional dependencies (`rich`, `shellingham` and `pydantic`), you can install `typer-slim` instead.

You can also install `typer-slim[standard]`, which includes the default optional dependencies, but not the `typer` command.

Expand Down
31 changes: 31 additions & 0 deletions docs/tutorial/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,34 @@ Using it in your editor is what really shows you the benefits of **Typer**, seei
And running the examples is what will really help you **understand** what is going on.

You can learn a lot more by **running some examples** and **playing around** with them than by reading all the docs here.

---

## Install **Typer**

The first step is to install **Typer**:

<div class="termy">

```console
$ pip install typer
---> 100%
Successfully installed typer click shellingham rich pydantic
```

</div>

By default, `typer` comes with `rich`, `shellingham` and `pydantic`.

!!! note
If you are an advanced user and want to opt out of these default extra dependencies, you can instead install `typer-slim`.

```bash
pip install typer
```

...includes the same optional dependencies as:

```bash
pip install "typer-slim[standard]"
```
37 changes: 37 additions & 0 deletions docs/tutorial/parameter-types/pydantic-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Pydantic types such as [AnyUrl](https://docs.pydantic.dev/latest/api/networks/#pydantic.networks.AnyUrl) or [EmailStr](https://docs.pydantic.dev/latest/api/networks/#pydantic.networks.EmailStr) can be very convenient to describe and validate some parameters.

Pydantic is installed automatically when installing Typer with its extra standard dependencies:

<div class="termy">

```console
// Pydantic comes with typer
$ pip install typer
---> 100%
Successfully installed typer rich shellingham pydantic

// Alternatively, you can install Pydantic independently
$ pip install pydantic
---> 100%
Successfully installed pydantic

// Or if you want to use EmailStr
$ pip install "pydantic[email]"
---> 100%
Successfully installed pydantic, email-validator
```

</div>


You can then use them as parameter types.

{* docs_src/parameter_types/pydantic_types/tutorial001_an_py39.py hl[9] *}

{* docs_src/parameter_types/pydantic_types/tutorial002_an_py39.py hl[9] *}

These types are also supported in lists or tuples:

{* docs_src/parameter_types/pydantic_types/tutorial003_an_py39.py hl[9] *}

{* docs_src/parameter_types/pydantic_types/tutorial004_an_py39.py hl[9] *}
Empty file.
15 changes: 15 additions & 0 deletions docs_src/parameter_types/pydantic_types/tutorial001_an_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Annotated

import typer
from pydantic import AnyHttpUrl

app = typer.Typer()


@app.command()
def main(url_arg: Annotated[AnyHttpUrl, typer.Argument()]):
typer.echo(f"url_arg: {url_arg}")


if __name__ == "__main__":
app()
13 changes: 13 additions & 0 deletions docs_src/parameter_types/pydantic_types/tutorial001_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import typer
from pydantic import AnyHttpUrl

app = typer.Typer()


@app.command()
def main(url_arg: AnyHttpUrl):
typer.echo(f"url_arg: {url_arg}")


if __name__ == "__main__":
app()
15 changes: 15 additions & 0 deletions docs_src/parameter_types/pydantic_types/tutorial002_an_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Annotated

import typer
from pydantic import AnyHttpUrl

app = typer.Typer()


@app.command()
def main(url_opt: Annotated[AnyHttpUrl, typer.Option()] = "https://typer.tiangolo.com"):
typer.echo(f"url_opt: {url_opt}")


if __name__ == "__main__":
app()
13 changes: 13 additions & 0 deletions docs_src/parameter_types/pydantic_types/tutorial002_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import typer
from pydantic import AnyHttpUrl

app = typer.Typer()


@app.command()
def main(url_opt: AnyHttpUrl = typer.Option("https://typer.tiangolo.com")):
typer.echo(f"url_opt: {url_opt}")


if __name__ == "__main__":
app()
17 changes: 17 additions & 0 deletions docs_src/parameter_types/pydantic_types/tutorial003_an_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Annotated

import typer
from pydantic import AnyHttpUrl

app = typer.Typer()


@app.command()
def main(
urls: Annotated[list[AnyHttpUrl], typer.Option("--url", default_factory=list)],
):
typer.echo(f"urls: {urls}")


if __name__ == "__main__":
app()
13 changes: 13 additions & 0 deletions docs_src/parameter_types/pydantic_types/tutorial003_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import typer
from pydantic import AnyHttpUrl

app = typer.Typer()


@app.command()
def main(urls: list[AnyHttpUrl] = typer.Option([], "--url")):
typer.echo(f"urls: {urls}")


if __name__ == "__main__":
app()
23 changes: 23 additions & 0 deletions docs_src/parameter_types/pydantic_types/tutorial004_an_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from typing import Annotated

import typer
from pydantic import AnyHttpUrl, IPvAnyAddress

app = typer.Typer()


@app.command()
def main(
server: Annotated[
tuple[str, IPvAnyAddress, AnyHttpUrl],
typer.Option(help="User name, age, email and social media URL"),
],
):
name, address, url = server
typer.echo(f"name: {name}")
typer.echo(f"address: {address}")
typer.echo(f"url: {url}")


if __name__ == "__main__":
app()
20 changes: 20 additions & 0 deletions docs_src/parameter_types/pydantic_types/tutorial004_py39.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import typer
from pydantic import AnyHttpUrl, IPvAnyAddress

app = typer.Typer()


@app.command()
def main(
server: tuple[str, IPvAnyAddress, AnyHttpUrl] = typer.Option(
..., help="Server name, IP address and public URL"
),
):
name, address, url = server
typer.echo(f"name: {name}")
typer.echo(f"address: {address}")
typer.echo(f"url: {url}")


if __name__ == "__main__":
app()
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ nav:
- tutorial/parameter-types/path.md
- tutorial/parameter-types/file.md
- tutorial/parameter-types/custom-types.md
- tutorial/parameter-types/pydantic-types.md
- SubCommands - Command Groups:
- tutorial/subcommands/index.md
- tutorial/subcommands/add-typer.md
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Changelog = "https://typer.tiangolo.com/release-notes/"
standard = [
"shellingham >=1.3.0",
"rich >=10.11.0",
"pydantic >=2.0.0",
]

[dependency-groups]
Expand Down Expand Up @@ -81,6 +82,7 @@ github-actions = [
tests = [
"coverage[toml]>=6.2,<8.0",
"mypy==1.19.1",
"pydantic >=2.0.0",
"pytest>=4.4.0,<9.0.0",
"pytest-cov>=2.10.0,<8.0.0",
"pytest-sugar>=0.9.4,<1.2.0",
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import importlib
import subprocess
import sys
from types import ModuleType

import pytest
from typer.testing import CliRunner

runner = CliRunner()


@pytest.fixture(
name="mod",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_an_py39"),
],
)
def get_mod(request: pytest.FixtureRequest) -> ModuleType:
module_name = f"docs_src.parameter_types.pydantic_types.{request.param}"
mod = importlib.import_module(module_name)
return mod


def test_help(mod: ModuleType):
result = runner.invoke(mod.app, ["--help"])
assert result.exit_code == 0


def test_url_arg(mod: ModuleType):
result = runner.invoke(mod.app, ["https://typer.tiangolo.com"])
assert result.exit_code == 0
assert "url_arg: https://typer.tiangolo.com" in result.output


def test_url_arg_invalid(mod: ModuleType):
result = runner.invoke(mod.app, ["invalid"])
assert result.exit_code != 0
assert "Input should be a valid URL" in result.output


def test_script(mod: ModuleType):
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
capture_output=True,
encoding="utf-8",
)
assert "Usage" in result.stdout
Loading