Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-typer for openSUSE:Factory checked in at 2025-09-01 17:16:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-typer (Old) and /work/SRC/openSUSE:Factory/.python-typer.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-typer" Mon Sep 1 17:16:43 2025 rev:25 rq:1302029 version:0.17.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-typer/python-typer.changes 2025-08-26 14:56:52.498083266 +0200 +++ /work/SRC/openSUSE:Factory/.python-typer.new.1977/python-typer.changes 2025-09-01 17:16:47.587391491 +0200 @@ -1,0 +2,10 @@ +Sat Aug 30 14:32:00 UTC 2025 - Matthias Bach <ma...@marix.org> + +- Update to 0.17.3 + * Allow annotated parsing with a subclass of Path. + * Avoid printing default: None in the help section when using + Rich. + * Fix markdown formatting in --help output. + * Lazy-load rich_utils to reduce startup time. + +------------------------------------------------------------------- Old: ---- typer-0.16.1.tar.gz New: ---- typer-0.17.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-typer.spec ++++++ --- /var/tmp/diff_new_pack.PZphjZ/_old 2025-09-01 17:16:48.499430106 +0200 +++ /var/tmp/diff_new_pack.PZphjZ/_new 2025-09-01 17:16:48.499430106 +0200 @@ -1,6 +1,7 @@ # # spec file for package python-typer # +# Copyright (c) 2025 SUSE LLC # Copyright (c) 2025 SUSE LLC and contributors # Copyright (c) 2021 Matthias Bach <ma...@marix.org> # @@ -25,7 +26,7 @@ %endif %{?sle15_python_module_pythons} Name: python-typer -Version: 0.16.1 +Version: 0.17.3 Release: 0 Summary: Typer, build great CLIs. Easy to code. Based on Python type hints License: MIT @@ -38,7 +39,7 @@ BuildRequires: %{python_module pytest} BuildRequires: %{python_module rich} BuildRequires: %{python_module shellingham} -BuildRequires: %{python_module typer-slim} +BuildRequires: %{python_module typer-slim >= %{version}} BuildRequires: fdupes BuildRequires: python-rpm-macros # Work around Python dependency not being auto-added as there are no modules provided ++++++ typer-0.16.1.tar.gz -> typer-0.17.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/PKG-INFO new/typer-0.17.3/PKG-INFO --- old/typer-0.16.1/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/typer-0.17.3/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: typer -Version: 0.16.1 +Version: 0.17.3 Summary: Typer, build great CLIs. Easy to code. Based on Python type hints. Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiang...@gmail.com> Classifier: Intended Audience :: Information Technology diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/pyproject.toml new/typer-0.17.3/pyproject.toml --- old/typer-0.16.1/pyproject.toml 2025-08-18 21:18:10.599890000 +0200 +++ new/typer-0.17.3/pyproject.toml 2025-08-30 14:35:08.346016400 +0200 @@ -42,7 +42,7 @@ "rich >=10.11.0", ] readme = "README.md" -version = "0.16.1" +version = "0.17.3" [project.urls] Homepage = "https://github.com/fastapi/typer" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/requirements-tests.txt new/typer-0.17.3/requirements-tests.txt --- old/typer-0.16.1/requirements-tests.txt 2025-08-18 21:18:05.480904000 +0200 +++ new/typer-0.17.3/requirements-tests.txt 2025-08-30 14:34:51.968851000 +0200 @@ -4,9 +4,9 @@ pytest-cov >=2.10.0,<7.0.0 coverage[toml] >=6.2,<8.0 pytest-xdist >=1.32.0,<4.0.0 -pytest-sugar >=0.9.4,<1.1.0 +pytest-sugar >=0.9.4,<1.2.0 mypy ==1.4.1 -ruff ==0.12.9 +ruff ==0.12.10 # Needed explicitly by typer-slim rich >=10.11.0 shellingham >=1.3.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/tests/assets/print_modules.py new/typer-0.17.3/tests/assets/print_modules.py --- old/typer-0.16.1/tests/assets/print_modules.py 1970-01-01 01:00:00.000000000 +0100 +++ new/typer-0.17.3/tests/assets/print_modules.py 2025-08-30 14:34:51.969851300 +0200 @@ -0,0 +1,15 @@ +import sys + +import typer + +app = typer.Typer() + + +@app.command() +def main(): + for m in sys.modules: + print(m) + + +if __name__ == "__main__": + app() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/tests/test_annotated.py new/typer-0.17.3/tests/test_annotated.py --- old/typer-0.16.1/tests/test_annotated.py 2025-08-18 21:18:05.481904300 +0200 +++ new/typer-0.17.3/tests/test_annotated.py 2025-08-30 14:34:51.970851200 +0200 @@ -1,3 +1,6 @@ +import sys +from pathlib import Path + import typer from typer.testing import CliRunner from typing_extensions import Annotated @@ -76,3 +79,22 @@ result = runner.invoke(app, ["--force"]) assert result.exit_code == 0, result.output assert "Forcing operation" in result.output + + +def test_annotated_custom_path(): + app = typer.Typer() + + class CustomPath(Path): + # Subclassing Path was not fully supported before 3.12 + # https://docs.python.org/3.12/whatsnew/3.12.html + if sys.version_info < (3, 12): + _flavour = type(Path())._flavour + + @app.command() + def custom_parser( + my_path: Annotated[CustomPath, typer.Argument(parser=CustomPath)], + ): + assert isinstance(my_path, CustomPath) + + result = runner.invoke(app, "/some/quirky/path/implementation") + assert result.exit_code == 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/tests/test_rich_import.py new/typer-0.17.3/tests/test_rich_import.py --- old/typer-0.16.1/tests/test_rich_import.py 1970-01-01 01:00:00.000000000 +0100 +++ new/typer-0.17.3/tests/test_rich_import.py 2025-08-30 14:34:51.971851300 +0200 @@ -0,0 +1,21 @@ +import subprocess +import sys +from pathlib import Path + +ACCEPTED_MODULES = {"rich._extension", "rich"} + + +def test_rich_not_imported_unnecessary(): + file_path = Path(__file__).parent / "assets/print_modules.py" + result = subprocess.run( + [sys.executable, "-m", "coverage", "run", str(file_path)], + capture_output=True, + encoding="utf-8", + ) + modules = result.stdout.splitlines() + modules = [ + module + for module in modules + if module not in ACCEPTED_MODULES and module.startswith("rich") + ] + assert not modules diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/tests/test_rich_markup_mode.py new/typer-0.17.3/tests/test_rich_markup_mode.py --- old/typer-0.16.1/tests/test_rich_markup_mode.py 2025-08-18 21:18:05.483904100 +0200 +++ new/typer-0.17.3/tests/test_rich_markup_mode.py 2025-08-30 14:34:51.971851300 +0200 @@ -49,7 +49,6 @@ pytest.param( "markdown", ["First line", "", "Line 1", "", "Line 2", "", "Line 3", ""], - marks=pytest.mark.xfail, ), pytest.param( "rich", ["First line", "", "Line 1", "", "Line 2", "", "Line 3", ""] @@ -140,7 +139,6 @@ "Line 3", "", ], - marks=pytest.mark.xfail, ), pytest.param( "rich", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/tests/test_rich_utils.py new/typer-0.17.3/tests/test_rich_utils.py --- old/typer-0.16.1/tests/test_rich_utils.py 2025-08-18 21:18:05.483904100 +0200 +++ new/typer-0.17.3/tests/test_rich_utils.py 2025-08-30 14:34:51.971851300 +0200 @@ -50,3 +50,32 @@ assert result.exit_code == 0 assert "Show this message" in result.stdout + + +def test_rich_doesnt_print_None_default(): + app = typer.Typer(rich_markup_mode="rich") + + @app.command() + def main( + name: str, + option_1: str = typer.Option( + "option_1_default", + ), + option_2: str = typer.Option( + ..., + ), + ): + print(f"Hello {name}") + print(f"First: {option_1}") + print(f"Second: {option_2}") + + result = runner.invoke(app, ["--help"]) + assert "Usage" in result.stdout + assert "name" in result.stdout + assert "option-1" in result.stdout + assert "option-2" in result.stdout + assert result.stdout.count("[default: None]") == 0 + result = runner.invoke(app, ["Rick", "--option-2=Morty"]) + assert "Hello Rick" in result.stdout + assert "First: option_1_default" in result.stdout + assert "Second: Morty" in result.stdout diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/typer/__init__.py new/typer-0.17.3/typer/__init__.py --- old/typer-0.16.1/typer/__init__.py 2025-08-18 21:18:05.491904300 +0200 +++ new/typer-0.17.3/typer/__init__.py 2025-08-30 14:34:51.979851200 +0200 @@ -1,6 +1,6 @@ """Typer, build great CLIs. Easy to code. Based on Python type hints.""" -__version__ = "0.16.1" +__version__ = "0.17.3" from shutil import get_terminal_size as get_terminal_size diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/typer/cli.py new/typer-0.17.3/typer/cli.py --- old/typer-0.16.1/typer/cli.py 2025-08-18 21:18:05.491904300 +0200 +++ new/typer-0.17.3/typer/cli.py 2025-08-30 14:34:51.980851400 +0200 @@ -15,7 +15,6 @@ import rich has_rich = True - from . import rich_utils except ImportError: # pragma: no cover has_rich = False @@ -275,6 +274,8 @@ def _parse_html(input_text: str) -> str: if not has_rich: # pragma: no cover return input_text + from . import rich_utils + return rich_utils.rich_to_html(input_text) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/typer/core.py new/typer-0.17.3/typer/core.py --- old/typer-0.16.1/typer/core.py 2025-08-18 21:18:05.492904200 +0200 +++ new/typer-0.17.3/typer/core.py 2025-08-30 14:34:51.980851400 +0200 @@ -33,8 +33,6 @@ try: import rich - from . import rich_utils - DEFAULT_MARKUP_MODE: MarkupMode = "rich" except ImportError: # pragma: no cover @@ -213,6 +211,8 @@ raise # Typer override if rich and rich_markup_mode is not None: + from . import rich_utils + rich_utils.rich_format_error(e) else: e.show() @@ -243,6 +243,8 @@ raise # Typer override if rich and rich_markup_mode is not None: + from . import rich_utils + rich_utils.rich_abort_error() else: click.echo(_("Aborted!"), file=sys.stderr) @@ -705,6 +707,8 @@ def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: if not rich or self.rich_markup_mode is None: return super().format_help(ctx, formatter) + from . import rich_utils + return rich_utils.rich_format_help( obj=self, ctx=ctx, @@ -768,6 +772,8 @@ def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: if not rich or self.rich_markup_mode is None: return super().format_help(ctx, formatter) + from . import rich_utils + return rich_utils.rich_format_help( obj=self, ctx=ctx, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/typer/main.py new/typer-0.17.3/typer/main.py --- old/typer-0.16.1/typer/main.py 2025-08-18 21:18:05.492904200 +0200 +++ new/typer-0.17.3/typer/main.py 2025-08-30 14:34:51.980851400 +0200 @@ -51,11 +51,6 @@ try: import rich - from rich.traceback import Traceback - - from . import rich_utils - - console_stderr = rich_utils._get_rich_console(stderr=True) except ImportError: # pragma: no cover rich = None # type: ignore @@ -83,7 +78,9 @@ supress_internal_dir_names = [typer_path, click_path] exc = exc_value if rich: - from .rich_utils import MAX_WIDTH + from rich.traceback import Traceback + + from . import rich_utils rich_tb = Traceback.from_exception( type(exc), @@ -91,8 +88,9 @@ exc.__traceback__, show_locals=exception_config.pretty_exceptions_show_locals, suppress=supress_internal_dir_names, - width=MAX_WIDTH, + width=rich_utils.MAX_WIDTH, ) + console_stderr = rich_utils._get_rich_console(stderr=True) console_stderr.print(rich_tb) return tb_exc = traceback.TracebackException.from_exception(exc) @@ -622,7 +620,9 @@ def param_path_convertor(value: Optional[str] = None) -> Optional[Path]: if value is not None: - return Path(value) + # allow returning any subclass of Path created by an annotated parser without converting + # it back to a Path + return value if isinstance(value, Path) else Path(value) return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/typer-0.16.1/typer/rich_utils.py new/typer-0.17.3/typer/rich_utils.py --- old/typer-0.16.1/typer/rich_utils.py 2025-08-18 21:18:05.492904200 +0200 +++ new/typer-0.17.3/typer/rich_utils.py 2025-08-30 14:34:51.980851400 +0200 @@ -190,7 +190,8 @@ help_text = help_text.partition("\f")[0] # Get the first paragraph - first_line = help_text.split("\n\n")[0] + first_line, *remaining_paragraphs = help_text.split("\n\n") + # Remove single linebreaks if markup_mode != MARKUP_MODE_MARKDOWN and not first_line.startswith("\b"): first_line = first_line.replace("\n", " ") @@ -200,13 +201,11 @@ markup_mode=markup_mode, ) - # Add a newline inbetween the header and the remaining paragraphs - yield Text("") - # Get remaining lines, remove single line breaks and format as dim - remaining_paragraphs = help_text.split("\n\n")[1:] if remaining_paragraphs: - if markup_mode != MARKUP_MODE_RICH: + # Add a newline inbetween the header and the remaining paragraphs + yield Text("") + if markup_mode not in (MARKUP_MODE_RICH, MARKUP_MODE_MARKDOWN): # Remove single linebreaks remaining_paragraphs = [ x.replace("\n", " ").strip() @@ -217,7 +216,7 @@ # Join back together remaining_lines = "\n".join(remaining_paragraphs) else: - # Join with double linebreaks if markdown + # Join with double linebreaks if markdown or Rich markup remaining_lines = "\n\n".join(remaining_paragraphs) yield _make_rich_text( @@ -289,9 +288,11 @@ # Default value # This uses Typer's specific param._get_default_string if isinstance(param, (TyperOption, TyperArgument)): - if param.show_default: - show_default_is_str = isinstance(param.show_default, str) - default_value = param._extract_default_help_str(ctx=ctx) + default_value = param._extract_default_help_str(ctx=ctx) + show_default_is_str = isinstance(param.show_default, str) + if show_default_is_str or ( + default_value is not None and (param.show_default or ctx.show_default) + ): default_str = param._get_default_string( ctx=ctx, show_default_is_str=show_default_is_str,