Skip to content
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
9b6081d
add pydantic as requirement
svlandeg Jun 9, 2026
b54b308
use TypeAdapter for int and float validation
svlandeg Jun 9, 2026
c8640ae
Range adaptor and Pydantic error messages
svlandeg Jun 9, 2026
10746de
UUID adapter
svlandeg Jun 9, 2026
394e7f2
DateTime adapter
svlandeg Jun 9, 2026
27f5880
Choice adapter
svlandeg Jun 9, 2026
570d2be
introduce PydanticParamType
svlandeg Jun 9, 2026
c8f6dff
build_type_adapter
svlandeg Jun 10, 2026
15a0e9a
consolidate enum validation
svlandeg Jun 10, 2026
94cf21b
type adapter for bool parsing
svlandeg Jun 10, 2026
d0fe927
🎨 Auto format
pre-commit-ci-lite[bot] Jun 10, 2026
b749fc2
fix types
svlandeg Jun 10, 2026
48ff1f4
param_type_from_annotation in new module param_types
svlandeg Jun 10, 2026
e0fd56d
move str and File to new module
svlandeg Jun 10, 2026
5eb5ade
🎨 Auto format
pre-commit-ci-lite[bot] Jun 10, 2026
4495762
clean up converter code
svlandeg Jun 10, 2026
31432df
remove support for click_type and open bounds
svlandeg Jun 10, 2026
eaa68dd
datetime factory
svlandeg Jun 10, 2026
a0e429e
🎨 Auto format
pre-commit-ci-lite[bot] Jun 10, 2026
b79b401
move min/max info into TyperOption and TyperArgument and clamp using …
svlandeg Jun 10, 2026
58bb823
Merge branch 'feat/pydantic' of https://github.com/svlandeg/typer int…
svlandeg Jun 10, 2026
3953649
🎨 Auto format
pre-commit-ci-lite[bot] Jun 10, 2026
943b335
repr cleanup
svlandeg Jun 10, 2026
5b5085e
move _types.py stuff to param_types.py
svlandeg Jun 11, 2026
7c201ec
move TyperPath to param_types.py as well
svlandeg Jun 11, 2026
621280b
remove unused ignore statement
svlandeg Jun 11, 2026
b6165b7
centralize Pydantic functionality to adapaters.py
svlandeg Jun 11, 2026
4332d34
resolve_param_type instead of convert_type
svlandeg Jun 12, 2026
43f71ad
fix type
svlandeg Jun 12, 2026
d6bc20d
fix import
svlandeg Jun 12, 2026
fdf2973
few more test cases for default type inference
svlandeg Jun 12, 2026
0336edf
move FuncParamType
svlandeg Jun 12, 2026
98e200b
coercion through RuntimeParam schema, slim down PydanticParamType to …
svlandeg Jun 14, 2026
12df977
move out File to param_types and extend RuntimeParam
svlandeg Jun 14, 2026
4972630
some cleanup and refactor
svlandeg Jun 15, 2026
9d97184
cleanup inline imports
svlandeg Jun 15, 2026
bab9056
TyperTuple into param_types
svlandeg Jun 15, 2026
0809456
ChoiceRuntimeParam
svlandeg Jun 15, 2026
80495f9
ChoiceRuntimeParam
svlandeg Jun 15, 2026
199b28b
clean up ParamType methods and introduce TyperParameter
svlandeg Jun 15, 2026
39a2c15
Merge branch 'master' into feat/pydantic
svlandeg Jun 16, 2026
78a1c37
refactors and simplifications
svlandeg Jun 16, 2026
cfccba8
fix test
svlandeg Jun 16, 2026
9a9bee7
some more cleanup in RuntimeParam/DeclaredParam/Parameter
svlandeg Jun 16, 2026
b7531f5
remove ParamType's repr functionality
svlandeg Jun 16, 2026
f98d311
consolidate metavar functionality and discard the short-lived Display…
svlandeg Jun 16, 2026
ab3863e
Merge branch 'master' into feat/pydantic
svlandeg Jun 17, 2026
46e3fec
return metavar in <> and lowercased
svlandeg Jun 17, 2026
1e6ff44
removing CommandSchema for now and make RuntimeParam required
svlandeg Jun 17, 2026
b157ea9
use TyperParameter more often and further unify metavar printing (sti…
svlandeg Jun 17, 2026
f3679c7
fix metavar for list
svlandeg Jun 17, 2026
3b3459a
clean out param_types and move metavar functions to TyperParameter
svlandeg Jun 18, 2026
0264bca
fix fixture and isolate temp dir
svlandeg Jun 18, 2026
de4e031
clean up default inference
svlandeg Jun 19, 2026
0c8b6a8
PassThroughRuntimeParam instead of falling back to str
svlandeg Jun 19, 2026
042d16c
small refactors for diff readability
svlandeg Jun 19, 2026
8600249
Merge branch 'master' into feat/pydantic
svlandeg Jun 22, 2026
b448af6
formatting
svlandeg Jun 22, 2026
0bf9b2f
remove intermediate layer DeclaredParam
svlandeg Jun 22, 2026
9d778d4
🎨 Auto format
pre-commit-ci-lite[bot] Jun 22, 2026
66f57a8
TypeDescriptor to solidify type coercion
svlandeg Jun 22, 2026
f462dab
Merge remote-tracking branch 'origin/feat/pydantic' into feat/pydantic
svlandeg Jun 22, 2026
65dd995
🎨 Auto format
pre-commit-ci-lite[bot] Jun 22, 2026
68c3a7f
remove unnecessary helper functions
svlandeg Jun 23, 2026
9c08b7c
🎨 Auto format
pre-commit-ci-lite[bot] Jun 23, 2026
0a0365a
fix types
svlandeg Jun 23, 2026
a1e10b6
Merge branch 'feat/pydantic' of https://github.com/svlandeg/typer int…
svlandeg Jun 23, 2026
1f058cc
fix types (again)
svlandeg Jun 23, 2026
07c724a
keep fixing types
svlandeg Jun 23, 2026
291e4e9
remove _click/types and ParamType entirely
svlandeg Jun 23, 2026
c5f30ac
Merge branch 'master' into feat/pydantic
svlandeg Jun 24, 2026
9b84173
better test for str resolved as path
svlandeg Jun 24, 2026
6198cd6
even better test for str resolve
svlandeg Jun 24, 2026
6230efc
avoid Path coercion for str-typed parameters
svlandeg Jun 24, 2026
9c3ddd8
extend metavar test with defaults (will fail for now due to related i…
svlandeg Jun 24, 2026
3948629
Merge branch 'master' into feat/pydantic
svlandeg Jun 26, 2026
53a6cf0
fix metavar type display
svlandeg Jun 26, 2026
166b22d
solidify metavar printing (part 1: brackets)
svlandeg Jun 26, 2026
f1cb56e
🎨 Auto format
pre-commit-ci-lite[bot] Jun 26, 2026
e7e8432
part 2 of metavar printing: use {} to denote arg/opt names otherwise …
svlandeg Jun 26, 2026
27c7840
🎨 Auto format
pre-commit-ci-lite[bot] Jun 26, 2026
ddb56ab
Merge branch 'master' into feat/pydantic
svlandeg Jul 7, 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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
]
dependencies = [
"pydantic >=2.5.3",
"shellingham >=1.3.0",
"rich >=13.8.0",
"annotated-doc >=0.0.2",
Expand Down
3 changes: 2 additions & 1 deletion tests/test_others.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,8 @@ def main(arg1, arg2: int, arg3: "int", arg4: bool = False, arg5: "bool" = False)

result = runner.invoke(app, ["Hello", "2", "invalid"])

assert "Invalid value for 'ARG3': 'invalid' is not a valid integer" in result.output
assert "Invalid value for 'ARG3'" in result.output
assert "Input should be a valid integer" in result.output
result = runner.invoke(app, ["Hello", "2", "3", "--arg4", "--arg5"])
assert (
"arg1: <class 'str'> Hello\narg2: <class 'int'> 2\narg3: <class 'int'> 3\narg4: <class 'bool'> True\narg5: <class 'bool'> True\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_type_repr():
def test_help():
result = runner.invoke(app, ["--help"])
assert result.exit_code == 0
assert "[%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S]" in result.output
assert "[%Y-%m-%d]" in result.output


def test_main():
Expand All @@ -42,14 +42,8 @@ def test_main_datetime_object():
def test_invalid():
result = runner.invoke(app, ["july-19-1989"])
assert result.exit_code != 0
assert (
"Invalid value for 'BIRTH:[%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S]':"
in result.output
)
assert "'july-19-1989' does not match the formats" in result.output
assert "%Y-%m-%d" in result.output
assert "%Y-%m-%dT%H:%M:%S" in result.output
assert "%Y-%m-%d %H:%M:%S" in result.output
assert "Invalid value for 'BIRTH:[%Y-%m-%d]'" in result.output
assert "should be a valid datetime" in result.output


def test_script():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def test_invalid():
result = runner.invoke(app, ["Camila", "--age", "15.3"])
assert result.exit_code != 0
assert "Invalid value for '--age'" in result.output
assert "'15.3' is not a valid integer" in result.output
assert "Input should be a valid integer" in result.output


def test_script():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,23 @@ def test_params(mod: ModuleType):
def test_invalid_id(mod: ModuleType):
result = runner.invoke(mod.app, ["1002"])
assert result.exit_code != 0
assert (
"Invalid value for 'ID': 1002 is not in the range 0<=x<=1000." in result.output
)
assert "Invalid value for 'ID'" in result.output
assert "should be less than or equal to 1000" in result.output


def test_invalid_age(mod: ModuleType):
result = runner.invoke(mod.app, ["5", "--age", "15"])
assert result.exit_code != 0
assert "Invalid value for '--age'" in result.output
assert "15 is not in the range x>=18" in result.output
assert "should be greater than or equal to 18" in result.output


def test_invalid_score(monkeypatch: pytest.MonkeyPatch, mod: ModuleType):
monkeypatch.setattr(typer.core, "HAS_RICH", False)
result = runner.invoke(mod.app, ["5", "--age", "20", "--score", "100.5"])
assert result.exit_code != 0
assert "Invalid value for '--score'" in result.output
assert "100.5 is not in the range x<=100." in result.output
assert "should be less than or equal to 100" in result.output


def test_negative_score(mod: ModuleType):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType:
def test_invalid_id(mod: ModuleType):
result = runner.invoke(mod.app, ["1002"])
assert result.exit_code != 0
assert (
"Invalid value for 'ID': 1002 is not in the range 0<=x<=1000" in result.output
)
assert "Invalid value for 'ID'" in result.output
assert "should be less than or equal to 1000" in result.output


def test_clamped(mod: ModuleType):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@ def test_main_with_uuid_object():
def test_invalid_uuid():
result = runner.invoke(app, ["7479706572-72756c6573"])
assert result.exit_code != 0
assert (
"Invalid value for 'USER_ID': '7479706572-72756c6573' is not a valid UUID"
in result.output
)
assert "Invalid value for 'USER_ID'" in result.output
assert "should be a valid UUID" in result.output


def test_script():
Expand Down
54 changes: 51 additions & 3 deletions tests/test_type_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,40 @@ def custom_click_type(
assert "2" in result.output


@pytest.mark.parametrize(
("cli_value", "expected"),
[
("true", True),
("false", False),
("yes", True),
("no", False),
("1", True),
("0", False),
("on", True),
("off", False),
("t", True),
("f", False),
("y", True),
("n", False),
("", False),
(" true ", True),
(" FALSE ", False),
("TRUE", True),
("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%.

app = typer.Typer()

@app.command()
def main(value: bool):
print(value)

result = runner.invoke(app, [cli_value])
assert result.exit_code == 0
assert str(expected) in result.output


def test_bool_convert_invalid():
app = typer.Typer()

Expand All @@ -225,9 +259,7 @@ def main(value: bool):

result = runner.invoke(app, ["maybe"])
assert result.exit_code == 2
assert "is not a valid boolean" in result.output
assert "yes" in result.output
assert "false" in result.output
assert "Input should be a valid boolean" in result.output


@pytest.mark.parametrize(
Expand Down Expand Up @@ -368,6 +400,22 @@ class CustomType:
assert func_type.name == "CustomType"


def test_int_rejects_float_default() -> None:
app = typer.Typer()

@app.command()
def main(age: int = typer.Option(15.3)):
typer.echo(age)

result = runner.invoke(app, ["--age", 42])
assert "42" in result.stdout

# Pydantic validation rejects floats as int instead of converting int(15.3) to 15
result = runner.invoke(app)
assert result.exit_code != 0
assert "Input should be a valid integer" in result.stderr


@pytest.mark.parametrize(
("platform_case", "stdin_encoding", "filesystem_encoding"),
[
Expand Down
Loading
Loading