Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-click-extra for 
openSUSE:Factory checked in at 2026-03-05 17:15:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-click-extra (Old)
 and      /work/SRC/openSUSE:Factory/.python-click-extra.new.561 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-click-extra"

Thu Mar  5 17:15:01 2026 rev:16 rq:1336598 version:7.6.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-click-extra/python-click-extra.changes    
2026-03-02 17:42:08.795877323 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-click-extra.new.561/python-click-extra.changes
   2026-03-05 17:18:20.786595304 +0100
@@ -1,0 +2,15 @@
+Wed Mar  4 21:45:16 UTC 2026 - Dirk MΓΌller <[email protected]>
+
+- update to 7.6.4:
+  * Fix `ExtraVersionOption.cli_frame()` crashing in Nuitka-
+    compiled binaries where all stack frames belong to the Click
+    ecosystem.
+  * Fix `ExtraVersionOption.module_version` returning `None` in
+    `__main__` entry points by checking the parent package's
+    `__version__`.
+  * Fix test plan for Nuitka-compiled binary.
+  * Add `@pytest.mark.once` marker for platform-independent
+    structural tests. Run them in a single CI job instead of
+    across the full matrix.
+
+-------------------------------------------------------------------

Old:
----
  click-extra-7.6.3.tar.gz

New:
----
  click-extra-7.6.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-click-extra.spec ++++++
--- /var/tmp/diff_new_pack.BlBlE5/_old  2026-03-05 17:18:21.362619143 +0100
+++ /var/tmp/diff_new_pack.BlBlE5/_new  2026-03-05 17:18:21.362619143 +0100
@@ -27,7 +27,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-click-extra
-Version:        7.6.3
+Version:        7.6.4
 Release:        0
 Summary:        Drop-in replacement for Click to make user-friendly and 
colorful CLI
 License:        GPL-2.0-or-later

++++++ click-extra-7.6.3.tar.gz -> click-extra-7.6.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/.github/workflows/tests.yaml 
new/click-extra-7.6.4/.github/workflows/tests.yaml
--- old/click-extra-7.6.3/.github/workflows/tests.yaml  2026-03-02 
10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/.github/workflows/tests.yaml  2026-03-04 
15:50:27.000000000 +0100
@@ -30,6 +30,19 @@
 
 jobs:
 
+  once-tests:
+    name: πŸ”‚ Once tests
+    runs-on: ubuntu-slim
+    steps:
+      - uses: actions/[email protected]
+      - uses: astral-sh/[email protected]
+      - name: Install Python
+        run: uv --no-progress venv --python 3.14
+      - name: Install project
+        run: uv --no-progress sync --frozen --all-extras --group test
+      - name: Run once-only tests
+        run: uv --no-progress run --frozen -- pytest -m once
+
   tests:
     strategy:
       # We delegate the failure decision to each job, by the way of the 
"continue-on-error" flag.
@@ -199,7 +212,7 @@
           ${{ matrix.cloup-version != 'released'
           && format('--with "git+https://github.com/janluke/cloup.git@{0}";', 
matrix.cloup-version) || ''}}
           --
-          pytest
+          pytest -m "not once"
 
       - name: Codecov - coverage
         uses: codecov/[email protected]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/changelog.md 
new/click-extra-7.6.4/changelog.md
--- old/click-extra-7.6.3/changelog.md  2026-03-02 10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/changelog.md  2026-03-04 15:50:27.000000000 +0100
@@ -1,19 +1,38 @@
 # Changelog
 
