🎨 Fix types and format
This commit is contained in:
parent
a3d337f98b
commit
b52fc16bba
7 changed files with 110 additions and 96 deletions
|
@ -5,8 +5,8 @@
|
|||
<em>Typer: CLIs with autocompletion. While developing and using.</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/tiangolo/typer" target="_blank">
|
||||
<img src="https://travis-ci.org/tiangolo/typer.svg?branch=master" alt="Build Status">
|
||||
<a href="https://travis-ci.com/tiangolo/typer" target="_blank">
|
||||
<img src="https://travis-ci.com/tiangolo/typer.svg?branch=master" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/tiangolo/typer" target="_blank">
|
||||
<img src="https://codecov.io/gh/tiangolo/typer/branch/master/graph/badge.svg" alt="Coverage">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from typer.testing import CliRunner
|
||||
import typer
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from first_steps.tutorial001 import main
|
||||
|
||||
|
|
|
@ -2,46 +2,44 @@
|
|||
|
||||
__version__ = "0.0.1"
|
||||
|
||||
from .main import Typer, run # noqa
|
||||
from .params import Option, Argument # noqa
|
||||
from .models import Context, TextFile, BinaryFileRead, BinaryFileWrite # noqa
|
||||
|
||||
from click.exceptions import ( # noqa
|
||||
Abort,
|
||||
BadArgumentUsage,
|
||||
BadOptionUsage,
|
||||
BadParameter,
|
||||
ClickException,
|
||||
FileError,
|
||||
MissingParameter,
|
||||
NoSuchOption,
|
||||
UsageError,
|
||||
)
|
||||
# Terminal functions
|
||||
from click.termui import ( # noqa
|
||||
clear,
|
||||
confirm,
|
||||
echo_via_pager,
|
||||
edit,
|
||||
get_terminal_size,
|
||||
getchar,
|
||||
launch,
|
||||
pause,
|
||||
progressbar,
|
||||
prompt,
|
||||
secho,
|
||||
style,
|
||||
unstyle,
|
||||
)
|
||||
# Utilities
|
||||
from click.utils import ( # noqa
|
||||
echo,
|
||||
get_binary_stream,
|
||||
get_text_stream,
|
||||
open_file,
|
||||
format_filename,
|
||||
get_app_dir,
|
||||
get_binary_stream,
|
||||
get_os_args,
|
||||
get_text_stream,
|
||||
open_file,
|
||||
)
|
||||
|
||||
# Terminal functions
|
||||
from click.termui import ( # noqa
|
||||
prompt,
|
||||
confirm,
|
||||
get_terminal_size,
|
||||
echo_via_pager,
|
||||
progressbar,
|
||||
clear,
|
||||
style,
|
||||
unstyle,
|
||||
secho,
|
||||
edit,
|
||||
launch,
|
||||
getchar,
|
||||
pause,
|
||||
)
|
||||
|
||||
from click.exceptions import ( # noqa
|
||||
ClickException,
|
||||
UsageError,
|
||||
BadParameter,
|
||||
FileError,
|
||||
Abort,
|
||||
NoSuchOption,
|
||||
BadOptionUsage,
|
||||
BadArgumentUsage,
|
||||
MissingParameter,
|
||||
)
|
||||
from .main import Typer, run # noqa
|
||||
from .models import BinaryFileRead, BinaryFileWrite, Context, TextFile # noqa
|
||||
from .params import Argument, Option # noqa
|
||||
|
|
|
@ -3,25 +3,26 @@ from datetime import datetime
|
|||
from enum import Enum
|
||||
from functools import update_wrapper
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
|
||||
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, Union
|
||||
from uuid import UUID
|
||||
|
||||
import click
|
||||
|
||||
from .models import (
|
||||
AnyType,
|
||||
ArgumentInfo,
|
||||
BinaryFileRead,
|
||||
BinaryFileWrite,
|
||||
CommandFunctionType,
|
||||
CommandInfo,
|
||||
Default,
|
||||
DefaultPlaceholder,
|
||||
NoneType,
|
||||
OptionInfo,
|
||||
ParameterInfo,
|
||||
Required,
|
||||
TyperInfo,
|
||||
TextFile,
|
||||
AnyType,
|
||||
Default,
|
||||
DefaultPlaceholder,
|
||||
TyperInfo,
|
||||
)
|
||||
|
||||
|
||||
|
@ -38,7 +39,7 @@ class Typer:
|
|||
result_callback: Optional[Callable] = Default(None),
|
||||
# Command
|
||||
context_settings: Optional[Dict[Any, Any]] = Default(None),
|
||||
callback: Optional[Callable[..., Any]] = Default(None),
|
||||
callback: Optional[Callable] = Default(None),
|
||||
help: Optional[str] = Default(None),
|
||||
epilog: Optional[str] = Default(None),
|
||||
short_help: Optional[str] = Default(None),
|
||||
|
@ -88,8 +89,8 @@ class Typer:
|
|||
add_help_option: bool = Default(True),
|
||||
hidden: bool = Default(False),
|
||||
deprecated: bool = Default(False),
|
||||
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
||||
def decorator(f: Callable[..., Any]):
|
||||
) -> Callable[[CommandFunctionType], CommandFunctionType]:
|
||||
def decorator(f: CommandFunctionType) -> CommandFunctionType:
|
||||
self.registered_callback = TyperInfo(
|
||||
name=name,
|
||||
cls=cls,
|
||||
|
@ -125,11 +126,11 @@ class Typer:
|
|||
add_help_option: bool = True,
|
||||
hidden: bool = False,
|
||||
deprecated: bool = False,
|
||||
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
||||
) -> Callable[[CommandFunctionType], CommandFunctionType]:
|
||||
if cls is None:
|
||||
cls = click.Command
|
||||
|
||||
def decorator(f):
|
||||
def decorator(f: CommandFunctionType) -> CommandFunctionType:
|
||||
self.registered_commands.append(
|
||||
CommandInfo(
|
||||
name=name,
|
||||
|
@ -162,7 +163,7 @@ class Typer:
|
|||
result_callback: Optional[Callable] = Default(None),
|
||||
# Command
|
||||
context_settings: Optional[Dict[Any, Any]] = Default(None),
|
||||
callback: Optional[Callable[..., Any]] = Default(None),
|
||||
callback: Optional[Callable] = Default(None),
|
||||
help: Optional[str] = Default(None),
|
||||
epilog: Optional[str] = Default(None),
|
||||
short_help: Optional[str] = Default(None),
|
||||
|
@ -170,7 +171,7 @@ class Typer:
|
|||
add_help_option: bool = Default(True),
|
||||
hidden: bool = Default(False),
|
||||
deprecated: bool = Default(False),
|
||||
):
|
||||
) -> None:
|
||||
self.registered_groups.append(
|
||||
TyperInfo(
|
||||
typer_instance,
|
||||
|
@ -193,16 +194,16 @@ class Typer:
|
|||
)
|
||||
)
|
||||
|
||||
def __call__(self):
|
||||
def __call__(self) -> Any:
|
||||
return get_command(self)()
|
||||
|
||||
|
||||
def get_group(typer_instance: Typer) -> click.Group:
|
||||
def get_group(typer_instance: Typer) -> click.Command:
|
||||
group = get_group_from_info(TyperInfo(typer_instance))
|
||||
return group
|
||||
|
||||
|
||||
def get_command(typer_instance: Typer):
|
||||
def get_command(typer_instance: Typer) -> click.Command:
|
||||
if (
|
||||
typer_instance.registered_callback
|
||||
or typer_instance.registered_groups
|
||||
|
@ -211,9 +212,10 @@ def get_command(typer_instance: Typer):
|
|||
return get_group(typer_instance)
|
||||
elif len(typer_instance.registered_commands) == 1:
|
||||
return get_command_from_info(typer_instance.registered_commands[0])
|
||||
assert False, "Could not get a command for this Typer instance"
|
||||
|
||||
|
||||
def get_group_name(typer_info: TyperInfo):
|
||||
def get_group_name(typer_info: TyperInfo) -> str:
|
||||
if typer_info.callback:
|
||||
# Priority 1: Callback passed in app.add_typer()
|
||||
return get_command_name(typer_info.callback.__name__)
|
||||
|
@ -225,9 +227,10 @@ def get_group_name(typer_info: TyperInfo):
|
|||
return get_command_name(registered_callback.callback.__name__)
|
||||
if typer_info.typer_instance.info.callback:
|
||||
return get_command_name(typer_info.typer_instance.info.callback.__name__)
|
||||
assert False, "A Group name could not be created"
|
||||
|
||||
|
||||
def solve_typer_info_defaults(typer_info: TyperInfo):
|
||||
def solve_typer_info_defaults(typer_info: TyperInfo) -> TyperInfo:
|
||||
values = {}
|
||||
name = None
|
||||
for name, value in typer_info.__dict__.items():
|
||||
|
@ -256,7 +259,7 @@ def solve_typer_info_defaults(typer_info: TyperInfo):
|
|||
return TyperInfo(**values)
|
||||
|
||||
|
||||
def get_group_from_info(group_info: TyperInfo):
|
||||
def get_group_from_info(group_info: TyperInfo) -> click.Command:
|
||||
assert (
|
||||
group_info.typer_instance
|
||||
), "A Typer instance is needed to generate a Click Group"
|
||||
|
@ -274,8 +277,8 @@ def get_group_from_info(group_info: TyperInfo):
|
|||
context_param_name,
|
||||
) = get_params_convertors_ctx_param_name_from_function(solved_info.callback)
|
||||
cls = solved_info.cls or click.Group
|
||||
group = cls(
|
||||
name=solved_info.name,
|
||||
group = cls( # type: ignore
|
||||
name=solved_info.name or "",
|
||||
commands=commands,
|
||||
invoke_without_command=solved_info.invoke_without_command,
|
||||
no_args_is_help=solved_info.no_args_is_help,
|
||||
|
@ -289,7 +292,7 @@ def get_group_from_info(group_info: TyperInfo):
|
|||
convertors=convertors,
|
||||
context_param_name=context_param_name,
|
||||
),
|
||||
params=params,
|
||||
params=params, # type: ignore
|
||||
help=solved_info.help,
|
||||
epilog=solved_info.epilog,
|
||||
short_help=solved_info.short_help,
|
||||
|
@ -301,13 +304,13 @@ def get_group_from_info(group_info: TyperInfo):
|
|||
return group
|
||||
|
||||
|
||||
def get_command_name(name: str):
|
||||
def get_command_name(name: str) -> str:
|
||||
return name.lower().replace("_", "-")
|
||||
|
||||
|
||||
def get_params_convertors_ctx_param_name_from_function(
|
||||
callback: Optional[Callable[..., Any]]
|
||||
):
|
||||
) -> Tuple[List[Union[click.Argument, click.Option]], Dict[str, Any], Optional[str]]:
|
||||
params = []
|
||||
convertors = {}
|
||||
context_param_name = None
|
||||
|
@ -324,7 +327,7 @@ def get_params_convertors_ctx_param_name_from_function(
|
|||
return params, convertors, context_param_name
|
||||
|
||||
|
||||
def get_command_from_info(command_info: CommandInfo):
|
||||
def get_command_from_info(command_info: CommandInfo) -> click.Command:
|
||||
assert command_info.callback, "A command must have a callback function"
|
||||
name = command_info.name or get_command_name(command_info.callback.__name__)
|
||||
(
|
||||
|
@ -342,7 +345,7 @@ def get_command_from_info(command_info: CommandInfo):
|
|||
convertors=convertors,
|
||||
context_param_name=context_param_name,
|
||||
),
|
||||
params=params,
|
||||
params=params, # type: ignore
|
||||
help=command_info.help,
|
||||
epilog=command_info.epilog,
|
||||
short_help=command_info.short_help,
|
||||
|
@ -354,15 +357,16 @@ def get_command_from_info(command_info: CommandInfo):
|
|||
return command
|
||||
|
||||
|
||||
def param_path_convertor(value: Optional[str] = None):
|
||||
def param_path_convertor(value: Optional[str] = None) -> Optional[Path]:
|
||||
if value is not None:
|
||||
return Path(value)
|
||||
return None
|
||||
|
||||
|
||||
def generate_enum_convertor(enum: Type[Enum]):
|
||||
def generate_enum_convertor(enum: Type[Enum]) -> Callable:
|
||||
lower_val_map = {str(val.value).lower(): val for val in enum}
|
||||
|
||||
def convertor(value: Any):
|
||||
def convertor(value: Any) -> Any:
|
||||
if value is not None:
|
||||
low = str(value).lower()
|
||||
if low in lower_val_map:
|
||||
|
@ -374,11 +378,11 @@ def generate_enum_convertor(enum: Type[Enum]):
|
|||
|
||||
def get_callback(
|
||||
*,
|
||||
callback: Optional[Callable[..., Any]] = None,
|
||||
params: List[click.Parameter] = [],
|
||||
callback: Optional[Callable] = None,
|
||||
params: Sequence[click.Parameter] = [],
|
||||
convertors: Dict[str, Callable[[str], Any]] = {},
|
||||
context_param_name: str = None,
|
||||
) -> Optional[Callable[..., Any]]:
|
||||
) -> Optional[Callable]:
|
||||
if not callback:
|
||||
return None
|
||||
signature = inspect.signature(callback)
|
||||
|
@ -388,7 +392,7 @@ def get_callback(
|
|||
for param in params:
|
||||
use_params[param.name] = param.default
|
||||
|
||||
def wrapper(**kwargs):
|
||||
def wrapper(**kwargs: Any) -> Any:
|
||||
for k, v in kwargs.items():
|
||||
if k in convertors:
|
||||
use_params[k] = convertors[k](v)
|
||||
|
@ -396,13 +400,15 @@ def get_callback(
|
|||
use_params[k] = v
|
||||
if context_param_name:
|
||||
use_params[context_param_name] = click.get_current_context()
|
||||
return callback(**use_params)
|
||||
return callback(**use_params) # type: ignore
|
||||
|
||||
update_wrapper(wrapper, callback)
|
||||
return wrapper
|
||||
|
||||
|
||||
def get_click_type(*, annotation: Any, parameter_info: ParameterInfo):
|
||||
def get_click_type(
|
||||
*, annotation: Any, parameter_info: ParameterInfo
|
||||
) -> click.ParamType:
|
||||
if annotation == str:
|
||||
return click.STRING
|
||||
elif annotation == int:
|
||||
|
@ -485,7 +491,9 @@ def lenient_issubclass(
|
|||
return isinstance(cls, type) and issubclass(cls, class_or_tuple)
|
||||
|
||||
|
||||
def get_click_param(param: inspect.Parameter):
|
||||
def get_click_param(
|
||||
param: inspect.Parameter,
|
||||
) -> Tuple[Union[click.Argument, click.Option], Any]:
|
||||
# First, find out what will be:
|
||||
# * ParamInfo (ArgumentInfo or OptionInfo)
|
||||
# * default_value
|
||||
|
@ -511,7 +519,7 @@ def get_click_param(param: inspect.Parameter):
|
|||
annotation = str
|
||||
main_type = annotation
|
||||
is_list = False
|
||||
parameter_type = None
|
||||
parameter_type: Any = None
|
||||
is_flag = None
|
||||
origin = getattr(main_type, "__origin__", None)
|
||||
if origin is not None:
|
||||
|
@ -624,9 +632,10 @@ def get_click_param(param: inspect.Parameter):
|
|||
),
|
||||
convertor,
|
||||
)
|
||||
assert False, "A click.Parameter should be returned"
|
||||
|
||||
|
||||
def run(function: Callable):
|
||||
def run(function: Callable) -> Any:
|
||||
app = Typer()
|
||||
app.command()(function)
|
||||
app()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import io
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
|
@ -7,12 +8,10 @@ from typing import (
|
|||
Optional,
|
||||
Sequence,
|
||||
Type,
|
||||
Union,
|
||||
TypeVar,
|
||||
Union,
|
||||
)
|
||||
|
||||
import io
|
||||
|
||||
import click
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -49,15 +48,18 @@ class DefaultPlaceholder:
|
|||
It's used internally to recognize when a default value has been overwritten, even
|
||||
if the new value is `None`.
|
||||
"""
|
||||
|
||||
def __init__(self, value: Any):
|
||||
self.value = value
|
||||
|
||||
def __bool__(self):
|
||||
def __bool__(self) -> bool:
|
||||
return bool(self.value)
|
||||
|
||||
|
||||
DefaultType = TypeVar("DefaultType")
|
||||
|
||||
CommandFunctionType = TypeVar("CommandFunctionType", bound=Callable[..., Any])
|
||||
|
||||
|
||||
def Default(value: DefaultType) -> DefaultType:
|
||||
"""
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
from typing import Optional, Any, List, Callable, Union, Type
|
||||
from .models import OptionInfo, ArgumentInfo
|
||||
from typing import Any, Callable, List, Optional, Type, Union
|
||||
|
||||
import click
|
||||
|
||||
from .models import ArgumentInfo, OptionInfo
|
||||
|
||||
|
||||
def Option(
|
||||
# Parameter
|
||||
|
@ -51,7 +53,7 @@ def Option(
|
|||
resolve_path: bool = False,
|
||||
allow_dash: bool = False,
|
||||
path_type: Union[None, Type[str], Type[bytes]] = None,
|
||||
):
|
||||
) -> Any:
|
||||
return OptionInfo(
|
||||
# Parameter
|
||||
default=default,
|
||||
|
@ -136,7 +138,7 @@ def Argument(
|
|||
resolve_path: bool = False,
|
||||
allow_dash: bool = False,
|
||||
path_type: Union[None, Type[str], Type[bytes]] = None,
|
||||
):
|
||||
) -> Any:
|
||||
return ArgumentInfo(
|
||||
# Parameter
|
||||
default=default,
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
from click.testing import Result, CliRunner as ClickCliRunner # noqa
|
||||
from typer.main import get_command as _get_command
|
||||
from typing import IO, Any, Iterable, Mapping, Optional, Text, Union
|
||||
|
||||
from click.testing import CliRunner as ClickCliRunner, Result # noqa
|
||||
from typer.main import Typer, get_command as _get_command
|
||||
|
||||
|
||||
class CliRunner(ClickCliRunner):
|
||||
def invoke(
|
||||
def invoke( # type: ignore
|
||||
self,
|
||||
cli,
|
||||
args=None,
|
||||
input=None,
|
||||
env=None,
|
||||
catch_exceptions=True,
|
||||
color=False,
|
||||
mix_stderr=False,
|
||||
**extra
|
||||
app: Typer,
|
||||
cli: Typer,
|
||||
args: Optional[Union[str, Iterable[str]]] = None,
|
||||
input: Optional[Union[bytes, Text, IO[Any]]] = None,
|
||||
env: Optional[Mapping[str, str]] = None,
|
||||
catch_exceptions: bool = True,
|
||||
color: bool = False,
|
||||
mix_stderr: bool = False,
|
||||
**extra: Any,
|
||||
) -> Result:
|
||||
use_cli = _get_command(cli)
|
||||
use_cli = _get_command(app)
|
||||
return super().invoke(
|
||||
use_cli,
|
||||
args=args,
|
||||
|
@ -23,5 +26,5 @@ class CliRunner(ClickCliRunner):
|
|||
catch_exceptions=catch_exceptions,
|
||||
color=color,
|
||||
mix_stderr=mix_stderr,
|
||||
**extra
|
||||
**extra,
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue