Skip to content
Draft
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
cc485f6
remove UNSET code paths that Typer doesn't use
svlandeg Apr 13, 2026
d358475
remove unused FLAG_NEEDS_VALUE functionality
svlandeg Apr 13, 2026
2603ad5
remove debug statements
svlandeg Apr 14, 2026
0ad141a
🎨 Auto format
pre-commit-ci-lite[bot] Apr 14, 2026
59d71cb
remove unused functionalityf
svlandeg Apr 14, 2026
13fa1c3
make Command abstract and clean up
svlandeg Apr 14, 2026
c2abab9
make Parameter abstract and clean up
svlandeg Apr 14, 2026
32c6f2c
further clean up of Context and use Typer formatting in _click.core
svlandeg Apr 14, 2026
a9809d3
clean up of _click.utils
svlandeg Apr 14, 2026
adcee61
clean up of _click.types
svlandeg Apr 14, 2026
3bc5952
clean up of _click.testing
svlandeg Apr 14, 2026
7ca5ef4
clean up of _click.termui
svlandeg Apr 14, 2026
479199d
clean up of _click.shell_completion
svlandeg Apr 14, 2026
4957df1
remove usage of cabc in _click classes
svlandeg Apr 14, 2026
a674e21
clean up of _click.parser
svlandeg Apr 14, 2026
ae32a24
clean up of _click.globals
svlandeg Apr 14, 2026
e31ea20
clean up of _click.formatting
svlandeg Apr 14, 2026
055b342
🎨 Auto format
pre-commit-ci-lite[bot] Apr 14, 2026
798caab
clean up of _click.exceptions
svlandeg Apr 14, 2026
c323bb1
clean up of _click.decorators
svlandeg Apr 14, 2026
6084689
clean up of _click._winconsole
svlandeg Apr 14, 2026
33209c5
clean up of _click._compat
svlandeg Apr 14, 2026
e264005
clean up of _click._termui_impl
svlandeg Apr 14, 2026
87bc518
few more little fixes
svlandeg Apr 14, 2026
b2a8cac
add colorama as dependency for Windows
svlandeg Apr 15, 2026
cc5a693
restore original error msg to avoid testing differences
svlandeg Apr 15, 2026
683ced0
additional unit tests for ParamType File
svlandeg Apr 15, 2026
8412f52
🎨 Auto format
pre-commit-ci-lite[bot] Apr 15, 2026
7ba8070
bring coverage of _click/types.py to 100%
svlandeg Apr 15, 2026
cb63ba7
format
svlandeg Apr 15, 2026
fc70c24
bring coverage of typer/types.py to 100%
svlandeg Apr 15, 2026
4c894e5
fix coverage in new tests
svlandeg Apr 15, 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 @@ -36,6 +36,7 @@ dependencies = [
"shellingham >=1.3.0",
"rich >=12.3.0",
"annotated-doc >=0.0.2",
"colorama; platform_system == 'Windows'",
]
readme = "README.md"

Expand Down
19 changes: 19 additions & 0 deletions tests/test_completion/choice_case_insensitive_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from enum import Enum

import typer

app = typer.Typer()


class User(str, Enum):
rick = "rick"
morty = "morty"


@app.command()
def main(name: User = typer.Option(User.rick, "--name", case_sensitive=False)):
print(name.value)


if __name__ == "__main__":
app()
19 changes: 19 additions & 0 deletions tests/test_completion/choice_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from enum import Enum

import typer

app = typer.Typer()


class User(str, Enum):
rick = "rick"
morty = "morty"


@app.command()
def main(name: User = typer.Option(User.rick, "--name")):
print(name.value)


if __name__ == "__main__":
app()
12 changes: 12 additions & 0 deletions tests/test_completion/file_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import typer

app = typer.Typer()


@app.command()
def main(config: typer.FileText = typer.Option(...)):
print(config.read())


if __name__ == "__main__":
app()
50 changes: 50 additions & 0 deletions tests/test_completion/test_completion_choice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import os
import subprocess
import sys

from . import choice_case_insensitive_example as mod_case_insensitive
from . import choice_example as mod


def test_script() -> None:
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, "--name", "rick"],
capture_output=True,
encoding="utf-8",
)
assert result.returncode == 0
assert "rick" in result.stdout


def test_completion_choice_bash() -> None:
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, " "],
capture_output=True,
encoding="utf-8",
env={
**os.environ,
"_CHOICE_EXAMPLE.PY_COMPLETE": "complete_bash",
"COMP_WORDS": "choice_example.py --name mo",
"COMP_CWORD": "2",
},
)
assert result.returncode == 0
assert "morty" in result.stdout
assert "rick" not in result.stdout


def test_completion_choice_bash_case_insensitive() -> None:
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod_case_insensitive.__file__, " "],
capture_output=True,
encoding="utf-8",
env={
**os.environ,
"_CHOICE_CASE_INSENSITIVE_EXAMPLE.PY_COMPLETE": "complete_bash",
"COMP_WORDS": "choice_case_insensitive_example.py --name MO",
"COMP_CWORD": "2",
},
)
assert result.returncode == 0
assert "morty" in result.stdout
assert "rick" not in result.stdout
39 changes: 39 additions & 0 deletions tests/test_completion/test_completion_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import os
import subprocess
import sys

from . import file_example as mod


