Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-hatch for openSUSE:Factory 
checked in at 2026-05-27 16:14:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-hatch (Old)
 and      /work/SRC/openSUSE:Factory/.python-hatch.new.1937 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-hatch"

Wed May 27 16:14:10 2026 rev:26 rq:1355147 version:1.16.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-hatch/python-hatch.changes        
2026-02-13 13:58:35.166810131 +0100
+++ /work/SRC/openSUSE:Factory/.python-hatch.new.1937/python-hatch.changes      
2026-05-27 16:14:29.210825003 +0200
@@ -1,0 +2,13 @@
+Mon May 25 09:00:32 UTC 2026 - Markéta Machová <[email protected]>
+
+- Update to 1.16.5
+  * Fixes hatch shell type error for keep_env.
+  * SBOM documentation for including SBOM files in sdist
+  * Fixes workspace member detection to properly handle shared path
+    prefixes.
+  * Handle a breaking change in virtualenv by only supporting the
+    latest version and adding python-discovery as a dependency.
+- Add fix-pth-editables06.patch to fix test failure
+- Drop upstream shell.patch and packaging26.patch
+
+-------------------------------------------------------------------

Old:
----
  hatch-v1.16.3.tar.gz
  packaging26.patch
  shell.patch

New:
----
  fix-pth-editables06.patch
  hatch-v1.16.5.tar.gz

----------(Old B)----------
  Old:- Add fix-pth-editables06.patch to fix test failure
- Drop upstream shell.patch and packaging26.patch
  Old:- Add fix-pth-editables06.patch to fix test failure
- Drop upstream shell.patch and packaging26.patch
----------(Old E)----------

----------(New B)----------
  New:    latest version and adding python-discovery as a dependency.
- Add fix-pth-editables06.patch to fix test failure
- Drop upstream shell.patch and packaging26.patch
----------(New E)----------

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

Other differences:
------------------
++++++ python-hatch.spec ++++++
--- /var/tmp/diff_new_pack.nenGqA/_old  2026-05-27 16:14:30.390873619 +0200
+++ /var/tmp/diff_new_pack.nenGqA/_new  2026-05-27 16:14:30.390873619 +0200
@@ -31,7 +31,7 @@
 %endif
 %{?sle15_python_module_pythons}
 Name:           python-hatch%{psuffix}
-Version:        1.16.3
+Version:        1.16.5
 Release:        0
 Summary:        Modern, extensible Python project management
 License:        MIT
@@ -53,10 +53,8 @@
 Source22:       
https://files.pythonhosted.org/packages/py3/s/setuptools/setuptools-80.9.0-py3-none-any.whl
 Source23:       
https://files.pythonhosted.org/packages/py3/t/trove_classifiers/trove_classifiers-2025.12.1.14-py3-none-any.whl
 Source24:       
https://files.pythonhosted.org/packages/py3/u/urllib3/urllib3-2.6.2-py3-none-any.whl
-# PATCH-FIX-UPSTREAM https://github.com/pypa/hatch/pull/2165 keep_env TypeError
-Patch0:         shell.patch
-# PATCH-FIX-UPSTREAM https://github.com/pypa/hatch/pull/2159 Fix warning and 
tests with packaging 26.0
-Patch1:         packaging26.patch
+# PATCH-FIX-UPSTREAM https://github.com/pypa/hatch/pull/2248 Update 
editable-exact test templates for editables 0.6 .pth file rename
+Patch0:         fix-pth-editables06.patch
 BuildRequires:  %{python_module base >= 3.10}
 BuildRequires:  %{python_module hatch-vcs >= 0.3}
 BuildRequires:  %{python_module hatchling >= 1.27}
@@ -72,12 +70,13 @@
 Requires:       python-packaging >= 24.2
 Requires:       python-platformdirs >= 2.5.0
 Requires:       python-pyproject-hooks
+Requires:       python-python-discovery >= 1.1
 Requires:       python-rich >= 11.2.0
 Requires:       python-shellingham >= 1.4.0
 Requires:       python-tomli-w >= 1.0
 Requires:       python-tomlkit >= 0.11.1
 Requires:       python-uv >= 0.5.23
-Requires:       python-virtualenv >= 20.26.1
+Requires:       python-virtualenv >= 21
 Requires:       (python-backports.zstd > 1 if python-base < 3.14)
 Requires:       (python-pexpect >= 4.8 with python-pexpect < 5)
 Requires:       (python-userpath >= 1.7 with python-userpath < 2)





++++++ fix-pth-editables06.patch ++++++
>From 34dba22e5e3c7b7468b67f53f93b7340e54609b8 Mon Sep 17 00:00:00 2001
From: Cary Hawkins <[email protected]>
Date: Thu, 23 Apr 2026 00:41:48 -0400
Subject: [PATCH] Annotate relevant_config as dict[str, Any] to prevent mypy
 from narrowing its key type and rejecting valid "dirs" access (#2248)

* Annotate relevant_config as dict[str, Any] to prevent mypy from narrowing its 
key type and rejecting valid "dirs" access

* Update editable-exact test templates for editables 0.6 .pth file rename

* Fix tests impacted by pth name changes in editables release
---
 src/hatch/cli/self/report.py                                  | 4 ++--
 tests/backend/builders/test_wheel.py                          | 1 +
 tests/helpers/templates/wheel/standard_editable_exact.py      | 2 +-
 .../wheel/standard_editable_exact_extra_dependencies.py       | 2 +-
 .../templates/wheel/standard_editable_exact_force_include.py  | 2 +-
 tests/helpers/templates/wheel/standard_editable_pth.py        | 2 +-
 .../wheel/standard_editable_pth_extra_dependencies.py         | 2 +-
 .../templates/wheel/standard_editable_pth_force_include.py    | 2 +-
 8 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/src/hatch/cli/self/report.py b/src/hatch/cli/self/report.py
index 49fe79b45..925ef83af 100644
--- a/src/hatch/cli/self/report.py
+++ b/src/hatch/cli/self/report.py
@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Any
 
 import click
 
@@ -80,7 +80,7 @@ def report(app: Application, *, no_open: bool) -> None:
 
     # Retain the config that would be most useful
     full_config = load_toml_data(app.config_file.read_scrubbed())
-    relevant_config = {}
+    relevant_config: dict[str, Any] = {}
     for setting in ("mode", "shell"):
         if setting in full_config:
             relevant_config[setting] = full_config[setting]
diff --git a/tests/backend/builders/test_wheel.py 
b/tests/backend/builders/test_wheel.py
index eeada10d0..28b98456f 100644
--- a/tests/backend/builders/test_wheel.py
+++ b/tests/backend/builders/test_wheel.py
@@ -3224,6 +3224,7 @@ def test_editable_pth(self, hatch, helpers, temp_dir):
             project_name,
             metadata_directory=metadata_directory,
             package_paths=[str(project_path)],
+            pth_file_name=f"_{builder.metadata.core.name.replace('-', 
'_')}.pth",
         )
         helpers.assert_files(extraction_directory, expected_files)
 
diff --git a/tests/helpers/templates/wheel/standard_editable_exact.py 
b/tests/helpers/templates/wheel/standard_editable_exact.py
index 491be227d..442d92230 100644
--- a/tests/helpers/templates/wheel/standard_editable_exact.py
+++ b/tests/helpers/templates/wheel/standard_editable_exact.py
@@ -17,7 +17,7 @@ def get_files(**kwargs):
         if str(f.path) == "LICENSE.txt"
     ]
 
-    pth_file_name = f"_{kwargs['package_name']}.pth"
+    pth_file_name = f"_editable_impl_{kwargs['package_name']}.pth"
     loader_file_name = f"_editable_impl_{kwargs['package_name']}.py"
     files.extend((
         File(Path(pth_file_name), f"import 
_editable_impl_{kwargs['package_name']}"),
diff --git 
a/tests/helpers/templates/wheel/standard_editable_exact_extra_dependencies.py 
b/tests/helpers/templates/wheel/standard_editable_exact_extra_dependencies.py
index 817a643eb..6a4158828 100644
--- 
a/tests/helpers/templates/wheel/standard_editable_exact_extra_dependencies.py
+++ 
b/tests/helpers/templates/wheel/standard_editable_exact_extra_dependencies.py
@@ -17,7 +17,7 @@ def get_files(**kwargs):
         if str(f.path) == "LICENSE.txt"
     ]
 
-    pth_file_name = f"_{kwargs['package_name']}.pth"
+    pth_file_name = f"_editable_impl_{kwargs['package_name']}.pth"
     loader_file_name = f"_editable_impl_{kwargs['package_name']}.py"
     files.extend((
         File(Path(pth_file_name), f"import 
_editable_impl_{kwargs['package_name']}"),
diff --git 
a/tests/helpers/templates/wheel/standard_editable_exact_force_include.py 
b/tests/helpers/templates/wheel/standard_editable_exact_force_include.py
index e9de6159c..72bf7a58f 100644
--- a/tests/helpers/templates/wheel/standard_editable_exact_force_include.py
+++ b/tests/helpers/templates/wheel/standard_editable_exact_force_include.py
@@ -18,7 +18,7 @@ def get_files(**kwargs):
         elif f.path.parts[-1] == "__about__.py":
             files.append(File(Path("zfoo.py"), f.contents))
 
-    pth_file_name = f"_{kwargs['package_name']}.pth"
+    pth_file_name = f"_editable_impl_{kwargs['package_name']}.pth"
     loader_file_name = f"_editable_impl_{kwargs['package_name']}.py"
     files.extend((
         File(Path(pth_file_name), f"import 
_editable_impl_{kwargs['package_name']}"),
diff --git a/tests/helpers/templates/wheel/standard_editable_pth.py 
b/tests/helpers/templates/wheel/standard_editable_pth.py
index 5a170cc6a..c78915cf6 100644
--- a/tests/helpers/templates/wheel/standard_editable_pth.py
+++ b/tests/helpers/templates/wheel/standard_editable_pth.py
@@ -17,7 +17,7 @@ def get_files(**kwargs):
         if str(f.path) == "LICENSE.txt"
     ]
 
-    pth_file_name = f"_{kwargs['package_name']}.pth"
+    pth_file_name = kwargs.get("pth_file_name", 
f"_editable_impl_{kwargs['package_name']}.pth")
     files.extend((
         File(Path(pth_file_name), "\n".join(package_paths)),
         File(
diff --git 
a/tests/helpers/templates/wheel/standard_editable_pth_extra_dependencies.py 
b/tests/helpers/templates/wheel/standard_editable_pth_extra_dependencies.py
index 834383259..cdc9f2ea9 100644
--- a/tests/helpers/templates/wheel/standard_editable_pth_extra_dependencies.py
+++ b/tests/helpers/templates/wheel/standard_editable_pth_extra_dependencies.py
@@ -17,7 +17,7 @@ def get_files(**kwargs):
         if str(f.path) == "LICENSE.txt"
     ]
 
-    pth_file_name = f"_{kwargs['package_name']}.pth"
+    pth_file_name = kwargs.get("pth_file_name", 
f"_editable_impl_{kwargs['package_name']}.pth")
     files.extend((
         File(Path(pth_file_name), "\n".join(package_paths)),
         File(
diff --git 
a/tests/helpers/templates/wheel/standard_editable_pth_force_include.py 
b/tests/helpers/templates/wheel/standard_editable_pth_force_include.py
index 003954027..00e0af96a 100644
--- a/tests/helpers/templates/wheel/standard_editable_pth_force_include.py
+++ b/tests/helpers/templates/wheel/standard_editable_pth_force_include.py
@@ -18,7 +18,7 @@ def get_files(**kwargs):
         elif f.path.parts[-1] == "__about__.py":
             files.append(File(Path("zfoo.py"), f.contents))
 
-    pth_file_name = f"_{kwargs['package_name']}.pth"
+    pth_file_name = kwargs.get("pth_file_name", 
f"_editable_impl_{kwargs['package_name']}.pth")
     files.extend((
         File(Path(pth_file_name), "\n".join(package_paths)),
         File(


++++++ hatch-v1.16.3.tar.gz -> hatch-v1.16.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/.github/workflows/build-hatch.yml 
new/hatch-hatch-v1.16.5/.github/workflows/build-hatch.yml
--- old/hatch-hatch-v1.16.3/.github/workflows/build-hatch.yml   2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/.github/workflows/build-hatch.yml   2026-02-27 
18:59:39.000000000 +0100
@@ -582,7 +582,7 @@
         path: installers
         merge-multiple: true
 
-    - name: Add assets to current release
+    - name: Add assets to draft release
       uses: softprops/action-gh-release@v2
       with:
         files: |-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/.github/workflows/build-hatchling.yml 
new/hatch-hatch-v1.16.5/.github/workflows/build-hatchling.yml
--- old/hatch-hatch-v1.16.3/.github/workflows/build-hatchling.yml       
2026-01-21 02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/.github/workflows/build-hatchling.yml       
2026-02-27 18:59:39.000000000 +0100
@@ -43,6 +43,7 @@
     runs-on: ubuntu-latest
 
     permissions:
+      contents: write
       id-token: write
 
     steps:
@@ -55,3 +56,8 @@
       uses: pypa/[email protected]
       with:
         skip-existing: true
+
+    - name: Add assets to draft release
+      uses: softprops/action-gh-release@v2
+      with:
+        files: dist/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/backend/src/hatchling/__about__.py 
new/hatch-hatch-v1.16.5/backend/src/hatchling/__about__.py
--- old/hatch-hatch-v1.16.3/backend/src/hatchling/__about__.py  2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/backend/src/hatchling/__about__.py  2026-02-27 
18:59:39.000000000 +0100
@@ -1 +1 @@
-__version__ = "1.28.0"
+__version__ = "1.29.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/backend/src/hatchling/builders/wheel.py 
new/hatch-hatch-v1.16.5/backend/src/hatchling/builders/wheel.py
--- old/hatch-hatch-v1.16.3/backend/src/hatchling/builders/wheel.py     
2026-01-21 02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/backend/src/hatchling/builders/wheel.py     
2026-02-27 18:59:39.000000000 +0100
@@ -88,7 +88,9 @@
     def get_reproducible_time_tuple() -> TIME_TUPLE:
         from datetime import datetime, timezone
 
-        d = datetime.fromtimestamp(get_reproducible_timestamp(), timezone.utc)
+        # `zipfile.ZipInfo` does not support timestamps before 1980
+        min_ts = 315532800  # 1980-01-01T00:00:00Z
+        d = datetime.fromtimestamp(max(get_reproducible_timestamp(), min_ts), 
timezone.utc)
         return d.year, d.month, d.day, d.hour, d.minute, d.second
 
     def add_file(self, included_file: IncludedFile) -> tuple[str, str, str]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/backend/src/hatchling/version/scheme/standard.py 
new/hatch-hatch-v1.16.5/backend/src/hatchling/version/scheme/standard.py
--- old/hatch-hatch-v1.16.3/backend/src/hatchling/version/scheme/standard.py    
2026-01-21 02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/backend/src/hatchling/version/scheme/standard.py    
2026-02-27 18:59:39.000000000 +0100
@@ -1,6 +1,6 @@
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Any, cast
+from typing import TYPE_CHECKING, Any, Literal, cast
 
 from hatchling.version.scheme.plugin.interface import VersionSchemeInterface
 
@@ -28,13 +28,15 @@
 
         for version in versions:
             if version == "release":
-                reset_version_parts(original, release=original.release)
+                original = reset_version_parts(original, 
release=original.release)
             elif version == "major":
-                reset_version_parts(original, release=update_release(original, 
[original.major + 1]))
+                original = reset_version_parts(original, 
release=update_release(original, [original.major + 1]))
             elif version == "minor":
-                reset_version_parts(original, release=update_release(original, 
[original.major, original.minor + 1]))
+                original = reset_version_parts(
+                    original, release=update_release(original, 
[original.major, original.minor + 1])
+                )
             elif version in {"micro", "patch", "fix"}:
-                reset_version_parts(
+                original = reset_version_parts(
                     original, release=update_release(original, 
[original.major, original.minor, original.micro + 1])
                 )
             elif version in {"a", "b", "c", "rc", "alpha", "beta", "pre", 
"preview"}:
@@ -44,13 +46,13 @@
                     if phase == current_phase:
                         number = current_number + 1
 
-                reset_version_parts(original, pre=(phase, number))
+                original = reset_version_parts(original, pre=(phase, number))
             elif version in {"post", "rev", "r"}:
                 number = 0 if original.post is None else original.post + 1
-                reset_version_parts(original, 
post=parse_letter_version(version, number))
+                original = reset_version_parts(original, post=number)
             elif version == "dev":
                 number = 0 if original.dev is None else original.dev + 1
-                reset_version_parts(original, dev=(version, number))
+                original = reset_version_parts(original, dev=number)
             else:
                 if len(versions) > 1:
                     message = "Cannot specify multiple update operations with 
an explicit version"
@@ -66,9 +68,13 @@
         return str(original)
 
 
-def reset_version_parts(version: Version, **kwargs: Any) -> None:
-    # 
https://github.com/pypa/packaging/blob/20.9/packaging/version.py#L301-L310
-    internal_version = version._version  # noqa: SLF001
+def reset_version_parts(version: Version, **kwargs: Any) -> Version:
+    """
+    Update version parts and clear all subsequent parts in the sequence.
+
+    When __replace__ is available (packaging 26.0+), returns a new Version 
instance.
+    Otherwise mutates version via private ._version and returns the same 
instance.
+    """
     parts: dict[str, Any] = {}
     ordered_part_names = ("epoch", "release", "pre", "post", "dev", "local")
 
@@ -80,9 +86,16 @@
             parts[part_name] = kwargs[part_name]
             reset = True
         else:
-            parts[part_name] = getattr(internal_version, part_name)
+            parts[part_name] = getattr(version, part_name)
+
+    # Use __replace__ if available for efficiency
+    if hasattr(version, "__replace__"):
+        return version.__replace__(**parts)
 
+    # Reference: 
https://github.com/pypa/packaging/blob/20.9/packaging/version.py#L301-L310
+    internal_version = version._version  # noqa: SLF001
     version._version = type(internal_version)(**parts)  # noqa: SLF001
+    return version
 
 
 def update_release(original_version: Version, new_release_parts: list[int]) -> 
tuple[int, ...]:
@@ -92,7 +105,7 @@
     return tuple(new_release_parts)
 
 
-def parse_letter_version(*args: Any, **kwargs: Any) -> tuple[str, int]:
+def parse_letter_version(*args: Any, **kwargs: Any) -> tuple[Literal["a", "b", 
"rc"], int]:
     from packaging.version import _parse_letter_version  # noqa: PLC2701
 
-    return cast(tuple[str, int], _parse_letter_version(*args, **kwargs))
+    return cast(tuple[Literal["a", "b", "rc"], int], 
_parse_letter_version(*args, **kwargs))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/backend/tests/downstream/requirements.txt 
new/hatch-hatch-v1.16.5/backend/tests/downstream/requirements.txt
--- old/hatch-hatch-v1.16.3/backend/tests/downstream/requirements.txt   
2026-01-21 02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/backend/tests/downstream/requirements.txt   
2026-02-27 18:59:39.000000000 +0100
@@ -2,4 +2,4 @@
 packaging
 requests
 tomli
-virtualenv>=20.13.1
+virtualenv>=21
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/docs/history/hatch.md 
new/hatch-hatch-v1.16.5/docs/history/hatch.md
--- old/hatch-hatch-v1.16.3/docs/history/hatch.md       2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/docs/history/hatch.md       2026-02-27 
18:59:39.000000000 +0100
@@ -8,6 +8,20 @@
 
 ## Unreleased
 
+## [1.16.5](https://github.com/pypa/hatch/releases/tag/hatch-v1.16.5) - 
2026-02-26 ## {: #hatch-v1.16.5 }
+
+***Fixed:***
+
+- Handle a breaking change in `virtualenv` by only supporting the latest 
version and adding `python-discovery` as a dependency.
+
+## [1.16.4](https://github.com/pypa/hatch/releases/tag/hatch-v1.16.4) - 
2026-02-23 ## {: #hatch-v1.16.4 }
+
+***Fixed:***
+
+- Fixes hatch shell type error for keep_env.
+- SBOM documentation for including SBOM files in `sdist`
+- Fixes workspace member detection to properly handle shared path prefixes.
+
 ## [1.16.3](https://github.com/pypa/hatch/releases/tag/hatch-v1.16.3) - 
2026-01-20 ## {: #hatch-v1.16.3 }
 
 ***Added:***
@@ -16,10 +30,10 @@
 
 ***Fixed:***
 
-- Fix issue with self-referential dependencies not being recognized. 
+- Fix issue with self-referential dependencies not being recognized.
 - Fix incomplete environments created when an exception occurs during creation.
-- Fix dependency-groups not working with when environment is not marked as 
builder. 
-- Change Keyring to take expect repository URL instead of repository name. 
+- Fix dependency-groups not working with when environment is not marked as 
builder.
+- Change Keyring to take expect repository URL instead of repository name.
 
 ## [1.16.2](https://github.com/pypa/hatch/releases/tag/hatch-v1.16.2) - 
2025-12-06 ## {: #hatch-v1.16.2 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/docs/history/hatchling.md 
new/hatch-hatch-v1.16.5/docs/history/hatchling.md
--- old/hatch-hatch-v1.16.3/docs/history/hatchling.md   2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/docs/history/hatchling.md   2026-02-27 
18:59:39.000000000 +0100
@@ -8,6 +8,12 @@
 
 ## Unreleased
 
+## [1.29.0](https://github.com/pypa/hatch/releases/tag/hatchling-v1.29.0) - 
2026-02-21 ## {: #hatchling-v1.29.0 }
+
+***Fixed:***
+
+- Source Date Epoch no longer fails when set to date before 1980. 
+
 ## [1.28.0](https://github.com/pypa/hatch/releases/tag/hatchling-v1.28.0) - 
2025-11-26 ## {: #hatchling-v1.28.0 }
 
 ***Changed:***
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/docs/plugins/builder/wheel.md 
new/hatch-hatch-v1.16.5/docs/plugins/builder/wheel.md
--- old/hatch-hatch-v1.16.3/docs/plugins/builder/wheel.md       2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/docs/plugins/builder/wheel.md       2026-02-27 
18:59:39.000000000 +0100
@@ -25,6 +25,8 @@
 | `bypass-selection` | `false` | Whether or not to suppress the error when one 
has not defined any file selection options and all heuristics have failed to 
determine what to ship |
 | `sbom-files` | | A list of paths to [Software Bill of 
Materials](https://peps.python.org/pep-0770/) files that will be included in 
the `.dist-info/sboms/` directory of the wheel |
 
+!!! note
+    Many build frontends will build the wheel from a source distribution. This 
is the recommended approach, but it means you need to ensure the SBOM files 
passed to `sbom-files` are also [included in the source 
distribution](https://hatch.pypa.io/latest/config/build/#file-selection).
 
 ## Versions
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/pyproject.toml 
new/hatch-hatch-v1.16.5/pyproject.toml
--- old/hatch-hatch-v1.16.3/pyproject.toml      2026-01-21 02:32:44.000000000 
+0100
+++ new/hatch-hatch-v1.16.5/pyproject.toml      2026-02-27 18:59:39.000000000 
+0100
@@ -46,6 +46,7 @@
   "keyring>=23.5.0",
   "packaging>=24.2",
   "pexpect~=4.8",
+  "python-discovery>=1.1",
   "platformdirs>=2.5.0",
   "pyproject-hooks",
   "rich>=11.2.0",
@@ -54,7 +55,7 @@
   "tomlkit>=0.11.1",
   "userpath~=1.7",
   "uv>=0.5.23",
-  "virtualenv>=20.26.6",
+  "virtualenv>=21",
   "backports.zstd>=1.0.0 ; python_version<'3.14'",
 ]
 dynamic = ["version"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/scripts/release_github.py 
new/hatch-hatch-v1.16.5/scripts/release_github.py
--- old/hatch-hatch-v1.16.3/scripts/release_github.py   2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/scripts/release_github.py   2026-02-27 
18:59:39.000000000 +0100
@@ -1,4 +1,6 @@
 import argparse
+import subprocess
+import sys
 import webbrowser
 from urllib.parse import urlencode
 
@@ -11,11 +13,23 @@
     args = parser.parse_args()
 
     version, notes = get_latest_release(args.project)
+    tag = f"{args.project}-v{version}"
 
+    # Create and push tag first
+    try:
+        subprocess.run(["git", "tag", tag], check=True)  # noqa: S607
+        subprocess.run(["git", "push", "origin", tag], check=True)  # noqa: 
S607
+        print(f"Created and pushed tag: {tag}")
+    except subprocess.CalledProcessError as e:
+        print(f"Error creating tag: {e}")
+        sys.exit(1)
+
+    # Open GitHub UI to create draft release
     params = urlencode({
         "title": f"{args.project.capitalize()} v{version}",
-        "tag": f"{args.project}-v{version}",
+        "tag": tag,
         "body": notes,
+        "draft": "true",
     })
 
     url = f"https://github.com/pypa/hatch/releases/new?{params}";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/src/hatch/cli/shell/__init__.py 
new/hatch-hatch-v1.16.5/src/hatch/cli/shell/__init__.py
--- old/hatch-hatch-v1.16.3/src/hatch/cli/shell/__init__.py     2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/src/hatch/cli/shell/__init__.py     2026-02-27 
18:59:39.000000000 +0100
@@ -1,9 +1,12 @@
 from __future__ import annotations
 
+import os
 from typing import TYPE_CHECKING
 
 import click
 
+from hatch.config.constants import AppEnvVars
+
 if TYPE_CHECKING:
     from hatch.cli.application import Application
 
@@ -42,7 +45,7 @@
 
     with app.project.ensure_cwd():
         environment = app.project.get_environment(chosen_env)
-        app.project.prepare_environment(environment)
+        app.project.prepare_environment(environment, 
keep_env=bool(os.environ.get(AppEnvVars.KEEP_ENV)))
 
         first_run_indicator = app.cache_dir / "shell" / "first_run"
         if not first_run_indicator.is_file():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/src/hatch/env/plugin/interface.py 
new/hatch-hatch-v1.16.5/src/hatch/env/plugin/interface.py
--- old/hatch-hatch-v1.16.3/src/hatch/env/plugin/interface.py   2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/src/hatch/env/plugin/interface.py   2026-02-27 
18:59:39.000000000 +0100
@@ -1238,7 +1238,7 @@
             path_spec = data["path"]
             normalized_path = os.path.normpath(os.path.join(root, path_spec))
             absolute_path = os.path.abspath(normalized_path)
-            shared_prefix = os.path.commonprefix([root, absolute_path])
+            shared_prefix = os.path.commonpath([root, absolute_path])
             relative_path = os.path.relpath(absolute_path, shared_prefix)
 
             # Now we have the necessary information to perform an optimized 
glob search for members
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/src/hatch/env/virtual.py 
new/hatch-hatch-v1.16.5/src/hatch/env/virtual.py
--- old/hatch-hatch-v1.16.3/src/hatch/env/virtual.py    2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/src/hatch/env/virtual.py    2026-02-27 
18:59:39.000000000 +0100
@@ -22,7 +22,7 @@
     from collections.abc import Callable, Iterable
 
     from packaging.specifiers import SpecifierSet
-    from virtualenv.discovery.py_info import PythonInfo
+    from python_discovery import PythonInfo
 
     from hatch.dep.core import Dependency
     from hatch.dep.sync import InstalledDistributions
@@ -334,7 +334,7 @@
 
     def _interpreter_is_compatible(self, interpreter: PythonInfo) -> bool:
         return (
-            interpreter.executable
+            interpreter.executable is not None
             and self._is_stable_path(interpreter.executable)
             and (self.skip_install or 
self._python_constraint.contains(interpreter.version_str))
         )
@@ -376,26 +376,12 @@
         return None
 
     def _find_existing_interpreter(self, python_version: str = "") -> str | 
None:
-        from virtualenv.discovery import builtin as virtualenv_discovery
+        import python_discovery
 
-        propose_interpreters = virtualenv_discovery.propose_interpreters
-
-        def _patched_propose_interpreters(*args, **kwargs):
-            for interpreter, impl_must_match in propose_interpreters(*args, 
**kwargs):
-                if not self._interpreter_is_compatible(interpreter):
-                    continue
-
-                yield interpreter, impl_must_match
-
-        virtualenv_discovery.propose_interpreters = 
_patched_propose_interpreters
-        try:
-            python_info = virtualenv_discovery.get_interpreter(
-                python_version, (), env=self.get_interpreter_resolver_env()
-            )
-            if python_info is not None:
-                return python_info.executable
-        finally:
-            virtualenv_discovery.propose_interpreters = propose_interpreters
+        python_info = python_discovery.get_interpreter(
+            python_version, (), env=self.get_interpreter_resolver_env(), 
predicate=self._interpreter_is_compatible
+        )
+        return None if python_info is None else python_info.executable
 
     def _get_available_distribution(self, python_version: str = "") -> str | 
None:
         from hatch.python.resolve import get_compatible_distributions
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/tests/backend/builders/test_wheel.py 
new/hatch-hatch-v1.16.5/tests/backend/builders/test_wheel.py
--- old/hatch-hatch-v1.16.3/tests/backend/builders/test_wheel.py        
2026-01-21 02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/backend/builders/test_wheel.py        
2026-02-27 18:59:39.000000000 +0100
@@ -786,7 +786,14 @@
             zip_info = zip_archive.getinfo(f"{metadata_directory}/WHEEL")
             assert zip_info.date_time == (2020, 2, 2, 0, 0, 0)
 
-    def test_default_reproducible_timestamp(self, hatch, helpers, temp_dir, 
config_file):
+    @pytest.mark.parametrize(
+        ("epoch", "expected_date_time"),
+        [
+            ("0", (1980, 1, 1, 0, 0, 0)),
+            ("1580601700", (2020, 2, 2, 0, 1, 40)),
+        ],
+    )
+    def test_default_reproducible_timestamp(self, hatch, helpers, temp_dir, 
config_file, epoch, expected_date_time):
         config_file.model.template.plugins["default"]["src-layout"] = False
         config_file.save()
 
@@ -812,7 +819,7 @@
         build_path = project_path / "dist"
         build_path.mkdir()
 
-        with project_path.as_cwd(env_vars={"SOURCE_DATE_EPOCH": "1580601700"}):
+        with project_path.as_cwd(env_vars={"SOURCE_DATE_EPOCH": epoch}):
             artifacts = list(builder.build(directory=str(build_path)))
 
         assert len(artifacts) == 1
@@ -837,7 +844,7 @@
 
         with zipfile.ZipFile(str(expected_artifact), "r") as zip_archive:
             zip_info = zip_archive.getinfo(f"{metadata_directory}/WHEEL")
-            assert zip_info.date_time == (2020, 2, 2, 0, 1, 40)
+            assert zip_info.date_time == expected_date_time
 
     def test_default_no_reproducible(self, hatch, helpers, temp_dir, 
config_file):
         config_file.model.template.plugins["default"]["src-layout"] = False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/tests/backend/metadata/test_core.py 
new/hatch-hatch-v1.16.5/tests/backend/metadata/test_core.py
--- old/hatch-hatch-v1.16.3/tests/backend/metadata/test_core.py 2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/backend/metadata/test_core.py 2026-02-27 
18:59:39.000000000 +0100
@@ -1163,7 +1163,7 @@
             },
         )
 
-        assert metadata.core.dependencies == ["proj@ 
git+https://github.com/org/proj.git@v1";]
+        assert metadata.core.dependencies == ["proj @ 
git+https://github.com/org/proj.git@v1";]
 
     def test_context_formatting(self, isolation, uri_slash_prefix):
         metadata = ProjectMetadata(
@@ -1176,7 +1176,7 @@
         )
 
         normalized_path = str(isolation).replace("\\", "/")
-        assert metadata.core.dependencies == [f"proj@ 
file:{uri_slash_prefix}{normalized_path}"]
+        assert metadata.core.dependencies == [f"proj @ 
file:{uri_slash_prefix}{normalized_path}"]
 
     def test_correct(self, isolation):
         metadata = ProjectMetadata(
@@ -1343,7 +1343,7 @@
         )
 
         normalized_path = str(isolation).replace("\\", "/")
-        assert metadata.core.optional_dependencies == {"foo": [f"proj@ 
file:{uri_slash_prefix}{normalized_path}"]}
+        assert metadata.core.optional_dependencies == {"foo": [f"proj @ 
file:{uri_slash_prefix}{normalized_path}"]}
 
     def test_direct_reference_allowed(self, isolation):
         metadata = ProjectMetadata(
@@ -1358,7 +1358,7 @@
             },
         )
 
-        assert metadata.core.optional_dependencies == {"foo": ["proj@ 
git+https://github.com/org/proj.git@v1"]}
+        assert metadata.core.optional_dependencies == {"foo": ["proj @ 
git+https://github.com/org/proj.git@v1"]}
 
     def test_correct(self, isolation):
         metadata = ProjectMetadata(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/tests/backend/metadata/test_spec.py 
new/hatch-hatch-v1.16.5/tests/backend/metadata/test_spec.py
--- old/hatch-hatch-v1.16.3/tests/backend/metadata/test_spec.py 2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/backend/metadata/test_spec.py 2026-02-27 
18:59:39.000000000 +0100
@@ -216,7 +216,7 @@
 Requires-Dist: bar==5; extra == 'feature2'
 Requires-Dist: foo==1; (python_version < '3') and extra == 'feature2'
 Provides-Extra: feature3
-Requires-Dist: baz@ file:///path/to/project ; extra == 'feature3'
+Requires-Dist: baz @ file:///path/to/project ; extra == 'feature3'
 """
         assert project_metadata_from_core_metadata(core_metadata) == {
             "name": "My.App",
@@ -225,7 +225,7 @@
             "optional-dependencies": {
                 "feature1": ['bar==5; python_version < "3"', "foo==1"],
                 "feature2": ["bar==5", 'foo==1; python_version < "3"'],
-                "feature3": ["baz@ file:///path/to/project"],
+                "feature3": ["baz @ file:///path/to/project"],
             },
         }
 
@@ -990,7 +990,7 @@
             Requires-Dist: bar==5; extra == 'feature2'
             Requires-Dist: foo==1; (python_version < '3') and extra == 
'feature2'
             Provides-Extra: feature3
-            Requires-Dist: baz@ file:///path/to/project ; extra == 'feature3'
+            Requires-Dist: baz @ file:///path/to/project ; extra == 'feature3'
             Description-Content-Type: text/markdown
 
             test content
@@ -1459,7 +1459,7 @@
             Requires-Dist: bar==5; extra == 'feature2'
             Requires-Dist: foo==1; (python_version < '3') and extra == 
'feature2'
             Provides-Extra: feature3
-            Requires-Dist: baz@ file:///path/to/project ; extra == 'feature3'
+            Requires-Dist: baz @ file:///path/to/project ; extra == 'feature3'
             Description-Content-Type: text/markdown
 
             test content
@@ -1898,7 +1898,7 @@
             Requires-Dist: bar==5; extra == 'feature2'
             Requires-Dist: foo==1; (python_version < '3') and extra == 
'feature2'
             Provides-Extra: feature3
-            Requires-Dist: baz@ file:///path/to/project ; extra == 'feature3'
+            Requires-Dist: baz @ file:///path/to/project ; extra == 'feature3'
             Description-Content-Type: text/markdown
 
             test content
@@ -2364,7 +2364,7 @@
             Requires-Dist: bar==5; extra == 'feature2'
             Requires-Dist: foo==1; (python_version < '3') and extra == 
'feature2'
             Provides-Extra: feature3
-            Requires-Dist: baz@ file:///path/to/project ; extra == 'feature3'
+            Requires-Dist: baz @ file:///path/to/project ; extra == 'feature3'
             Description-Content-Type: text/markdown
 
             test content
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/tests/cli/dep/show/test_table.py 
new/hatch-hatch-v1.16.5/tests/cli/dep/show/test_table.py
--- old/hatch-hatch-v1.16.3/tests/cli/dep/show/test_table.py    2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/cli/dep/show/test_table.py    2026-02-27 
18:59:39.000000000 +0100
@@ -69,7 +69,7 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-            Project
+        Project
         +-------------+
         | Name        |
         +=============+
@@ -103,7 +103,7 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-         Env: default
+        Env: default
         +-------------+
         | Name        |
         +=============+
@@ -140,13 +140,13 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-            Project
+        Project
         +-------------+
         | Name        |
         +=============+
         | foo-bar-baz |
         +-------------+
-         Env: default
+        Env: default
         +-------------+
         | Name        |
         +=============+
@@ -196,7 +196,7 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-                                      Project
+        Project
         +-----------------+----------+------------------------+------------+
         | Name            | Versions | Markers                | Features   |
         +=================+==========+========================+============+
@@ -204,7 +204,7 @@
         | foo             |          | python_version < '3.8' |            |
         | python-dateutil |          |                        |            |
         +-----------------+----------+------------------------+------------+
-                                                    Env: default
+        Env: default
         
+---------+----------------------------------------+----------+------------------------+------------+
         | Name    | URL                                    | Versions | 
Markers                | Features   |
         
+=========+========================================+==========+========================+============+
@@ -252,7 +252,7 @@
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
         Syncing environment plugin requirements
-            Project
+        Project
         +-------------+
         | Name        |
         +=============+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/tests/cli/env/test_show.py 
new/hatch-hatch-v1.16.5/tests/cli/env/test_show.py
--- old/hatch-hatch-v1.16.3/tests/cli/env/test_show.py  2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/cli/env/test_show.py  2026-02-27 
18:59:39.000000000 +0100
@@ -36,7 +36,7 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-             Standalone
+        Standalone
         +---------+---------+
         | Name    | Type    |
         +=========+=========+
@@ -107,7 +107,7 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-             Standalone
+        Standalone
         +---------+---------+
         | Name    | Type    |
         +=========+=========+
@@ -145,13 +145,13 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-             Standalone
+        Standalone
         +---------+---------+
         | Name    | Type    |
         +=========+=========+
         | default | virtual |
         +---------+---------+
-                     Matrices
+        Matrices
         +------+---------+----------------+
         | Name | Type    | Envs           |
         +======+=========+================+
@@ -190,7 +190,7 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-                     Matrices
+        Matrices
         +---------+---------+------------+
         | Name    | Type    | Envs       |
         +=========+=========+============+
@@ -231,13 +231,13 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-            Standalone
+        Standalone
         +------+---------+
         | Name | Type    |
         +======+=========+
         | bar  | virtual |
         +------+---------+
-                       Matrices
+        Matrices
         +---------+---------+----------------+
         | Name    | Type    | Envs           |
         +=========+=========+================+
@@ -280,7 +280,7 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-            Standalone
+        Standalone
         +------+---------+
         | Name | Type    |
         +======+=========+
@@ -377,7 +377,7 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-                                                                               
                        Standalone
+        Standalone
         
+------+---------+----------+-----------------------------+-----------------------+---------+----------------------------------------------------------------------------------------------------------+
         | Name | Type    | Features | Dependencies                | 
Environment variables | Scripts | Description                                   
                                                           |
         
+======+=========+==========+=============================+=======================+=========+==========================================================================================================+
@@ -387,7 +387,7 @@
         |      |         |          |                             |            
           |         | fugiat nulla pariatur. Excepteur sint occaecat cupidatat 
non proident, sunt in culpa qui officia         |
         |      |         |          |                             |            
           |         | deserunt mollit anim id est laborum.                     
                                                |
         
+------+---------+----------+-----------------------------+-----------------------+---------+----------------------------------------------------------------------------------------------------------+
-                                                                               
                         Matrices
+        Matrices
         
+---------+---------+------------+----------+-----------------------------+-----------------------+---------+------------------------------------------------------------------------------------------+
         | Name    | Type    | Envs       | Features | Dependencies             
   | Environment variables | Scripts | Description                              
                                                |
         
+=========+=========+============+==========+=============================+=======================+=========+==========================================================================================+
@@ -425,7 +425,7 @@
         "default",
         {
             "matrix": [{"version": ["9000", "3.14"], "py": ["39", "310"]}],
-            "dependencies": ["foo @ {root:uri}/../foo"],
+            "dependencies": ["foo@ {root:uri}/../foo"],
         },
     )
 
@@ -445,21 +445,21 @@
     assert result.exit_code == 0, result.output
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
-                               Standalone
+        Standalone
         +------+---------+--------------+-----------------------+
         | Name | Type    | Dependencies | Environment variables |
         +======+=========+==============+=======================+
         | foo  | virtual | pydantic     | BAR=FOO_BAR           |
         +------+---------+--------------+-----------------------+
-                                 Matrices
-        +---------+---------+------------+------------------------+
-        | Name    | Type    | Envs       | Dependencies           |
-        +=========+=========+============+========================+
-        | default | virtual | py39-9000  | foo@ {root:uri}/../foo |
-        |         |         | py39-3.14  |                        |
-        |         |         | py310-9000 |                        |
-        |         |         | py310-3.14 |                        |
-        +---------+---------+------------+------------------------+
+        Matrices
+        +---------+---------+------------+-------------------------+
+        | Name    | Type    | Envs       | Dependencies            |
+        +=========+=========+============+=========================+
+        | default | virtual | py39-9000  | foo @ {root:uri}/../foo |
+        |         |         | py39-3.14  |                         |
+        |         |         | py310-9000 |                         |
+        |         |         | py310-3.14 |                         |
+        +---------+---------+------------+-------------------------+
         """
     )
 
@@ -496,7 +496,7 @@
     assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
         """
         Syncing environment plugin requirements
-             Standalone
+        Standalone
         +---------+---------+
         | Name    | Type    |
         +=========+=========+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/tests/cli/python/test_show.py 
new/hatch-hatch-v1.16.5/tests/cli/python/test_show.py
--- old/hatch-hatch-v1.16.3/tests/cli/python/test_show.py       2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/cli/python/test_show.py       2026-02-27 
18:59:39.000000000 +0100
@@ -16,7 +16,7 @@
         table.add_row(*row)
 
     with console.capture() as capture:
-        console.print(table)
+        console.print(table, overflow="ignore", no_wrap=True, crop=False)
 
     return capture.get()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hatch-hatch-v1.16.3/tests/conftest.py 
new/hatch-hatch-v1.16.5/tests/conftest.py
--- old/hatch-hatch-v1.16.3/tests/conftest.py   2026-01-21 02:32:44.000000000 
+0100
+++ new/hatch-hatch-v1.16.5/tests/conftest.py   2026-02-27 18:59:39.000000000 
+0100
@@ -295,17 +295,33 @@
     with FileLock(lock_file):
         if not any(devpi_started_sessions.iterdir()):
             with EnvVars(env_vars):
-                subprocess.check_call(["docker", "compose", "-f", 
compose_file, "up", "--build", "-d"])
+                result = subprocess.run(
+                    ["docker", "compose", "-f", compose_file, "up", "--build", 
"-d", "--wait"],
+                    check=False,
+                    capture_output=True,
+                )
+                if result.returncode != 0:
+                    # Debugging info for if devpi fails to start
+                    logs = subprocess.run(["docker", "logs", "hatch-devpi"], 
check=False, capture_output=True)
+                    pytest.fail(
+                        f"Failed to start devpi container, see 
logs:\n{logs.stdout.decode()}\n{logs.stderr.decode()}"
+                    )
 
-            for _ in range(60):
+            for _ in range(120):
                 output = subprocess.check_output(["docker", "logs", 
"hatch-devpi"]).decode("utf-8")
                 if f"Serving index {dp.user}/{dp.index_name}" in output:
-                    time.sleep(5)
+                    time.sleep(15)
                     break
 
                 time.sleep(1)
             else:  # no cov
-                pass
+                # Add logging here too for timeout case
+                import warnings
+
+                logs = subprocess.run(["docker", "logs", "hatch-devpi"], 
check=False, capture_output=True)
+                warnings.warn(
+                    f"devpi container logs 
(timeout):\n{logs.stdout.decode()}\n{logs.stderr.decode()}", stacklevel=1
+                )
 
         (devpi_started_sessions / worker_id).touch()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/tests/env/plugin/test_interface.py 
new/hatch-hatch-v1.16.5/tests/env/plugin/test_interface.py
--- old/hatch-hatch-v1.16.3/tests/env/plugin/test_interface.py  2026-01-21 
02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/env/plugin/test_interface.py  2026-02-27 
18:59:39.000000000 +0100
@@ -1194,7 +1194,7 @@
         )
 
         normalized_path = str(isolation).replace("\\", "/")
-        assert environment.dependencies == ["dep2", f"proj@ 
file:{uri_slash_prefix}{normalized_path}", "dep1"]
+        assert environment.dependencies == ["dep2", f"proj @ 
file:{uri_slash_prefix}{normalized_path}", "dep1"]
 
     def test_project_dependencies_context_formatting(
         self, temp_dir, isolated_data_dir, platform, temp_application, 
uri_slash_prefix
@@ -1244,7 +1244,7 @@
         )
 
         normalized_parent_path = str(temp_dir.parent).replace("\\", "/")
-        expected_dep = f"sibling-project@ 
file:{uri_slash_prefix}{normalized_parent_path}/sibling-project"
+        expected_dep = f"sibling-project @ 
file:{uri_slash_prefix}{normalized_parent_path}/sibling-project"
 
         # Verify the dependency was formatted correctly
         assert expected_dep in environment.dependencies
@@ -3221,6 +3221,59 @@
         assert members[1].project.location == member2_path
         assert members[2].project.location == member3_path
 
+    def test_member_outside_root_with_shared_prefix(self, temp_dir, 
isolated_data_dir, platform, global_application):
+        """Verify correct workspace member discovery with shared path prefix.
+
+        os.path.commonprefix works character-by-character, so for paths that
+        share a partial directory name (e.g. 'local_app' and 'lib_member' both
+        start with 'l'), it would return an invalid path like '.../l' instead
+        of the true common ancestor directory. os.path.commonpath correctly
+        returns the nearest common directory, which is what we need as the
+        base for the member glob search.
+
+        Example of the mismatch:
+            os.path.commonprefix(['/usr/lib', '/usr/local/lib']) == '/usr/l'
+            os.path.commonpath(['/usr/lib', '/usr/local/lib'])   == '/usr'
+        """
+        project_root = temp_dir / "local_app"
+        project_root.mkdir()
+
+        member_path = temp_dir / "lib_member"
+        member_path.mkdir()
+        (member_path / "pyproject.toml").write_text(
+            """\
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[project]
+name = "lib-member"
+version = "0.1.0"
+"""
+        )
+
+        config = {
+            "project": {"name": "my_app", "version": "0.0.1"},
+            "tool": {"hatch": {"envs": {"default": {"workspace": {"members": 
[{"path": "../lib_member"}]}}}}},
+        }
+        project = Project(project_root, config=config)
+        environment = MockEnvironment(
+            project_root,
+            project.metadata,
+            "default",
+            project.config.envs["default"],
+            {},
+            isolated_data_dir,
+            isolated_data_dir,
+            platform,
+            0,
+            global_application,
+        )
+
+        members = environment.workspace.members
+        assert len(members) == 1
+        assert members[0].project.location == member_path
+
 
 class TestWorkspaceDependencies:
     def test_basic(self, temp_dir, isolated_data_dir, platform, 
global_application):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/tests/helpers/templates/licenses/__init__.py 
new/hatch-hatch-v1.16.5/tests/helpers/templates/licenses/__init__.py
--- old/hatch-hatch-v1.16.3/tests/helpers/templates/licenses/__init__.py        
2026-01-21 02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/helpers/templates/licenses/__init__.py        
2026-02-27 18:59:39.000000000 +0100
@@ -194,9 +194,18 @@
 
 Copyright (c) <year> <copyright holders>
 
-Permission is hereby granted, free of charge, to any person obtaining a copy 
of this software and associated documentation files (the "Software"), to deal 
in the Software without restriction, including without limitation the rights to 
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
of the Software, and to permit persons to whom the Software is furnished to do 
so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy 
of this software and
+associated documentation files (the "Software"), to deal in the Software 
without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, 
distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is 
furnished to do so, subject to the
+following conditions:
 
-The above copyright notice and this permission notice shall be included in all 
copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all 
copies or substantial
+portions of the Software.
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 
AND NONINFRINGEMENT. IN NO
+EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 
OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
 """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/tests/index/server/devpi/entrypoint.sh 
new/hatch-hatch-v1.16.5/tests/index/server/devpi/entrypoint.sh
--- old/hatch-hatch-v1.16.3/tests/index/server/devpi/entrypoint.sh      
2026-01-21 02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/index/server/devpi/entrypoint.sh      
2026-02-27 18:59:39.000000000 +0100
@@ -10,7 +10,17 @@
 devpi-server --host 0.0.0.0 --port 3141 &
 
 echo "==:> Waiting on server"
-sleep 5
+for i in $(seq 1 30); do
+    if devpi use http://localhost:3141 2>/dev/null; then
+        break
+    fi
+    if [ "$i" -eq 30 ]; then
+        echo "Timed out waiting for devpi-server"
+        exit 1
+    fi
+    sleep 1
+done
+
 
 echo "==:> Setting up index"
 devpi use http://localhost:3141
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hatch-hatch-v1.16.3/tests/index/server/docker-compose.yaml 
new/hatch-hatch-v1.16.5/tests/index/server/docker-compose.yaml
--- old/hatch-hatch-v1.16.3/tests/index/server/docker-compose.yaml      
2026-01-21 02:32:44.000000000 +0100
+++ new/hatch-hatch-v1.16.5/tests/index/server/docker-compose.yaml      
2026-02-27 18:59:39.000000000 +0100
@@ -9,6 +9,12 @@
     - DEVPI_INDEX_NAME
     - DEVPI_USERNAME
     - DEVPI_PASSWORD
+    healthcheck:
+      test: [ "CMD", "python", "-c", "import urllib.request; 
urllib.request.urlopen('http://localhost:3141')" ]
+      interval: 2s
+      timeout: 5s
+      retries: 30
+      start_period: 10s
 
   nginx:
     container_name: hatch-nginx
@@ -19,4 +25,5 @@
     volumes:
     - ./nginx:/etc/nginx
     depends_on:
-    - devpi
+      devpi:
+        condition: service_healthy
\ No newline at end of file

Reply via email to