+## [7.6.4 
(2026-03-04)](https://github.com/kdeldycke/click-extra/compare/v7.6.3...v7.6.4)
+
+- Fix `ExtraVersionOption.cli_frame()` crashing in Nuitka-compiled binaries 
where all stack frames belong to the Click ecosystem.
+- Fix `ExtraVersionOption.module_version` returning `None` in `__main__` entry 
points by checking the parent package's `__version__`.
+- Fix test plan for Nuitka-compiled binary.
+- Add `@pytest.mark.once` marker for platform-independent structural tests. 
Run them in a single CI job instead of across the full matrix.
+
 ## [7.6.3 
(2026-03-02)](https://github.com/kdeldycke/click-extra/compare/v7.6.2...v7.6.3)
 
+> [!NOTE]
+> `7.6.3` is available on [🐍 
PyPI](https://pypi.org/project/click-extra/7.6.3/) and [πŸ™ 
GitHub](https://github.com/kdeldycke/click-extra/releases/tag/v7.6.3).
+
 - Fix `test_default_pattern_roaming_force_posix` test failures when 
`XDG_CONFIG_HOME` is set. Closes {issue}`1541`.
 
 ## [7.6.2 
(2026-02-27)](https://github.com/kdeldycke/click-extra/compare/v7.6.1...v7.6.2)
 
+> [!NOTE]
+> `7.6.2` is available on [🐍 
PyPI](https://pypi.org/project/click-extra/7.6.2/) and [πŸ™ 
GitHub](https://github.com/kdeldycke/click-extra/releases/tag/v7.6.2).
+
 - Add `ExtraVersionOption.prebake_version()` static method to pre-bake 
`__version__` strings with Git hashes at compile time, complementing the 
runtime `version` property for Nuitka/PyInstaller binaries.
 
 ## [7.6.1 
(2026-02-27)](https://github.com/kdeldycke/click-extra/compare/v7.6.0...v7.6.1)
 
+> [!NOTE]
+> `7.6.1` is available on [🐍 
PyPI](https://pypi.org/project/click-extra/7.6.1/) and [πŸ™ 
GitHub](https://github.com/kdeldycke/click-extra/releases/tag/v7.6.1).
+
 - Fix test failures when optional config format dependencies are not 
installed. Closes {issue}`1538`.
 
 ## [7.6.0 
(2026-02-26)](https://github.com/kdeldycke/click-extra/compare/v7.5.3...v7.6.0)
 
+> [!NOTE]
+> `7.6.0` is available on [🐍 
PyPI](https://pypi.org/project/click-extra/7.6.0/) and [πŸ™ 
GitHub](https://github.com/kdeldycke/click-extra/releases/tag/v7.6.0).
+
 - Add `_default_subcommands` reserved configuration key to auto-invoke 
subcommands when none are provided on the CLI. Closes {issue}`1405`.
 - Add `_prepend_subcommands` reserved configuration key to always prepend 
subcommands to every invocation (requires `chain=True`). Closes {issue}`1405`.
 - Add `--validate-config` option to validate configuration files.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/citation.cff 
new/click-extra-7.6.4/citation.cff
--- old/click-extra-7.6.3/citation.cff  2026-03-02 10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/citation.cff  2026-03-04 15:50:27.000000000 +0100
@@ -8,8 +8,8 @@
     email: [email protected]
     orcid: "https://orcid.org/0000-0001-9748-9014";
 doi: 10.5281/zenodo.7116050
-version: 7.6.3
+version: 7.6.4
 # The release date is kept up to date by the external workflows. See:
 # 
https://github.com/kdeldycke/workflows/blob/33b704b489c1aa18b7b7efbf963e153e91e1c810/.github/workflows/changelog.yaml#L135-L137
-date-released: 2026-03-02
+date-released: 2026-03-04
 url: "https://github.com/kdeldycke/click-extra";
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/click_extra/__init__.py 
new/click-extra-7.6.4/click_extra/__init__.py
--- old/click-extra-7.6.3/click_extra/__init__.py       2026-03-02 
10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/click_extra/__init__.py       2026-03-04 
15:50:27.000000000 +0100
@@ -242,7 +242,7 @@
 """
 
 
-__version__ = "7.6.3"
+__version__ = "7.6.4"
 
 
 def __getattr__(name: str) -> object:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/click_extra/version.py 
new/click-extra-7.6.4/click_extra/version.py
--- old/click-extra-7.6.3/click_extra/version.py        2026-03-02 
10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/click_extra/version.py        2026-03-04 
15:50:27.000000000 +0100
@@ -259,12 +259,23 @@
             # which the user's CLI is implemented.
             return frame
 
-        # Our heuristics to locate the CLI implementation failed.
+        # Our heuristics to locate the CLI implementation failed. Fall back to
+        # the outermost frame in the stack. This happens in Nuitka-compiled
+        # binaries where the entry point module's ``__name__`` may be a
+        # submodule of the Click ecosystem package (e.g.
+        # ``click_extra.__main__``) and all frames get skipped.
         logger = logging.getLogger("click_extra")
         count_size = len(str(len(frame_chain)))
         for counter, (p_name, f_name) in enumerate(frame_chain):
             logger.debug(f"Frame {counter:<{count_size}} # {p_name}:{f_name}")
-        raise RuntimeError("Could not find the frame in which the CLI is 
implemented.")
+
+        # The outermost frame is the last one returned by inspect.stack().
+        outermost = inspect.stack()[-1].frame
+        logger.debug(
+            "cli_frame heuristics exhausted, falling back to outermost frame: "
+            f"{outermost.f_globals.get('__name__')}:{outermost.f_code.co_name}"
+        )
+        return outermost
 
     @cached_property
     def module(self) -> ModuleType:
@@ -371,6 +382,21 @@
                     callback_globals = getattr(callback, "__globals__", {})
                     version = callback_globals.get("__version__")
 
+        # If still not found, check the parent package. This handles
+        # ``__main__`` entry points where ``__version__`` is defined in
+        # the package's ``__init__.py`` (e.g. Nuitka-compiled binaries).
+        # Skip modules belonging to the Click ecosystem because
+        # ``cli_frame()`` may resolve to a CliRunner frame instead of
+        # the user's module, producing false-positive lookups.
+        if (
+            version is None
+            and self.package_name
+            and self.module_name.split(".")[0] not in ("click", "click_extra", 
"cloup")
+        ):
+            parent = sys.modules.get(self.package_name)
+            if parent:
+                version = getattr(parent, "__version__", None)
+
         if version is not None and not isinstance(version, str):
             raise ValueError(
                 f"Module version {version!r} expected to be a string or None."
@@ -519,17 +545,18 @@
 
             # Replace only the string literal in-place using AST
             # positions, preserving surrounding content and quoting.
-            lines = source.splitlines(keepends=True)
-            line = lines[node.value.end_lineno - 1]
-            # end_col_offset points past the closing quote.
+            end_lineno = node.value.end_lineno
             col_end = node.value.end_col_offset
+            assert end_lineno is not None and col_end is not None
+            lines = source.splitlines(keepends=True)
+            line = lines[end_lineno - 1]
             # The closing quote character.
             quote = line[col_end - 1]
             # Insert the local version just before the closing quote.
             new_line = (
                 line[: col_end - 1] + "+" + local_version + quote + 
line[col_end:]
             )
-            lines[node.value.end_lineno - 1] = new_line
+            lines[end_lineno - 1] = new_line
             file_path.write_text("".join(lines), encoding="utf-8")
 
             logging.info(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/docs/version.md 
new/click-extra-7.6.4/docs/version.md
--- old/click-extra-7.6.3/docs/version.md       2026-03-02 10:52:22.000000000 
+0100
+++ new/click-extra-7.6.4/docs/version.md       2026-03-04 15:50:27.000000000 
+0100
@@ -84,6 +84,15 @@
 The ``git_*`` variables are evaluated at runtime by calling ``git``. They 
return ``None`` in environments where Git is not available (e.g., standalone 
Nuitka binaries, Docker containers without Git). This is distinct from 
``{version}``, which can be [pre-baked at build time](#pre-baked-versions) to 
include the commit hash.
 ```
 
+```{hint}
+The `{version}` variable is resolved in this order:
+
+1. A `__version__` variable defined alongside your CLI (see [standalone 
scripts](#standalone-script)).
+2. A `__version__` variable in the parent package's `__init__.py` (for 
`__main__` entry points, e.g. Nuitka-compiled binaries).
+3. The version from package metadata via 
[`importlib.metadata`](https://docs.python.org/3/library/importlib.metadata.html#distribution-versions)
 β€” this is the most common source for installed packages.
+4. `None` if none of the above succeeds (e.g. unpackaged scripts without 
`__version__`).
+```
+
 ```{error}
 Some Click's built-in variables are not recognized:
 - `%(package)s` should be replaced by `{package_name}`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/pyproject.toml 
new/click-extra-7.6.4/pyproject.toml
--- old/click-extra-7.6.3/pyproject.toml        2026-03-02 10:52:22.000000000 
+0100
+++ new/click-extra-7.6.4/pyproject.toml        2026-03-04 15:50:27.000000000 
+0100
@@ -5,7 +5,7 @@
 [project]
 # Docs: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
 name = "click-extra"
-version = "7.6.3"
+version = "7.6.4"
 description = "🌈 Drop-in replacement for Click to make user-friendly and 
colorful CLI"
 readme = "readme.md"
 keywords = [
@@ -180,7 +180,7 @@
 
 [project.urls]
 "Homepage" = "https://github.com/kdeldycke/click-extra";
-"Download" = "https://github.com/kdeldycke/click-extra/releases/tag/v7.6.3";
+"Download" = "https://github.com/kdeldycke/click-extra/releases/tag/v7.6.4";
 "Changelog" = "https://github.com/kdeldycke/click-extra/blob/main/changelog.md";
 "Issues" = "https://github.com/kdeldycke/click-extra/issues";
 "Repository" = "https://github.com/kdeldycke/click-extra";
@@ -305,6 +305,9 @@
 
 [tool.pytest]
 # https://docs.pytest.org/en/latest/customize.html#pyproject-toml
+markers = [
+  "once: Tests that only need to run once, not across the full CI matrix.",
+]
 addopts = [
   "--durations=10",
   "--cov",
@@ -325,7 +328,7 @@
 report.precision = 2
 
 [tool.bumpversion]
-current_version = "7.6.3"
+current_version = "7.6.4"
 allow_dirty = true
 ignore_missing_files = true
 # Parse versions with an optional .devN suffix (PEP 440).
@@ -391,6 +394,8 @@
   { ignore_missing_imports = true, module = [ "sphinx.*" ], follow_imports = 
"skip" },
 ]
 
+[tool.repomatic]
+
 [tool.gha-utils]
 workflow-sync-exclude = [ "debug.yaml" ]
 dependency-graph-all-groups = false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/tests/cli-test-plan.yaml 
new/click-extra-7.6.4/tests/cli-test-plan.yaml
--- old/click-extra-7.6.3/tests/cli-test-plan.yaml      2026-03-02 
10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/tests/cli-test-plan.yaml      2026-03-04 
15:50:27.000000000 +0100
@@ -1,11 +1,25 @@
 # This test plan checks some high-level behavior of the click-extra CLI.
+#
+# The CLI's prog_name is "demo" (from the @group-decorated function name in 
cli.py).
+# The version regex allows stable (1.2.3), dev (1.2.3.dev0), and prebaked
+# (1.2.3.dev0+abc1234) versions.
 
 
-# Check click-extra is reporting the correct version of itself.
+# Diagnostic: check if binary produces ANY output on stderr (no stdout 
assertion).
+# This helps debug Nuitka onefile binaries where stdout may be empty.
+- cli_parameters:
+    - --verbosity
+    - DEBUG
+    - --version
+  exit_code: 0
+  stderr_regex_matches: "."
+
+
+# Check the CLI reports its version on stdout.
 - cli_parameters: --version
   exit_code: 0
-  stdout_contains: "\x1b[97mclick-extra\x1b[0m, version \x1b[32m"
-  stdout_regex_fullmatch: "\x1b\\[97mclick-extra\x1b\\[0m, version 
\x1b\\[32m[0-9]+\\.[0-9]+\\.[0-9]+\x1b\\[0m\n"
+  stdout_contains: "demo\x1b[0m, version \x1b[32m"
+  stdout_regex_fullmatch: "\x1b\\[97mdemo\x1b\\[0m, version 
\x1b\\[32m[0-9]+\\.[0-9]+\\.[0-9]+(\\.[a-z]+[0-9]+(\\+[0-9a-f]+)?)?\x1b\\[0m\n"
 
 
 # Test combination of version and verbosity.
@@ -15,43 +29,18 @@
     - --version
   exit_code: 0
   stdout_contains: ", version"
-  stdout_regex_matches: "\x1b\\[97mclick-extra\x1b\\[0m, version "
   stderr_contains:
     - "Set <RootLogger root (DEBUG)> to DEBUG."
-    - "\x1b[34mdebug\x1b[0m: {prog_name}      : \x1b[97mclick-extra\x1b[0m\n"
-  stderr_regex_matches:
-    - "\x1b\\[34mdebug\x1b\\[0m: {prog_name}      : 
\x1b\\[97mclick-extra\x1b\\[0m\n"
 
 
-# Test help output.
+# Test help output. Use platform-independent assertions: only check parts of 
the
+# help text that are the same across all OSes (the config default path varies,
+# and column alignment depends on terminal width).
 - cli_parameters:
     - --help
+  exit_code: 0
   strip_ansi: true
   stdout_contains:
-    # yamllint disable rule:line-length
-    - |
-      Usage: click-extra [OPTIONS] COMMAND [ARGS]...
-
-      Options:
-        --time / --no-time    Measure and print elapsed execution time.  
[default:
-                              no-time]
-        --color, --ansi / --no-color, --no-ansi
-                              Strip out all colors and all ANSI codes from 
output.
-                              [default: color]
-        --config CONFIG_PATH  Location of the configuration file. Supports glob
-                              pattern of local path and remote URL.  [default:
-                              ~/Library/Application 
Support/click-extra/*.toml|*.yaml
-                              
|*.yml|*.json|*.json5|*.jsonc|*.hjson|*.ini|*.xml]
-        --no-config           Ignore all configuration files and only use 
command
-                              line parameters and environment variables.
-        --show-params         Show all CLI parameters, their provenance, 
defaults and
-                              value, then exit.
-        --table-format 
[asciidoc|csv|csv-excel|csv-excel-tab|csv-unix|double-grid|double-outline|fancy-grid|fancy-outline|github|grid|heavy-grid|heavy-outline|html|jira|latex|latex-booktabs|latex-longtable|latex-raw|mediawiki|mixed-grid|mixed-outline|moinmoin|orgtbl|outline|pipe|plain|presto|pretty|psql|rounded-grid|rounded-outline|rst|simple|simple-grid|simple-outline|textile|tsv|unsafehtml|vertical|youtrack]
-                              Rendering style of tables.  [default: 
rounded-outline]
-        --verbosity LEVEL     Either CRITICAL, ERROR, WARNING, INFO, DEBUG.
-                              [default: WARNING]
-        -v, --verbose         Increase the default WARNING verbosity by one 
level for
-                              each additional repetition of the option.  
[default: 0]
-        --version             Show the version and exit.
-        -h, --help            Show this message and exit.
-    # yamllint enable rule:line-length
\ No newline at end of file
+    - "Usage: demo [OPTIONS] COMMAND [ARGS]..."
+    - "Show the version and exit."
+    - "Show this message and exit."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/tests/test_colorize.py 
new/click-extra-7.6.4/tests/test_colorize.py
--- old/click-extra-7.6.3/tests/test_colorize.py        2026-03-02 
10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/tests/test_colorize.py        2026-03-04 
15:50:27.000000000 +0100
@@ -67,6 +67,7 @@
 from .conftest import skip_windows_colors
 
 
[email protected]
 def test_theme_definition():
     """Ensure we do not leave any property we would have inherited from cloup 
and
     logging primitives."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/tests/test_commands.py 
new/click-extra-7.6.4/tests/test_commands.py
--- old/click-extra-7.6.3/tests/test_commands.py        2026-03-02 
10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/tests/test_commands.py        2026-03-04 
15:50:27.000000000 +0100
@@ -50,6 +50,7 @@
 )
 
 
[email protected]
 def test_module_root_declarations():
     def fetch_root_members(module):
         """Fetch all members exposed at the module root."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/tests/test_config.py 
new/click-extra-7.6.4/tests/test_config.py
--- old/click-extra-7.6.3/tests/test_config.py  2026-03-02 10:52:22.000000000 
+0100
+++ new/click-extra-7.6.4/tests/test_config.py  2026-03-04 15:50:27.000000000 
+0100
@@ -32,7 +32,7 @@
     is_unix_not_macos,
     is_windows,
 )
-from extra_platforms.pytest import unless_unix_not_macos  # type: 
ignore[attr-defined]
+from extra_platforms.pytest import unless_unix_not_macos
 
 from click_extra import (
     NO_CONFIG,
@@ -1241,9 +1241,7 @@
 
         if force_posix:
             # force_posix ignores XDG_CONFIG_HOME and uses ~/.test-cli/.
-            assert pattern.startswith(
-                str(Path("~/.test-cli").expanduser().resolve())
-            )
+            assert 
pattern.startswith(str(Path("~/.test-cli").expanduser().resolve()))
         else:
             # XDG_CONFIG_HOME is resolved into the pattern.
             assert pattern.startswith(str(custom_config.resolve() / 
"test-cli"))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/tests/test_pygments.py 
new/click-extra-7.6.4/tests/test_pygments.py
--- old/click-extra-7.6.3/tests/test_pygments.py        2026-03-02 
10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/tests/test_pygments.py        2026-03-04 
15:50:27.000000000 +0100
@@ -22,6 +22,7 @@
 from operator import itemgetter
 from pathlib import Path
 
+import pytest
 import requests
 from boltons.strutils import camel2under
 from boltons.typeutils import issubclass
@@ -44,6 +45,7 @@
 PROJECT_ROOT = Path(__file__).parent.parent
 
 
[email protected]
 def test_ansi_lexers_candidates(tmp_path):
     """Look into Pygments test suite to find all ANSI lexers candidates.
 
@@ -157,6 +159,7 @@
     assert project_entry_points == entry_points
 
 
[email protected]
 def test_formatter_entry_points():
     entry_points = {}
     for name in collect_classes(Formatter):
@@ -166,6 +169,7 @@
     check_entry_points(entry_points, "project", "entry-points", 
"pygments.formatters")
 
 
[email protected]
 def test_filter_entry_points():
     entry_points = {}
     for name in collect_classes(Filter):
@@ -175,6 +179,7 @@
     check_entry_points(entry_points, "project", "entry-points", 
"pygments.filters")
 
 
[email protected]
 def test_lexer_entry_points():
     entry_points = {}
     for lexer in collect_session_lexers():
@@ -194,24 +199,28 @@
     check_entry_points(entry_points, "project", "entry-points", 
"pygments.lexers")
 
 
[email protected]
 def test_registered_formatters():
     for klass in collect_classes(Formatter).values():
         for alias in klass.aliases:
             get_formatter_by_name(alias)
 
 
[email protected]
 def test_registered_filters():
     for name in collect_classes(Filter):
         entry_id = camel2under(name).replace("_", "-")
         get_filter_by_name(entry_id)
 
 
[email protected]
 def test_registered_lexers():
     for klass in collect_classes(Lexer).values():
         for alias in klass.aliases:
             get_lexer_by_name(alias)
 
 
[email protected]
 def test_ansi_lexers_doc():
     doc_content = 
PROJECT_ROOT.joinpath("docs/pygments.md").read_text(encoding="utf-8")
     for lexer in collect_session_lexers():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/tests/test_table.py 
new/click-extra-7.6.4/tests/test_table.py
--- old/click-extra-7.6.3/tests/test_table.py   2026-03-02 10:52:22.000000000 
+0100
+++ new/click-extra-7.6.4/tests/test_table.py   2026-03-04 15:50:27.000000000 
+0100
@@ -34,6 +34,7 @@
 from click_extra.pytest import command_decorators
 
 
[email protected]
 def test_table_formats_definition():
     """Check all table formats are accounted for and properly named."""
     # Formats from tabulate.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/tests/test_version.py 
new/click-extra-7.6.4/tests/test_version.py
--- old/click-extra-7.6.3/tests/test_version.py 2026-03-02 10:52:22.000000000 
+0100
+++ new/click-extra-7.6.4/tests/test_version.py 2026-03-04 15:50:27.000000000 
+0100
@@ -25,7 +25,9 @@
 
 from __future__ import annotations
 
+import inspect
 import re
+import sys
 
 import click
 import pytest
@@ -241,6 +243,60 @@
     assert result.exit_code == 0
 
 
+def test_module_version_parent_package_fallback(monkeypatch):
+    """``module_version`` falls back to parent package's ``__version__``.
+
+    Simulates the Nuitka use-case: a CLI whose module is ``myapp.__main__``
+    (no ``__version__``), with the parent package ``myapp`` providing it.
+    """
+    import types
+
+    # Create a fake parent package with __version__.
+    fake_parent = types.ModuleType("myapp")
+    fake_parent.__version__ = "1.2.3"
+    fake_parent.__package__ = "myapp"
+
+    # Create a fake __main__ submodule without __version__.
+    fake_main = types.ModuleType("myapp.__main__")
+    fake_main.__package__ = "myapp"
+
+    monkeypatch.setitem(sys.modules, "myapp", fake_parent)
+    monkeypatch.setitem(sys.modules, "myapp.__main__", fake_main)
+
+    opt = ExtraVersionOption(["--version"])
+    # Bypass cli_frame resolution by setting the module directly.
+    monkeypatch.setattr(
+        type(opt),
+        "module",
+        property(lambda self: fake_main),
+    )
+
+    assert opt.module_version == "1.2.3"
+
+
+def test_cli_frame_fallback(monkeypatch):
+    """``cli_frame()`` falls back to the outermost frame when all frames are
+    from the Click ecosystem."""
+    original_stack = inspect.stack
+
+    def patched_stack():
+        """Make every frame look like it belongs to click_extra."""
+        frames = original_stack()
+        for frame_info in frames:
+            frame_info.frame.f_globals.setdefault("__name__", "")
+            # Temporarily override __name__ so the heuristic skips all frames.
+            frame_info.frame.f_globals["__name__"] = (
+                "click_extra." + frame_info.function
+            )
+        return frames
+
+    monkeypatch.setattr(inspect, "stack", patched_stack)
+
+    # Should not raise RuntimeError; instead falls back to outermost frame.
+    frame = ExtraVersionOption.cli_frame()
+    assert frame is not None
+
+
 @pytest.mark.parametrize(
     "params",
     (None, "--help", "blah", ("--config", "random.toml")),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/click-extra-7.6.3/uv.lock 
new/click-extra-7.6.4/uv.lock
--- old/click-extra-7.6.3/uv.lock       2026-03-02 10:52:22.000000000 +0100
+++ new/click-extra-7.6.4/uv.lock       2026-03-04 15:50:27.000000000 +0100
@@ -9,7 +9,7 @@
 ]
 
 [options]
-exclude-newer = "2026-02-20T15:19:31.896200888Z"
+exclude-newer = "2026-02-23T17:23:32.3307652Z"
 exclude-newer-span = "P1W"
 
 [[package]]
@@ -194,7 +194,7 @@
 
 [[package]]
 name = "click-extra"
-version = "7.6.3.dev0"
+version = "7.6.4.dev0"
 source = { editable = "." }
 dependencies = [
     { name = "boltons" },
@@ -532,7 +532,7 @@
 version = "1.3.1"
 source = { registry = "https://pypi.org/simple"; }
 dependencies = [
-    { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+    { name = "typing-extensions", marker = "python_full_version < '3.13'" },
 ]
 sdist = { url = 
"https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz";,
 hash = 
"sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size 
= 30371, upload-time = "2025-11-21T23:01:54.787Z" }
 wheels = [
@@ -1129,14 +1129,14 @@
 
 [[package]]
 name = "sphinx-autodoc-typehints"
-version = "3.6.2"
+version = "3.6.3"
 source = { registry = "https://pypi.org/simple"; }
 dependencies = [
     { name = "sphinx", version = "9.1.0", source = { registry = 
"https://pypi.org/simple"; }, marker = "python_full_version >= '3.14'" },
 ]
-sdist = { url = 
"https://files.pythonhosted.org/packages/97/51/6603ed3786a2d52366c66f49bc8afb31ae5c0e33d4a156afcb38d2bac62c/sphinx_autodoc_typehints-3.6.2.tar.gz";,
 hash = 
"sha256:3d37709a21b7b765ad6e20a04ecefcb229b9eb0007cb24f6ebaa8a4576ea7f06", size 
= 37574, upload-time = "2026-01-02T21:25:28.216Z" }
+sdist = { url = 
"https://files.pythonhosted.org/packages/64/5f/ebcaed1a67e623e4a7622808a8be6b0fd8344313e185f62e85a26b0ce26a/sphinx_autodoc_typehints-3.6.3.tar.gz";,
 hash = 
"sha256:6c387b47d9ad5e75b157810af5bad46901f0a22708ed5e4adf466885a9c60910", size 
= 38288, upload-time = "2026-02-18T04:22:08.384Z" }
 wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/e5/6a/877e8a6ea52fc86d88ce110ebcfe4f8474ff590d8a8d322909673af3da7b/sphinx_autodoc_typehints-3.6.2-py3-none-any.whl";,
 hash = 
"sha256:9e70bee1f487b087c83ba0f4949604a4630bee396e263a324aae1dc4268d2c0f", size 
= 20853, upload-time = "2026-01-02T21:25:26.853Z" },
+    { url = 
"https://files.pythonhosted.org/packages/0a/bd/2b853836d152e40a27655828fdc02c5128f294ac452ad9a13424bb7f92fa/sphinx_autodoc_typehints-3.6.3-py3-none-any.whl";,
 hash = 
"sha256:46ebc68fa85b320d55887a8d836a01e12e3b7744da973e70af8cedc74072aad5", size 
= 20882, upload-time = "2026-02-18T04:22:07.238Z" },
 ]
 
 [[package]]
@@ -1346,11 +1346,11 @@
 
 [[package]]
 name = "types-docutils"
-version = "0.22.3.20251115"
+version = "0.22.3.20260223"
 source = { registry = "https://pypi.org/simple"; }
-sdist = { url = 
"https://files.pythonhosted.org/packages/eb/d7/576ec24bf61a280f571e1f22284793adc321610b9bcfba1bf468cf7b334f/types_docutils-0.22.3.20251115.tar.gz";,
 hash = 
"sha256:0f79ea6a7bd4d12d56c9f824a0090ffae0ea4204203eb0006392906850913e16", size 
= 56828, upload-time = "2025-11-15T02:59:57.371Z" }
+sdist = { url = 
"https://files.pythonhosted.org/packages/80/33/92c0129283363e3b3ba270bf6a2b7d077d949d2f90afc4abaf6e73578563/types_docutils-0.22.3.20260223.tar.gz";,
 hash = 
"sha256:e90e868da82df615ea2217cf36dff31f09660daa15fc0f956af53f89c1364501", size 
= 57230, upload-time = "2026-02-23T04:11:21.806Z" }
 wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/9c/01/61ac9eb38f1f978b47443dc6fd2e0a3b0f647c2da741ddad30771f1b2b6f/types_docutils-0.22.3.20251115-py3-none-any.whl";,
 hash = 
"sha256:c6e53715b65395d00a75a3a8a74e352c669bc63959e65a207dffaa22f4a2ad6e", size 
= 91951, upload-time = "2025-11-15T02:59:56.413Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ba/c7/a4ae6a75d5b07d63089d5c04d450a0de4a5d48ffcb84b95659b22d3885fe/types_docutils-0.22.3.20260223-py3-none-any.whl";,
 hash = 
"sha256:cc2d6b7560a28e351903db0989091474aa619ad287843a018324baee9c4d9a8f", size 
= 91969, upload-time = "2026-02-23T04:11:20.966Z" },
 ]
 
 [[package]]
@@ -1445,21 +1445,21 @@
 
 [[package]]
 name = "werkzeug"
-version = "3.1.5"
+version = "3.1.6"
 source = { registry = "https://pypi.org/simple"; }
 dependencies = [
     { name = "markupsafe" },
 ]
-sdist = { url = 
"https://files.pythonhosted.org/packages/5a/70/1469ef1d3542ae7c2c7b72bd5e3a4e6ee69d7978fa8a3af05a38eca5becf/werkzeug-3.1.5.tar.gz";,
 hash = 
"sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67", size 
= 864754, upload-time = "2026-01-08T17:49:23.247Z" }
+sdist = { url = 
"https://files.pythonhosted.org/packages/61/f1/ee81806690a87dab5f5653c1f146c92bc066d7f4cebc603ef88eb9e13957/werkzeug-3.1.6.tar.gz";,
 hash = 
"sha256:210c6bede5a420a913956b4791a7f4d6843a43b6fcee4dfa08a65e93007d0d25", size 
= 864736, upload-time = "2026-02-19T15:17:18.884Z" }
 wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/ad/e4/8d97cca767bcc1be76d16fb76951608305561c6e056811587f36cb1316a8/werkzeug-3.1.5-py3-none-any.whl";,
 hash = 
"sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc", size 
= 225025, upload-time = "2026-01-08T17:49:21.859Z" },
+    { url = 
"https://files.pythonhosted.org/packages/4d/ec/d58832f89ede95652fd01f4f24236af7d32b70cab2196dfcc2d2fd13c5c2/werkzeug-3.1.6-py3-none-any.whl";,
 hash = 
"sha256:7ddf3357bb9564e407607f988f683d72038551200c704012bb9a4c523d42f131", size 
= 225166, upload-time = "2026-02-19T15:17:17.475Z" },
 ]
 
 [[package]]
 name = "xmltodict"
-version = "1.0.3"
+version = "1.0.4"
 source = { registry = "https://pypi.org/simple"; }
-sdist = { url = 
"https://files.pythonhosted.org/packages/a9/66/d1242ce8748c698e0036837dfbb530480e31f11d3ecf7101cd4e30d29913/xmltodict-1.0.3.tar.gz";,
 hash = 
"sha256:3bf1f49c7836df34cf6d9cc7e690c4351f7dfff2ab0b8a1988bba4a9b9474909", size 
= 25170, upload-time = "2026-02-15T04:05:05.728Z" }
+sdist = { url = 
"https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz";,
 hash = 
"sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size 
= 26124, upload-time = "2026-02-22T02:21:22.074Z" }
 wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/82/df/5c50d5bfc886cf61e665f34925e70c7d5ab1d39db0bcc4a03f6fdae3cd76/xmltodict-1.0.3-py3-none-any.whl";,
 hash = 
"sha256:35d65d5c08f2a1121df338a0c4e49ca638480fa7c1b899ded45e0759bf32e40e", size 
= 13295, upload-time = "2026-02-15T04:05:04.407Z" },
+    { url = 
"https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl";,
 hash = 
"sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size 
= 13580, upload-time = "2026-02-22T02:21:21.039Z" },
 ]

Reply via email to