def test_script() -> None:
result = subprocess.run(
[
sys.executable,
"-m",
"coverage",
"run",
mod.__file__,
"--config",
mod.__file__,
],
capture_output=True,
encoding="utf-8",
)
assert result.returncode == 0
assert "def main(config: typer.FileText = typer.Option(...)):" in result.stdout


def test_completion_file_bash() -> None:
result = subprocess.run(
[sys.executable, "-m", "coverage", "run", mod.__file__, " "],
capture_output=True,
encoding="utf-8",
env={
**os.environ,
"_FILE_EXAMPLE.PY_COMPLETE": "complete_bash",
"COMP_WORDS": "file_example.py --config file_ex",
"COMP_CWORD": "2",
},
)
assert result.returncode == 0
assert "file_ex" in result.stdout
4 changes: 2 additions & 2 deletions tests/test_others.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_too_many_parsers():
def custom_parser(value: str) -> int:
return int(value) # pragma: no cover

class CustomClickParser(_click.ParamType):
class CustomClickParser(_click.types.ParamType):
name = "custom_parser"

def convert(
Expand All @@ -61,7 +61,7 @@ def test_valid_parser_permutations():
def custom_parser(value: str) -> int:
return int(value) # pragma: no cover

class CustomClickParser(_click.ParamType):
class CustomClickParser(_click.types.ParamType):
name = "custom_parser"

def convert(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from types import ModuleType

import pytest
import typer
from typer.testing import CliRunner

runner = CliRunner()
Expand All @@ -22,6 +23,12 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType:
return mod


def test_type_repr(mod: ModuleType):
command = typer.main.get_command(mod.app)
force_param = next(param for param in command.params if param.name == "force")
assert repr(force_param.type) == "BOOL"


def test_help(mod: ModuleType):
result = runner.invoke(mod.app, ["--help"])
assert result.exit_code == 0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import subprocess
import sys
from datetime import datetime

import typer
from typer.testing import CliRunner

from docs_src.parameter_types.datetime import tutorial001_py310 as mod
Expand All @@ -9,6 +11,12 @@
app = mod.app


def test_type_repr():
command = typer.main.get_command(app)
birth_param = next(param for param in command.params if param.name == "birth")
assert repr(birth_param.type) == "DateTime"


def test_help():
result = runner.invoke(app, ["--help"])
assert result.exit_code == 0
Expand All @@ -22,6 +30,15 @@ def test_main():
assert "Birth hour: 10" in result.output


def test_main_datetime_object():
result = runner.invoke(
app, [], default_map={"birth": datetime(1956, 1, 31, 10, 0, 0)}
)
assert result.exit_code == 0
assert "Interesting day to be born: 1956-01-31 10:00:00" in result.output
assert "Birth hour: 10" in result.output


def test_invalid():
result = runner.invoke(app, ["july-19-1989"])
assert result.exit_code != 0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import subprocess
import sys

import typer
from typer.testing import CliRunner

from docs_src.parameter_types.index import tutorial001_py310 as mod
Expand All @@ -9,6 +10,16 @@
app = mod.app


def test_type_repr():
command = typer.main.get_command(app)
age_param = next(param for param in command.params if param.name == "age")
height_meters_param = next(
param for param in command.params if param.name == "height_meters"
)
assert repr(age_param.type) == "INT"
assert repr(height_meters_param.type) == "FLOAT"


def test_help():
result = runner.invoke(app, ["--help"])
assert result.exit_code == 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ def get_mod(request: pytest.FixtureRequest) -> ModuleType:
return mod


def test_type_repr(mod: ModuleType):
command = typer.main.get_command(mod.app)

id_param = next(param for param in command.params if param.name == "id")
assert repr(id_param.type) == "<IntRange 0<=x<=1000>"

age_param = next(param for param in command.params if param.name == "age")
assert repr(age_param.type) == "<IntRange x>=18>"

score_param = next(param for param in command.params if param.name == "score")
assert repr(score_param.type) == "<FloatRange x<=100>"


def test_help(mod: ModuleType):
result = runner.invoke(mod.app, ["--help"])
assert result.exit_code == 0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import subprocess
import sys
import uuid

import typer
from typer.testing import CliRunner

from docs_src.parameter_types.uuid import tutorial001_py310 as mod
Expand All @@ -9,13 +11,27 @@
app = mod.app


def test_type_repr():
command = typer.main.get_command(app)
user_id_param = next(param for param in command.params if param.name == "user_id")
assert repr(user_id_param.type) == "UUID"


def test_main():
result = runner.invoke(app, ["d48edaa6-871a-4082-a196-4daab372d4a1"])
assert result.exit_code == 0
assert "USER_ID is d48edaa6-871a-4082-a196-4daab372d4a1" in result.output
assert "UUID version is: 4" in result.output


def test_main_with_uuid_object():
user_id = uuid.UUID("d48edaa6-871a-4082-a196-4daab372d4a1")
result = runner.invoke(app, [], default_map={"user_id": user_id})
assert result.exit_code == 0
assert "USER_ID is d48edaa6-871a-4082-a196-4daab372d4a1" in result.output
assert "UUID version is: 4" in result.output


def test_invalid_uuid():
result = runner.invoke(app, ["7479706572-72756c6573"])
assert result.exit_code != 0
Expand Down
Loading
Loading