Coverage for typer / models.py: 100%
181 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-11-09 00:15 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-11-09 00:15 +0000
1import inspect 1abcdefg
2import io 1abcdefg
3import os 1abcdefg
4import stat 1abcdefg
5from collections.abc import Callable, Sequence 1abcdefg
6from typing import ( 1abcdefg
7 TYPE_CHECKING,
8 Any,
9 ClassVar,
10 Optional,
11 TypeVar,
12 cast,
13)
15from . import _click 1abcdefg
16from ._click import types 1abcdefg
17from ._click.shell_completion import CompletionItem 1abcdefg
19if TYPE_CHECKING: # pragma: no cover 1abcdefg
20 from .core import TyperCommand, TyperGroup
21 from .main import Typer
24NoneType = type(None) 1abcdefg
26AnyType = type[Any] 1abcdefg
28Required = ... 1abcdefg
31class Context(_click.Context): 1abcdefg
32 """
33 The [`Context`](https://click.palletsprojects.com/en/stable/api/#click.Context) has some additional data about the current execution of your program.
34 When declaring it in a [callback](https://typer.tiangolo.com/tutorial/options/callback-and-context/) function,
35 you can access this additional information.
36 """
38 pass 1abcdefg
41class FileText(io.TextIOWrapper): 1abcdefg
42 """ 1abcdefg
43 Gives you a file-like object for reading text, and you will get a `str` data from it.
44 The default mode of this class is `mode="r"`.
46 **Example**
48 ```python
49 from typing import Annotated
51 import typer
53 app = typer.Typer()
55 @app.command()
56 def main(config: Annotated[typer.FileText, typer.Option()]):
57 for line in config:
58 print(f"Config line: {line}")
60 if __name__ == "__main__":
61 app()
62 ```
63 """
65 pass 1abcdefg
68class FileTextWrite(FileText): 1abcdefg
69 """ 1abcdefg
70 You can use this class for writing text. Alternatively, you can use `FileText` with `mode="w"`.
71 The default mode of this class is `mode="w"`.
73 **Example**
75 ```python
76 from typing import Annotated
78 import typer
80 app = typer.Typer()
82 @app.command()
83 def main(config: Annotated[typer.FileTextWrite, typer.Option()]):
84 config.write("Some config written by the app")
85 print("Config written")
87 if __name__ == "__main__":
88 app()
89 ```
90 """
92 pass 1abcdefg
95class FileBinaryRead(io.BufferedReader): 1abcdefg
96 """ 1abcdefg
97 You can use this class to read binary data, receiving `bytes`.
98 The default mode of this class is `mode="rb"`.
99 It is useful for reading binary files like images:
101 **Example**
103 ```python
104 from typing import Annotated
106 import typer
108 app = typer.Typer()
110 @app.command()
111 def main(file: Annotated[typer.FileBinaryRead, typer.Option()]):
112 processed_total = 0
113 for bytes_chunk in file:
114 # Process the bytes in bytes_chunk
115 processed_total += len(bytes_chunk)
116 print(f"Processed bytes total: {processed_total}")
118 if __name__ == "__main__":
119 app()
120 ```
121 """
123 pass 1abcdefg
126class FileBinaryWrite(io.BufferedWriter): 1abcdefg
127 """ 1abcdefg
128 You can use this class to write binary data: you pass `bytes` to it instead of strings.
129 The default mode of this class is `mode="wb"`.
130 It is useful for writing binary files like images:
132 **Example**
134 ```python
135 from typing import Annotated
137 import typer
139 app = typer.Typer()
141 @app.command()
142 def main(file: Annotated[typer.FileBinaryWrite, typer.Option()]):
143 first_line_str = "some settings\\n"
144 # You cannot write str directly to a binary file; encode it first
145 first_line_bytes = first_line_str.encode("utf-8")
146 # Then you can write the bytes
147 file.write(first_line_bytes)
148 # This is already bytes, it starts with b"
149 second_line = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o"
150 file.write(second_line)
151 print("Binary file written")
153 if __name__ == "__main__":
154 app()
155 ```
156 """
158 pass 1abcdefg
161class CallbackParam(_click.Parameter): 1abcdefg
162 """
163 In a callback function, you can declare a function parameter with type `CallbackParam`
164 to access the specific Click [`Parameter`](https://click.palletsprojects.com/en/stable/api/#click.Parameter) object.
165 """
167 pass 1abcdefg
170class DefaultPlaceholder: 1abcdefg
171 """
172 You shouldn't use this class directly.
174 It's used internally to recognize when a default value has been overwritten, even
175 if the new value is `None`.
176 """
178 def __init__(self, value: Any): 1abcdefg
179 self.value = value 1abcdefg
181 def __bool__(self) -> bool: 1abcdefg
182 return bool(self.value) 1abcdefg
185DefaultType = TypeVar("DefaultType") 1abcdefg
187CommandFunctionType = TypeVar("CommandFunctionType", bound=Callable[..., Any]) 1abcdefg
190def Default(value: DefaultType) -> DefaultType: 1abcdefg
191 """
192 You shouldn't use this function directly.
194 It's used internally to recognize when a default value has been overwritten, even
195 if the new value is `None`.
196 """
197 return DefaultPlaceholder(value) # type: ignore 1abcdefg
200class CommandInfo: 1abcdefg
201 def __init__( 1abcdefg
202 self,
203 name: str | None = None,
204 *,
205 cls: type["TyperCommand"] | None = None,
206 context_settings: dict[Any, Any] | None = None,
207 callback: Callable[..., Any] | None = None,
208 help: str | None = None,
209 epilog: str | None = None,
210 short_help: str | None = None,
211 options_metavar: str = "[OPTIONS]",
212 add_help_option: bool = True,
213 no_args_is_help: bool = False,
214 hidden: bool = False,
215 deprecated: bool = False,
216 # Rich settings
217 rich_help_panel: str | None = None,
218 ):
219 self.name = name 1abcdefg
220 self.cls = cls 1abcdefg
221 self.context_settings = context_settings 1abcdefg
222 self.callback = callback 1abcdefg
223 self.help = help 1abcdefg
224 self.epilog = epilog 1abcdefg
225 self.short_help = short_help 1abcdefg
226 self.options_metavar = options_metavar 1abcdefg
227 self.add_help_option = add_help_option 1abcdefg
228 self.no_args_is_help = no_args_is_help 1abcdefg
229 self.hidden = hidden 1abcdefg
230 self.deprecated = deprecated 1abcdefg
231 # Rich settings
232 self.rich_help_panel = rich_help_panel 1abcdefg
235class TyperInfo: 1abcdefg
236 def __init__( 1abcdefg
237 self,
238 typer_instance: Optional["Typer"] = Default(None),
239 *,
240 name: str | None = Default(None),
241 cls: type["TyperGroup"] | None = Default(None),
242 invoke_without_command: bool = Default(False),
243 no_args_is_help: bool = Default(False),
244 subcommand_metavar: str | None = Default(None),
245 chain: bool = Default(False),
246 result_callback: Callable[..., Any] | None = Default(None),
247 # Command
248 context_settings: dict[Any, Any] | None = Default(None),
249 callback: Callable[..., Any] | None = Default(None),
250 help: str | None = Default(None),
251 epilog: str | None = Default(None),
252 short_help: str | None = Default(None),
253 options_metavar: str = Default("[OPTIONS]"),
254 add_help_option: bool = Default(True),
255 hidden: bool = Default(False),
256 deprecated: bool = Default(False),
257 # Rich settings
258 rich_help_panel: str | None = Default(None),
259 ):
260 self.typer_instance = typer_instance 1abcdefg
261 self.name = name 1abcdefg
262 self.cls = cls 1abcdefg
263 self.invoke_without_command = invoke_without_command 1abcdefg
264 self.no_args_is_help = no_args_is_help 1abcdefg
265 self.subcommand_metavar = subcommand_metavar 1abcdefg
266 self.chain = chain 1abcdefg
267 self.result_callback = result_callback 1abcdefg
268 self.context_settings = context_settings 1abcdefg
269 self.callback = callback 1abcdefg
270 self.help = help 1abcdefg
271 self.epilog = epilog 1abcdefg
272 self.short_help = short_help 1abcdefg
273 self.options_metavar = options_metavar 1abcdefg
274 self.add_help_option = add_help_option 1abcdefg
275 self.hidden = hidden 1abcdefg
276 self.deprecated = deprecated 1abcdefg
277 self.rich_help_panel = rich_help_panel 1abcdefg
280class ParameterInfo: 1abcdefg
281 def __init__( 1abcdefg
282 self,
283 *,
284 default: Any | None = None,
285 param_decls: Sequence[str] | None = None,
286 callback: Callable[..., Any] | None = None,
287 metavar: str | None = None,
288 expose_value: bool = True,
289 is_eager: bool = False,
290 envvar: str | list[str] | None = None,
291 # Note that shell_complete is not fully supported and will be removed in future versions
292 # TODO: Remove shell_complete in a future version (after 0.16.0)
293 shell_complete: Callable[
294 [_click.Context, _click.Parameter, str],
295 list["CompletionItem"] | list[str],
296 ]
297 | None = None,
298 autocompletion: Callable[..., Any] | None = None,
299 default_factory: Callable[[], Any] | None = None,
300 # Custom type
301 parser: Callable[[str], Any] | None = None,
302 click_type: types.ParamType | None = None,
303 # TyperArgument
304 show_default: bool | str = True,
305 show_choices: bool = True,
306 show_envvar: bool = True,
307 help: str | None = None,
308 hidden: bool = False,
309 # Choice
310 case_sensitive: bool = True,
311 # Numbers
312 min: int | float | None = None,
313 max: int | float | None = None,
314 clamp: bool = False,
315 # DateTime
316 formats: list[str] | None = None,
317 # File
318 mode: str | None = None,
319 encoding: str | None = None,
320 errors: str | None = "strict",
321 lazy: bool | None = None,
322 atomic: bool = False,
323 # Path
324 exists: bool = False,
325 file_okay: bool = True,
326 dir_okay: bool = True,
327 writable: bool = False,
328 readable: bool = True,
329 resolve_path: bool = False,
330 allow_dash: bool = False,
331 path_type: None | type[str] | type[bytes] = None,
332 # Rich settings
333 rich_help_panel: str | None = None,
334 ):
335 # Check if user has provided multiple custom parsers
336 if parser and click_type: 1abcdefg
337 raise ValueError( 1abcdefg
338 "Multiple custom type parsers provided. "
339 "`parser` and `click_type` may not both be provided."
340 )
342 self.default = default 1abcdefg
343 self.param_decls = param_decls 1abcdefg
344 self.callback = callback 1abcdefg
345 self.metavar = metavar 1abcdefg
346 self.expose_value = expose_value 1abcdefg
347 self.is_eager = is_eager 1abcdefg
348 self.envvar = envvar 1abcdefg
349 self.shell_complete = shell_complete 1abcdefg
350 self.autocompletion = autocompletion 1abcdefg
351 self.default_factory = default_factory 1abcdefg
352 # Custom type
353 self.parser = parser 1abcdefg
354 self.click_type = click_type 1abcdefg
355 # TyperArgument
356 self.show_default = show_default 1abcdefg
357 self.show_choices = show_choices 1abcdefg
358 self.show_envvar = show_envvar 1abcdefg
359 self.help = help 1abcdefg
360 self.hidden = hidden 1abcdefg
361 # Choice
362 self.case_sensitive = case_sensitive 1abcdefg
363 # Numbers
364 self.min = min 1abcdefg
365 self.max = max 1abcdefg
366 self.clamp = clamp 1abcdefg
367 # DateTime
368 self.formats = formats 1abcdefg
369 # File
370 self.mode = mode 1abcdefg
371 self.encoding = encoding 1abcdefg
372 self.errors = errors 1abcdefg
373 self.lazy = lazy 1abcdefg
374 self.atomic = atomic 1abcdefg
375 # Path
376 self.exists = exists 1abcdefg
377 self.file_okay = file_okay 1abcdefg
378 self.dir_okay = dir_okay 1abcdefg
379 self.writable = writable 1abcdefg
380 self.readable = readable 1abcdefg
381 self.resolve_path = resolve_path 1abcdefg
382 self.allow_dash = allow_dash 1abcdefg
383 self.path_type = path_type 1abcdefg
384 # Rich settings
385 self.rich_help_panel = rich_help_panel 1abcdefg
388class OptionInfo(ParameterInfo): 1abcdefg
389 def __init__( 1abcdefg
390 self,
391 *,
392 # ParameterInfo
393 default: Any | None = None,
394 param_decls: Sequence[str] | None = None,
395 callback: Callable[..., Any] | None = None,
396 metavar: str | None = None,
397 expose_value: bool = True,
398 is_eager: bool = False,
399 envvar: str | list[str] | None = None,
400 # Note that shell_complete is not fully supported and will be removed in future versions
401 # TODO: Remove shell_complete in a future version (after 0.16.0)
402 shell_complete: Callable[
403 [_click.Context, _click.Parameter, str],
404 list["CompletionItem"] | list[str],
405 ]
406 | None = None,
407 autocompletion: Callable[..., Any] | None = None,
408 default_factory: Callable[[], Any] | None = None,
409 # Custom type
410 parser: Callable[[str], Any] | None = None,
411 click_type: types.ParamType | None = None,
412 # Option
413 show_default: bool | str = True,
414 prompt: bool | str = False,
415 confirmation_prompt: bool = False,
416 prompt_required: bool = True,
417 hide_input: bool = False,
418 # TODO: remove is_flag and flag_value in a future release
419 is_flag: bool | None = None,
420 flag_value: Any | None = None,
421 count: bool = False,
422 allow_from_autoenv: bool = True,
423 help: str | None = None,
424 hidden: bool = False,
425 show_choices: bool = True,
426 show_envvar: bool = True,
427 # Choice
428 case_sensitive: bool = True,
429 # Numbers
430 min: int | float | None = None,
431 max: int | float | None = None,
432 clamp: bool = False,
433 # DateTime
434 formats: list[str] | None = None,
435 # File
436 mode: str | None = None,
437 encoding: str | None = None,
438 errors: str | None = "strict",
439 lazy: bool | None = None,
440 atomic: bool = False,
441 # Path
442 exists: bool = False,
443 file_okay: bool = True,
444 dir_okay: bool = True,
445 writable: bool = False,
446 readable: bool = True,
447 resolve_path: bool = False,
448 allow_dash: bool = False,
449 path_type: None | type[str] | type[bytes] = None,
450 # Rich settings
451 rich_help_panel: str | None = None,
452 ):
453 super().__init__( 1abcdefg
454 default=default,
455 param_decls=param_decls,
456 callback=callback,
457 metavar=metavar,
458 expose_value=expose_value,
459 is_eager=is_eager,
460 envvar=envvar,
461 shell_complete=shell_complete,
462 autocompletion=autocompletion,
463 default_factory=default_factory,
464 # Custom type
465 parser=parser,
466 click_type=click_type,
467 # TyperArgument
468 show_default=show_default,
469 show_choices=show_choices,
470 show_envvar=show_envvar,
471 help=help,
472 hidden=hidden,
473 # Choice
474 case_sensitive=case_sensitive,
475 # Numbers
476 min=min,
477 max=max,
478 clamp=clamp,
479 # DateTime
480 formats=formats,
481 # File
482 mode=mode,
483 encoding=encoding,
484 errors=errors,
485 lazy=lazy,
486 atomic=atomic,
487 # Path
488 exists=exists,
489 file_okay=file_okay,
490 dir_okay=dir_okay,
491 writable=writable,
492 readable=readable,
493 resolve_path=resolve_path,
494 allow_dash=allow_dash,
495 path_type=path_type,
496 # Rich settings
497 rich_help_panel=rich_help_panel,
498 )
499 if is_flag is not None or flag_value is not None: 1abcdefg
500 import warnings 1abcdefg
502 warnings.warn( 1abcdefg
503 "The 'is_flag' and 'flag_value' parameters are not supported by Typer "
504 "and will be removed entirely in a future release.",
505 DeprecationWarning,
506 stacklevel=2,
507 )
508 self.prompt = prompt 1abcdefg
509 self.confirmation_prompt = confirmation_prompt 1abcdefg
510 self.prompt_required = prompt_required 1abcdefg
511 self.hide_input = hide_input 1abcdefg
512 self.count = count 1abcdefg
513 self.allow_from_autoenv = allow_from_autoenv 1abcdefg
516class ArgumentInfo(ParameterInfo): 1abcdefg
517 def __init__( 1abcdefg
518 self,
519 *,
520 # ParameterInfo
521 default: Any | None = None,
522 param_decls: Sequence[str] | None = None,
523 callback: Callable[..., Any] | None = None,
524 metavar: str | None = None,
525 expose_value: bool = True,
526 is_eager: bool = False,
527 envvar: str | list[str] | None = None,
528 # Note that shell_complete is not fully supported and will be removed in future versions
529 # TODO: Remove shell_complete in a future version (after 0.16.0)
530 shell_complete: Callable[
531 [_click.Context, _click.Parameter, str],
532 list["CompletionItem"] | list[str],
533 ]
534 | None = None,
535 autocompletion: Callable[..., Any] | None = None,
536 default_factory: Callable[[], Any] | None = None,
537 # Custom type
538 parser: Callable[[str], Any] | None = None,
539 click_type: types.ParamType | None = None,
540 # TyperArgument
541 show_default: bool | str = True,
542 show_choices: bool = True,
543 show_envvar: bool = True,
544 help: str | None = None,
545 hidden: bool = False,
546 # Choice
547 case_sensitive: bool = True,
548 # Numbers
549 min: int | float | None = None,
550 max: int | float | None = None,
551 clamp: bool = False,
552 # DateTime
553 formats: list[str] | None = None,
554 # File
555 mode: str | None = None,
556 encoding: str | None = None,
557 errors: str | None = "strict",
558 lazy: bool | None = None,
559 atomic: bool = False,
560 # Path
561 exists: bool = False,
562 file_okay: bool = True,
563 dir_okay: bool = True,
564 writable: bool = False,
565 readable: bool = True,
566 resolve_path: bool = False,
567 allow_dash: bool = False,
568 path_type: None | type[str] | type[bytes] = None,
569 # Rich settings
570 rich_help_panel: str | None = None,
571 ):
572 super().__init__( 1abcdefg
573 default=default,
574 param_decls=param_decls,
575 callback=callback,
576 metavar=metavar,
577 expose_value=expose_value,
578 is_eager=is_eager,
579 envvar=envvar,
580 shell_complete=shell_complete,
581 autocompletion=autocompletion,
582 default_factory=default_factory,
583 # Custom type
584 parser=parser,
585 click_type=click_type,
586 # TyperArgument
587 show_default=show_default,
588 show_choices=show_choices,
589 show_envvar=show_envvar,
590 help=help,
591 hidden=hidden,
592 # Choice
593 case_sensitive=case_sensitive,
594 # Numbers
595 min=min,
596 max=max,
597 clamp=clamp,
598 # DateTime
599 formats=formats,
600 # File
601 mode=mode,
602 encoding=encoding,
603 errors=errors,
604 lazy=lazy,
605 atomic=atomic,
606 # Path
607 exists=exists,
608 file_okay=file_okay,
609 dir_okay=dir_okay,
610 writable=writable,
611 readable=readable,
612 resolve_path=resolve_path,
613 allow_dash=allow_dash,
614 path_type=path_type,
615 # Rich settings
616 rich_help_panel=rich_help_panel,
617 )
620class ParamMeta: 1abcdefg
621 empty = inspect.Parameter.empty 1abcdefg
623 def __init__( 1abcdefg
624 self,
625 *,
626 name: str,
627 default: Any = inspect.Parameter.empty,
628 annotation: Any = inspect.Parameter.empty,
629 ) -> None:
630 self.name = name 1abcdefg
631 self.default = default 1abcdefg
632 self.annotation = annotation 1abcdefg
635class DeveloperExceptionConfig: 1abcdefg
636 def __init__( 1abcdefg
637 self,
638 *,
639 pretty_exceptions_enable: bool = True,
640 pretty_exceptions_show_locals: bool = True,
641 pretty_exceptions_short: bool = True,
642 ) -> None:
643 self.pretty_exceptions_enable = pretty_exceptions_enable 1abcdefg
644 self.pretty_exceptions_show_locals = pretty_exceptions_show_locals 1abcdefg
645 self.pretty_exceptions_short = pretty_exceptions_short 1abcdefg
648class TyperPath(types.ParamType): 1abcdefg
649 # Based originally on code from Click 8.3.1
650 # Partly rewritten and added an override for shell_complete
652 envvar_list_splitter: ClassVar[str] = os.path.pathsep 1abcdefg
654 def __init__( 1abcdefg
655 self,
656 exists: bool = False,
657 file_okay: bool = True,
658 dir_okay: bool = True,
659 writable: bool = False,
660 readable: bool = True,
661 resolve_path: bool = False,
662 allow_dash: bool = False,
663 path_type: type[Any] | None = None,
664 ):
665 self.exists = exists 1abcdefg
666 self.file_okay = file_okay 1abcdefg
667 self.dir_okay = dir_okay 1abcdefg
668 self.readable = readable 1abcdefg
669 self.writable = writable 1abcdefg
670 self.resolve_path = resolve_path 1abcdefg
671 self.allow_dash = allow_dash 1abcdefg
672 self.type = path_type 1abcdefg
674 if self.file_okay and not self.dir_okay: 1abcdefg
675 self.name = "file" 1abcdefg
676 elif self.dir_okay and not self.file_okay: 1abcdefg
677 self.name = "directory" 1abcdefg
678 else:
679 self.name = "path" 1abcdefg
681 def coerce_path_result( 1abcdefg
682 self, value: str | os.PathLike[str]
683 ) -> str | bytes | os.PathLike[str]:
684 if self.type is not None and not isinstance(value, self.type): 1abcdefg
685 if (
686 self.type is str
687 ): # pragma: no cover # TODO: perhaps this branch can't be hit and should be removed
688 return os.fsdecode(value)
689 elif self.type is bytes: 1abcdefg
690 return os.fsencode(value) 1abcdefg
691 else:
692 return cast("os.PathLike[str]", self.type(value)) 1abcdefg
694 return value 1abcdefg
696 def convert( # ty: ignore[invalid-method-override] 1abcdefg
697 self,
698 value: str | os.PathLike[str],
699 param: _click.Parameter | None,
700 ctx: Context | None, # type: ignore[override]
701 ) -> str | bytes | os.PathLike[str]:
702 rv = value 1abcdefg
704 is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") 1abcdefg
706 if not is_dash: 1abcdefg
707 if self.resolve_path: 1abcdefg
708 rv = os.path.realpath(rv) 1abcdefg
710 try: 1abcdefg
711 st = os.stat(rv) 1abcdefg
712 except OSError: 1abcdefg
713 if not self.exists: 1abcdefg
714 return self.coerce_path_result(rv) 1abcdefg
715 self.fail( 1abcdefg
716 f"{self.name.title()} {_click.utils.format_filename(value)!r} does not exist.",
717 param,
718 ctx,
719 )
721 name = self.name.title() 1abcdefg
722 loc = repr(_click.utils.format_filename(value)) 1abcdefg
723 if not self.file_okay and stat.S_ISREG(st.st_mode): 1abcdefg
724 self.fail(f"{name} {loc} is a file.", param, ctx) 1abcdefg
726 if not self.dir_okay and stat.S_ISDIR(st.st_mode): 1abcdefg
727 self.fail(f"{name} {loc} is a directory.", param, ctx) 1abcdefg
729 if self.readable and not os.access(rv, os.R_OK): 1abcdefg
730 self.fail(f"{name} {loc} is not readable.", param, ctx) 1abcdefg
732 if self.writable and not os.access(rv, os.W_OK): 1abcdefg
733 self.fail(f"{name} {loc} is not writable.", param, ctx) 1abcdefg
735 return self.coerce_path_result(rv) 1abcdefg
737 def shell_complete( 1abcdefg
738 self, ctx: _click.Context, param: _click.Parameter, incomplete: str
739 ) -> list[CompletionItem]:
740 """Return an empty list so that the autocompletion functionality
741 will work properly from the commandline.
742 """
743 return [] 1abcdefg