typer-examples 1.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib.metadata import PackageNotFoundError
4
+ from importlib.metadata import version as _pkg_version
5
+ from typing import Callable, Optional
6
+
7
+ import typer as _typer
8
+
9
+ from ._hook import install_hook, register_app, set_config
10
+ from ._models import Example, ExamplesConfig
11
+ from .docs import get_all_examples
12
+
13
+ __all__ = [
14
+ "example",
15
+ "install",
16
+ "configure",
17
+ "ExamplesConfig",
18
+ "get_all_examples",
19
+ ]
20
+
21
+ try:
22
+ __version__ = _pkg_version("typer-examples")
23
+ except PackageNotFoundError: # source tree, not installed
24
+ __version__ = "0.0.0.dev0"
25
+
26
+
27
+ def example(
28
+ desc: str,
29
+ code: str,
30
+ detail: str = "",
31
+ **vars: str,
32
+ ) -> Callable:
33
+ ex = Example(desc=desc, code=code, detail=detail, vars=vars)
34
+
35
+ def decorator(fn: Callable) -> Callable:
36
+ if not hasattr(fn, "_typer_examples"):
37
+ fn._typer_examples = [] # type: ignore[attr-defined]
38
+ fn._typer_examples.insert(0, ex) # type: ignore[attr-defined]
39
+ return fn
40
+
41
+ return decorator
42
+
43
+
44
+ def install(app: _typer.Typer, config: Optional[ExamplesConfig] = None) -> None:
45
+ cfg = config or ExamplesConfig()
46
+ register_app(app, cfg)
47
+ install_hook()
48
+
49
+
50
+ def configure(config: ExamplesConfig) -> None:
51
+ set_config(config)
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+
3
+ import weakref
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ import click
8
+
9
+ import typer.rich_utils as _ut
10
+
11
+ from ._models import ExamplesConfig
12
+
13
+ _MARKER = "_typer_examples_installed"
14
+
15
+ _config: ExamplesConfig = ExamplesConfig()
16
+
17
+ _app_config_map: weakref.WeakKeyDictionary = weakref.WeakKeyDictionary()
18
+
19
+
20
+ def get_config() -> ExamplesConfig:
21
+ return _config
22
+
23
+
24
+ def set_config(cfg: ExamplesConfig) -> None:
25
+ global _config
26
+ _config = cfg
27
+
28
+
29
+ def register_app(app: Any, cfg: ExamplesConfig) -> None:
30
+ _app_config_map[app] = cfg
31
+
32
+
33
+ def _get_config_for_callback(callback: Any) -> ExamplesConfig:
34
+ original = callback
35
+ while hasattr(original, "__wrapped__"):
36
+ original = original.__wrapped__
37
+
38
+ for app, cfg in list(_app_config_map.items()):
39
+ if _app_directly_has_callback(app, original):
40
+ return cfg
41
+ return _config
42
+
43
+
44
+ def _app_directly_has_callback(app: Any, callback: Any) -> bool:
45
+ for cmd_info in app.registered_commands:
46
+ if cmd_info.callback is callback:
47
+ return True
48
+ return False
49
+
50
+
51
+ def install_hook() -> None:
52
+ try:
53
+ import rich # noqa: F401
54
+ except ImportError:
55
+ return
56
+
57
+ if getattr(_ut, _MARKER, False):
58
+ return
59
+
60
+ _upstream = _ut.rich_format_help
61
+
62
+ def _patched(
63
+ *, obj: "click.Command", ctx: "click.Context", markup_mode: str
64
+ ) -> None:
65
+ _upstream(obj=obj, ctx=ctx, markup_mode=markup_mode)
66
+ _render_examples(obj, ctx)
67
+
68
+ _ut.rich_format_help = _patched # type: ignore[assignment]
69
+ setattr(_ut, _MARKER, True)
70
+
71
+
72
+ def _render_examples(obj: "click.Command", ctx: "click.Context") -> None:
73
+ try:
74
+ from ._renderer import print_examples_panel
75
+ except ImportError:
76
+ return
77
+
78
+ examples = getattr(getattr(obj, "callback", None), "_typer_examples", None)
79
+ if not examples:
80
+ return
81
+
82
+ config = _get_config_for_callback(obj.callback)
83
+ print_examples_panel(examples, obj, ctx, config)
@@ -0,0 +1,47 @@
1
+ """Data models for typer-examples."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any, Callable, Dict, Optional, Tuple, Union
7
+
8
+
9
+ @dataclass
10
+ class Example:
11
+ """A single CLI usage example attached to a command.
12
+
13
+ Attributes:
14
+ desc: Short heading (5-8 words, imperative). Answers: *what is this example for?*
15
+ code: The CLI invocation string. May contain ``{placeholder}`` template variables.
16
+ detail: Optional prose line. Answers: *why or when to use this invocation?*
17
+ vars: Per-example template variable overrides (highest priority in resolution chain).
18
+ """
19
+
20
+ desc: str
21
+ code: str
22
+ detail: str = ""
23
+ vars: Dict[str, str] = field(default_factory=dict)
24
+
25
+
26
+ # Template var values can be a plain string or a lazy callable(ctx) -> str
27
+ VarValue = Union[str, Callable[..., str]]
28
+
29
+
30
+ @dataclass
31
+ class ExamplesConfig:
32
+ """Global rendering configuration for typer-examples.
33
+
34
+ Style fields that are ``None`` are auto-matched to the values Typer itself uses
35
+ (read from ``typer.rich_utils`` at render time).
36
+ """
37
+
38
+ panel_title: str = "Examples"
39
+ panel_border_style: Optional[str] = None
40
+ panel_padding: Optional[Tuple[Any, ...]] = None
41
+ title_align: Optional[str] = None
42
+ heading_style: str = "bold"
43
+ detail_style: str = "dim"
44
+ syntax_theme: str = "ansi_dark"
45
+ syntax_highlight: bool = True
46
+ show_command_prefix: bool = True
47
+ vars: Dict[str, VarValue] = field(default_factory=dict)
@@ -0,0 +1,102 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from typing import Any, Dict
5
+
6
+ import click
7
+
8
+ # Click uses a Sentinel singleton (not None) for required args that have no default.
9
+ # We must exclude it from the template-var resolution, otherwise str(Sentinel.UNSET)
10
+ # leaks as a literal "Sentinel.UNSET" placeholder value.
11
+ try:
12
+ from click.core import Sentinel as _ClickSentinel
13
+
14
+ _CLICK_UNSET = _ClickSentinel.UNSET
15
+ except (ImportError, AttributeError):
16
+ # Older Click versions don't have this sentinel; use a private object that
17
+ # will never match any real default value.
18
+ _CLICK_UNSET = object()
19
+
20
+
21
+ class _SafeFormatMap(dict):
22
+ """dict subclass that returns '{key}' for missing keys instead of raising KeyError."""
23
+
24
+ def __missing__(self, key: str) -> str:
25
+ return f"{{{key}}}"
26
+
27
+
28
+ def resolve_vars(
29
+ obj: click.Command,
30
+ ctx: click.Context,
31
+ config_vars: Dict[str, Any],
32
+ ) -> Dict[str, str]:
33
+ """Build the template-variable mapping for a single render pass.
34
+
35
+ Resolution priority (highest → lowest):
36
+ 1. Auto-fill from ``sys.argv`` positional args before ``--help`` (merged by
37
+ the renderer after this returns, always wins over per-example kwargs)
38
+ 2. Per-example kwargs (merged by the renderer after this returns)
39
+ 3. App-level ``configure(vars={...})`` — callables evaluated here
40
+ 4. Parameter defaults from the Click command definition
41
+ """
42
+ result: Dict[str, str] = {}
43
+
44
+ positional_params = [p for p in obj.params if isinstance(p, click.Argument)]
45
+
46
+ for param in positional_params:
47
+ if param.default is not None and param.default is not _CLICK_UNSET:
48
+ result[param.name] = str(param.default) # type: ignore[arg-type]
49
+
50
+ argv_values = _extract_argv_positionals(obj, ctx)
51
+ result.update(argv_values)
52
+
53
+ for key, val in config_vars.items():
54
+ if callable(val):
55
+ try:
56
+ result[key] = str(val(ctx))
57
+ except Exception:
58
+ pass
59
+ else:
60
+ result[key] = str(val)
61
+
62
+ return result
63
+
64
+
65
+ def _extract_argv_positionals(
66
+ obj: click.Command,
67
+ ctx: click.Context,
68
+ ) -> Dict[str, str]:
69
+ positional_params = [p for p in obj.params if isinstance(p, click.Argument)]
70
+ if not positional_params:
71
+ return {}
72
+
73
+ known_subcommands: set[str] = set()
74
+ c: click.Context | None = ctx
75
+ while c is not None:
76
+ if isinstance(c.command, click.Group):
77
+ known_subcommands.update(c.command.list_commands(c))
78
+ c = c.parent
79
+
80
+ raw_args = list(sys.argv[1:])
81
+ try:
82
+ help_idx = next(i for i, a in enumerate(raw_args) if a in ("--help", "-h"))
83
+ raw_args = raw_args[:help_idx]
84
+ except StopIteration:
85
+ pass
86
+
87
+ command_path_tokens = ctx.command_path.split()
88
+ for token in command_path_tokens:
89
+ if raw_args and raw_args[0] == token:
90
+ raw_args = raw_args[1:]
91
+
92
+ positional_values = [a for a in raw_args if not a.startswith("-") and a not in known_subcommands]
93
+
94
+ result: Dict[str, str] = {}
95
+ for param, value in zip(positional_params, positional_values):
96
+ result[param.name] = value # type: ignore[assignment]
97
+
98
+ return result
99
+
100
+
101
+ def safe_format_map(text: str, vars: Dict[str, str]) -> str:
102
+ return text.format_map(_SafeFormatMap(vars))
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, List
4
+
5
+ if TYPE_CHECKING:
6
+ import click
7
+
8
+ from rich.console import Group
9
+ from rich.panel import Panel
10
+ from rich.syntax import Syntax
11
+ from rich.text import Text
12
+
13
+ from ._models import Example, ExamplesConfig
14
+ from ._providers import _extract_argv_positionals, resolve_vars, safe_format_map
15
+
16
+
17
+ def print_examples_panel(
18
+ examples: List[Example],
19
+ obj: "click.Command",
20
+ ctx: "click.Context",
21
+ config: ExamplesConfig,
22
+ ) -> None:
23
+ import typer.rich_utils as ut
24
+
25
+ console = ut._get_rich_console() # type: ignore[attr-defined]
26
+ template_vars = resolve_vars(obj, ctx, config.vars)
27
+ argv_vars = _extract_argv_positionals(obj, ctx)
28
+
29
+ border_style = (
30
+ config.panel_border_style
31
+ if config.panel_border_style is not None
32
+ else getattr(ut, "STYLE_OPTIONS_PANEL_BORDER", "dim")
33
+ )
34
+ padding = (
35
+ config.panel_padding if config.panel_padding is not None else getattr(ut, "STYLE_OPTIONS_TABLE_PADDING", (0, 1))
36
+ )
37
+ title_align = config.title_align if config.title_align is not None else getattr(ut, "ALIGN_OPTIONS_PANEL", "left")
38
+
39
+ rows = []
40
+
41
+ for i, ex in enumerate(examples):
42
+ merged_vars = {**template_vars, **ex.vars, **argv_vars}
43
+
44
+ desc = safe_format_map(ex.desc, merged_vars)
45
+ code = _build_code(ex.code, obj, ctx, merged_vars, config)
46
+ detail = safe_format_map(ex.detail, merged_vars) if ex.detail else None
47
+
48
+ parts: list = [Text(desc, style=config.heading_style)]
49
+
50
+ if detail:
51
+ parts.append(Text(detail, style=config.detail_style))
52
+
53
+ if config.syntax_highlight:
54
+ parts.append(
55
+ Syntax(
56
+ f"$ {code}",
57
+ "bash",
58
+ theme=config.syntax_theme,
59
+ background_color="default",
60
+ )
61
+ )
62
+ else:
63
+ parts.append(Text(f"$ {code}"))
64
+
65
+ rows.append(Group(*parts))
66
+
67
+ if i < len(examples) - 1:
68
+ rows.append(Text(""))
69
+
70
+ console.print(
71
+ Panel(
72
+ Group(*rows),
73
+ padding=padding,
74
+ border_style=border_style,
75
+ title=config.panel_title,
76
+ title_align=title_align,
77
+ )
78
+ )
79
+
80
+
81
+ def _build_code(
82
+ code: str,
83
+ obj: "click.Command",
84
+ ctx: "click.Context",
85
+ vars: dict,
86
+ config: ExamplesConfig,
87
+ ) -> str:
88
+ resolved = safe_format_map(code, vars)
89
+ if config.show_command_prefix:
90
+ prefix = ctx.command_path
91
+ resolved = f"{prefix} {resolved}".strip()
92
+ return resolved
typer_examples/docs.py ADDED
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Dict, List, Optional, Tuple
4
+
5
+ import typer
6
+
7
+ from ._providers import safe_format_map
8
+
9
+
10
+ def get_all_examples(app: typer.Typer) -> Dict[Tuple[str, ...], list]:
11
+ from ._models import Example
12
+
13
+ result: Dict[Tuple[str, ...], List[Example]] = {}
14
+ _collect(app, path=(), result=result)
15
+ return result
16
+
17
+
18
+ def _collect(
19
+ app: typer.Typer,
20
+ path: Tuple[str, ...],
21
+ result: Dict[Tuple[str, ...], list],
22
+ ) -> None:
23
+ for command_info in app.registered_commands:
24
+ name = command_info.name or (
25
+ command_info.callback.__name__.replace("_", "-")
26
+ if command_info.callback
27
+ else None
28
+ )
29
+ if not name:
30
+ continue
31
+ examples = getattr(command_info.callback, "_typer_examples", None)
32
+ if examples:
33
+ result[path + (name,)] = list(examples)
34
+
35
+ for group_info in app.registered_groups:
36
+ sub_app = group_info.typer_instance
37
+ if sub_app is None:
38
+ continue
39
+ group_name = group_info.name or ""
40
+ _collect(sub_app, path + (group_name,) if group_name else path, result)
41
+
42
+
43
+ def to_markdown(app: typer.Typer, vars: Optional[Dict[str, str]] = None) -> str:
44
+ all_examples = get_all_examples(app)
45
+ lines: List[str] = []
46
+
47
+ for path, examples in all_examples.items():
48
+ command_str = " ".join(path)
49
+ lines.append(f"## `{command_str}`\n")
50
+ for ex in examples:
51
+ lines.append(f"**{ex.desc}**\n")
52
+ if ex.detail:
53
+ lines.append(f"{ex.detail}\n")
54
+ code = (
55
+ safe_format_map(ex.code, {**vars, **ex.vars})
56
+ if vars is not None
57
+ else ex.code
58
+ )
59
+ lines.append(f"```bash\n$ {code}\n```\n")
60
+
61
+ return "\n".join(lines)
62
+
63
+
64
+ def to_rst(app: typer.Typer, vars: Optional[Dict[str, str]] = None) -> str:
65
+ all_examples = get_all_examples(app)
66
+ lines: List[str] = []
67
+
68
+ for path, examples in all_examples.items():
69
+ command_str = " ".join(path)
70
+ heading = f"``{command_str}``"
71
+ lines.append(heading)
72
+ lines.append("~" * len(heading))
73
+ lines.append("")
74
+
75
+ for ex in examples:
76
+ lines.append(f"**{ex.desc}**")
77
+ lines.append("")
78
+ if ex.detail:
79
+ lines.append(ex.detail)
80
+ lines.append("")
81
+ lines.append(".. code-block:: bash")
82
+ lines.append("")
83
+ code = (
84
+ safe_format_map(ex.code, {**vars, **ex.vars})
85
+ if vars is not None
86
+ else ex.code
87
+ )
88
+ lines.append(f" $ {code}")
89
+ lines.append("")
90
+
91
+ return "\n".join(lines)
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.4
2
+ Name: typer-examples
3
+ Version: 1.1.1
4
+ Summary: Beautiful example rendering for Typer CLI help output
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: cli,examples,help,rich,typer
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Classifier: Topic :: Utilities
18
+ Requires-Python: >=3.9
19
+ Requires-Dist: typer>=0.9.0
20
+ Provides-Extra: dev
21
+ Requires-Dist: git-cliff>=2.6; extra == 'dev'
22
+ Requires-Dist: pytest>=7.0; extra == 'dev'
23
+ Requires-Dist: typer[all]>=0.9.0; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # typer-examples
27
+
28
+ [![CI](https://github.com/Xieyt/typer-examples/actions/workflows/ci.yml/badge.svg)](https://github.com/Xieyt/typer-examples/actions/workflows/ci.yml)
29
+ [![Typer Compatibility](https://github.com/Xieyt/typer-examples/actions/workflows/typer-compat.yml/badge.svg)](https://github.com/Xieyt/typer-examples/actions/workflows/typer-compat.yml)
30
+ [![Python](https://img.shields.io/badge/python-3.9--3.12-blue)](#compatibility)
31
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](#license)
32
+
33
+ Attach structured, syntax-highlighted usage examples to [Typer](https://typer.tiangolo.com/) commands. They appear automatically in `--help` output as a Rich panel — no subclassing, no epilog hacks.
34
+
35
+ ```
36
+ Usage: myapp deploy [OPTIONS] ENV
37
+
38
+ ╭─ Options ──────────────────────────────────────────────────────────╮
39
+ │ --tag TEXT Docker image tag to deploy. [default: latest] │
40
+ │ --yes Skip confirmation prompt. │
41
+ │ --help Show this message and exit. │
42
+ ╰────────────────────────────────────────────────────────────────────╯
43
+ ╭─ Examples ─────────────────────────────────────────────────────────╮
44
+ │ Deploy to staging with a pinned tag │
45
+ │ Pulls the image, runs migrations, and restarts services. │
46
+ │ $ myapp deploy staging --tag 1.4.2 │
47
+ │ │
48
+ │ Deploy to production and skip confirmation │
49
+ │ Pass --yes in CI pipelines to avoid interactive prompts. │
50
+ │ $ myapp deploy production --tag 2.0.0 --yes │
51
+ ╰────────────────────────────────────────────────────────────────────╯
52
+ ```
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install typer-examples
58
+ # or
59
+ uv add typer-examples
60
+ ```
61
+
62
+ Requires Python ≥ 3.9 and Typer ≥ 0.9.
63
+
64
+ ## Quick start
65
+
66
+ ```python
67
+ import typer
68
+ from typer_examples import example, install
69
+
70
+ app = typer.Typer()
71
+ install(app)
72
+
73
+ @app.command()
74
+ @example(
75
+ "Deploy to staging with a pinned tag",
76
+ "{env} --tag {version}",
77
+ env="staging",
78
+ version="1.4.2",
79
+ detail="Pulls the image, runs migrations, and restarts services.",
80
+ )
81
+ @example(
82
+ "Deploy to production and skip confirmation",
83
+ "{env} --tag {version} --yes",
84
+ env="production",
85
+ version="2.0.0",
86
+ detail="Pass --yes in CI pipelines to avoid interactive prompts.",
87
+ )
88
+ def deploy(env: str, tag: str = typer.Option("latest"), yes: bool = False):
89
+ ...
90
+
91
+ if __name__ == "__main__":
92
+ app()
93
+ ```
94
+
95
+ > **Decorator order**: `@example` must sit *below* `@app.command()` — closest to `def`. This ensures the metadata is attached to the raw function before Typer wraps it.
96
+
97
+ ## Features
98
+
99
+ - **Decorator-first** — examples live next to the command, not buried in docstrings or epilog strings
100
+ - **Template variables** — `{placeholders}` resolved from per-example kwargs, app-level defaults, `sys.argv`, or Click parameter defaults → [details](docs/template-variables.md)
101
+ - **Per-app config** — each `Typer()` instance gets its own panel title, style theme, and variable defaults → [details](docs/configuration.md)
102
+ - **Docs generation** — export all examples to Markdown or reStructuredText for CI doc pipelines → [API](docs/api.md)
103
+ - **Chain-safe** — composes with `rich-click` and any other `rich_format_help` patch without clobbering
104
+ - **Graceful degradation** — if `rich` is absent, `install()` returns silently with no error
105
+
106
+ ## Documentation
107
+
108
+ | Topic | |
109
+ |-------|--|
110
+ | [Template variables](docs/template-variables.md) | Resolution chain: per-example → app-level → argv → defaults |
111
+ | [Configuration](docs/configuration.md) | `ExamplesConfig` fields, global config, per-app config for sub-commands |
112
+ | [API reference](docs/api.md) | Full public API with signatures and return types |
113
+ | [How it works](docs/how-it-works.md) | Internal implementation and the `rich_format_help` hook |
114
+
115
+ ## Try the examples
116
+
117
+ ```bash
118
+ # Minimal single-app setup — three commands, each with examples
119
+ uv run python examples/simple.py deploy --help
120
+ uv run python examples/simple.py logs --help
121
+ uv run python examples/simple.py shell --help
122
+
123
+ # Root app + two sub-apps with independent per-app config
124
+ uv run python examples/app.py deploy --help
125
+ uv run python examples/app.py db migrate --help
126
+ uv run python examples/app.py server start --help
127
+
128
+ # Static docs generation
129
+ uv run python examples/app.py docs
130
+ uv run python examples/app.py docs --format rst
131
+ ```
132
+
133
+ ## Compatibility
134
+
135
+ | Typer | Python | rich-click |
136
+ |-------|--------|------------|
137
+ | ≥ 0.9 | 3.9 – 3.12 | Supported |
138
+
139
+ Compatibility is verified daily across all supported Typer × Python combinations in CI.
140
+
141
+ ## License
142
+
143
+ MIT
@@ -0,0 +1,10 @@
1
+ typer_examples/__init__.py,sha256=k2Brsn-ASPNxABZg2jQNwcbsrSLGNUjCuN1-_6-Y_so,1269
2
+ typer_examples/_hook.py,sha256=lsU1Vafm4K0EzpZwGiSjjBVF4y6y0CkOKNdtXvcmXXU,1999
3
+ typer_examples/_models.py,sha256=ZRCng0TGlAZQvGDs2GCsXt-QVG-_WA04Kok51iPamw4,1516
4
+ typer_examples/_providers.py,sha256=fc2WVhzYFzJKgNdDFlFt6pml0ZjLEngkfXR-tehA1wY,3287
5
+ typer_examples/_renderer.py,sha256=OChScZ0UlaWY_d4X0oRVNxZPpxlRxIcwnGqW8mHV-Dg,2599
6
+ typer_examples/docs.py,sha256=OJvea4Kvtx_KJ40GRStosVyASJmUTOzT3C5w_e1NX2E,2723
7
+ typer_examples-1.1.1.dist-info/METADATA,sha256=1P8EVG4AkYs_0S4hFb9UnnFymFZzcYEFt2ST2kY55Eg,6212
8
+ typer_examples-1.1.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
9
+ typer_examples-1.1.1.dist-info/licenses/LICENSE,sha256=3gIpJJaVDsJdEq5q2GxKWznSwv1N2Uu2aHkw-17QJfs,1066
10
+ typer_examples-1.1.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aloksingh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.