Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-hatchling for
openSUSE:Factory checked in at 2026-06-04 18:52:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-hatchling (Old)
and /work/SRC/openSUSE:Factory/.python-hatchling.new.2375 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-hatchling"
Thu Jun 4 18:52:57 2026 rev:35 rq:1357010 version:1.30.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-hatchling/python-hatchling.changes
2026-03-01 22:13:47.623420746 +0100
+++
/work/SRC/openSUSE:Factory/.python-hatchling.new.2375/python-hatchling.changes
2026-06-04 18:53:50.895718639 +0200
@@ -1,0 +2,11 @@
+Tue Jun 2 19:18:51 UTC 2026 - BenoƮt Monin <[email protected]>
+
+- update to version 1.30.1:
+ * Fixed: Default core metadata version kept at 2.4 until more
+ tools support 2.5
+- additional changes from version 1.30.0:
+ * Added: Support PEP 794 (core metadata Import-Name and
+ Import-Namespace fields and version 2.5)
+ * Fixed: Exclude Git worktree metadata files from sdists
+
+-------------------------------------------------------------------
Old:
----
hatchling-1.29.0.tar.gz
New:
----
hatchling-1.30.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-hatchling.spec ++++++
--- /var/tmp/diff_new_pack.Xgkle2/_old 2026-06-04 18:53:52.563787443 +0200
+++ /var/tmp/diff_new_pack.Xgkle2/_new 2026-06-04 18:53:52.567787608 +0200
@@ -24,7 +24,7 @@
%{?pythons_for_pypi}
%{?sle15_python_module_pythons}
Name: python-hatchling
-Version: 1.29.0
+Version: 1.30.1
Release: 0
Summary: Build backend used by Hatch
License: MIT
++++++ hatchling-1.29.0.tar.gz -> hatchling-1.30.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hatchling-1.29.0/PKG-INFO
new/hatchling-1.30.1/PKG-INFO
--- old/hatchling-1.29.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
+++ new/hatchling-1.30.1/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: hatchling
-Version: 1.29.0
+Version: 1.30.1
Summary: Modern, extensible Python build backend
Project-URL: Homepage, https://hatch.pypa.io/latest/
Project-URL: Sponsor, https://github.com/sponsors/ofek
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hatchling-1.29.0/src/hatchling/__about__.py
new/hatchling-1.30.1/src/hatchling/__about__.py
--- old/hatchling-1.29.0/src/hatchling/__about__.py 2020-02-02
01:00:00.000000000 +0100
+++ new/hatchling-1.30.1/src/hatchling/__about__.py 2020-02-02
01:00:00.000000000 +0100
@@ -1 +1 @@
-__version__ = "1.29.0"
+__version__ = "1.30.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hatchling-1.29.0/src/hatchling/builders/constants.py
new/hatchling-1.30.1/src/hatchling/builders/constants.py
--- old/hatchling-1.29.0/src/hatchling/builders/constants.py 2020-02-02
01:00:00.000000000 +0100
+++ new/hatchling-1.30.1/src/hatchling/builders/constants.py 2020-02-02
01:00:00.000000000 +0100
@@ -27,6 +27,8 @@
EXCLUDED_FILES = frozenset((
# https://en.wikipedia.org/wiki/.DS_Store
".DS_Store",
+ # Git worktree metadata file
+ ".git",
))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hatchling-1.29.0/src/hatchling/builders/wheel.py
new/hatchling-1.30.1/src/hatchling/builders/wheel.py
--- old/hatchling-1.29.0/src/hatchling/builders/wheel.py 2020-02-02
01:00:00.000000000 +0100
+++ new/hatchling-1.30.1/src/hatchling/builders/wheel.py 2020-02-02
01:00:00.000000000 +0100
@@ -65,6 +65,21 @@
self.__file_obj.close()
+class _WheelZipFile(zipfile.ZipFile):
+ def open(self, name, mode="r", pwd=None, *, force_zip64=False):
+ filename = name.filename if isinstance(name, zipfile.ZipInfo) else name
+ if mode == "w" and filename in self.NameToInfo:
+ message = (
+ f"A second file is being added to the wheel archive at the
same path: `{filename}`.\n\n"
+ f"The most likely cause of this is an entry in the "
+ f"`tool.hatch.build.targets.wheel.force-include` table. See: "
+ f"https://hatch.pypa.io/1.8/config/build/#forced-inclusion\n\n"
+ )
+ raise ValueError(message)
+
+ return super().open(name, mode, pwd, force_zip64=force_zip64)
+
+
class WheelArchive:
def __init__(self, project_id: str, *, reproducible: bool) -> None:
"""
@@ -82,7 +97,7 @@
raw_fd, self.path = tempfile.mkstemp(suffix=".whl")
self.fd = os.fdopen(raw_fd, "w+b")
- self.zf = zipfile.ZipFile(self.fd, "w",
compression=zipfile.ZIP_DEFLATED)
+ self.zf = _WheelZipFile(self.fd, "w", compression=zipfile.ZIP_DEFLATED)
@staticmethod
def get_reproducible_time_tuple() -> TIME_TUPLE:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hatchling-1.29.0/src/hatchling/metadata/core.py
new/hatchling-1.30.1/src/hatchling/metadata/core.py
--- old/hatchling-1.29.0/src/hatchling/metadata/core.py 2020-02-02
01:00:00.000000000 +0100
+++ new/hatchling-1.30.1/src/hatchling/metadata/core.py 2020-02-02
01:00:00.000000000 +0100
@@ -389,6 +389,8 @@
self._optional_dependencies_complex: dict[str, dict[str, Requirement]]
| None = None
self._optional_dependencies: dict[str, list[str]] | None = None
self._dynamic: list[str] | None = None
+ self._import_names: list[str] | None = None
+ self._import_namespaces: list[str] | None = None
# Indicates that the version has been successfully set dynamically
self._version_set: bool = False
@@ -1338,6 +1340,75 @@
return self._optional_dependencies
@property
+ def import_names(self) -> list[str] | None:
+ """
+ https://peps.python.org/pep-0794/
+ """
+ if self._import_names is None:
+ if "import-names" not in self.config:
+ return None
+
+ import_names = self.config["import-names"]
+ if "import-names" in self.dynamic:
+ message = (
+ "Metadata field `import-names` cannot be both statically
defined and "
+ "listed in field `project.dynamic`"
+ )
+ raise ValueError(message)
+
+ if not isinstance(import_names, list):
+ message = "Field `project.import-names` must be an array"
+ raise TypeError(message)
+
+ for i, import_name in enumerate(import_names, 1):
+ if not isinstance(import_name, str) or not
self.__import_name_is_valid(import_name):
+ message = f"Import name #{i} of field
`project.import-names` must be a valid import name"
+ raise TypeError(message)
+
+ self._import_names = sorted(import_names)
+
+ if set(self._import_names) & set(self.import_namespaces):
+ message = "Fields `project.import-names` and
`project.import-namespaces` cannot contain the same name"
+ raise ValueError(message)
+
+ return self._import_names
+
+ @property
+ def import_namespaces(self) -> list[str]:
+ """
+
https://packaging.python.org/en/latest/specifications/pyproject-toml/#import-namespaces
+ """
+ if self._import_namespaces is None:
+ if "import-namespaces" in self.config:
+ import_namespaces = self.config["import-namespaces"]
+ if "import-namespaces" in self.dynamic:
+ message = (
+ "Metadata field `import-namespaces` cannot be both
statically defined and "
+ "listed in field `project.dynamic`"
+ )
+ raise ValueError(message)
+ else:
+ import_namespaces = []
+
+ if not isinstance(import_namespaces, list):
+ message = "Field `project.import-namespaces` must be an array"
+ raise TypeError(message)
+
+ for i, import_namespace in enumerate(import_namespaces, 1):
+ if not isinstance(import_namespace, str) or not
self.__import_name_is_valid(import_namespace):
+ message = f"Import namespace #{i} of field
`project.import-namespaces` must be a valid import name"
+ raise TypeError(message)
+
+ self._import_namespaces = sorted(import_namespaces)
+
+ import_names = self.import_names
+ if import_names is not None and set(import_names) &
set(self._import_namespaces):
+ message = "Fields `project.import-names` and
`project.import-namespaces` cannot contain the same name"
+ raise ValueError(message)
+
+ return self._import_namespaces
+
+ @property
def dynamic(self) -> list[str]:
"""
https://peps.python.org/pep-0621/#dynamic
@@ -1369,6 +1440,10 @@
def __classifier_is_private(classifier: str) -> bool:
return classifier.lower().startswith("private ::")
+ @staticmethod
+ def __import_name_is_valid(import_name: str) -> bool:
+ return all(module.isidentifier() for module in import_name.split("."))
+
class HatchMetadata(Generic[PluginManagerBound]):
def __init__(self, root: str, config: dict[str, dict[str, Any]],
plugin_manager: PluginManagerBound) -> None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hatchling-1.29.0/src/hatchling/metadata/spec.py
new/hatchling-1.30.1/src/hatchling/metadata/spec.py
--- old/hatchling-1.29.0/src/hatchling/metadata/spec.py 2020-02-02
01:00:00.000000000 +0100
+++ new/hatchling-1.30.1/src/hatchling/metadata/spec.py 2020-02-02
01:00:00.000000000 +0100
@@ -8,7 +8,7 @@
from hatchling.metadata.core import ProjectMetadata
DEFAULT_METADATA_VERSION = "2.4"
-LATEST_METADATA_VERSION = "2.4"
+LATEST_METADATA_VERSION = "2.5"
CORE_METADATA_PROJECT_FIELDS = {
"Author": ("authors",),
"Author-email": ("authors",),
@@ -29,6 +29,8 @@
"Summary": ("description",),
"Project-URL": ("urls",),
"Version": ("version",),
+ "Import-Name": ("import-names",),
+ "Import-Namespace": ("import-namespaces",),
}
PROJECT_CORE_METADATA_FIELDS = {
"authors": ("Author", "Author-email"),
@@ -46,6 +48,8 @@
"description": ("Summary",),
"urls": ("Project-URL",),
"version": ("Version",),
+ "import-names": ("Import-Name",),
+ "import-namespaces": ("Import-Namespace",),
}
@@ -59,6 +63,7 @@
"2.2": construct_metadata_file_2_2,
"2.3": construct_metadata_file_2_3,
"2.4": construct_metadata_file_2_4,
+ "2.5": construct_metadata_file_2_5,
}
@@ -196,6 +201,16 @@
if optional_dependencies:
metadata["optional-dependencies"] = optional_dependencies
+ if (import_names := message.get_all("Import-Name")) is not None:
+ metadata["import-names"] = import_names
+
+ if (import_namespaces := message.get_all("Import-Namespace")) is not None:
+ metadata["import-namespaces"] = import_namespaces
+
+ if set(metadata.get("import-names", [])) &
set(metadata.get("import-namespaces", [])):
+ error_message = "Import-Name and Import-Namespace fields cannot
contain the same name"
+ raise ValueError(error_message)
+
return metadata
@@ -519,6 +534,115 @@
if metadata.core.dynamic:
# Ordered set
+ for field in {
+ core_metadata_field: None
+ for project_field in metadata.core.dynamic
+ for core_metadata_field in
PROJECT_CORE_METADATA_FIELDS.get(project_field, ())
+ }:
+ metadata_file += f"Dynamic: {field}\n"
+
+ if metadata.core.description:
+ metadata_file += f"Summary: {metadata.core.description}\n"
+
+ if metadata.core.urls:
+ for label, url in metadata.core.urls.items():
+ metadata_file += f"Project-URL: {label}, {url}\n"
+
+ authors_data = metadata.core.authors_data
+ if authors_data["name"]:
+ metadata_file += f"Author: {', '.join(authors_data['name'])}\n"
+ if authors_data["email"]:
+ metadata_file += f"Author-email: {', '.join(authors_data['email'])}\n"
+
+ maintainers_data = metadata.core.maintainers_data
+ if maintainers_data["name"]:
+ metadata_file += f"Maintainer: {', '.join(maintainers_data['name'])}\n"
+ if maintainers_data["email"]:
+ metadata_file += f"Maintainer-email: {',
'.join(maintainers_data['email'])}\n"
+
+ if metadata.core.license:
+ license_start = "License: "
+ indent = " " * (len(license_start) - 1)
+ metadata_file += license_start
+
+ for i, line in enumerate(metadata.core.license.splitlines()):
+ if i == 0:
+ metadata_file += f"{line}\n"
+ else:
+ metadata_file += f"{indent}{line}\n"
+
+ if metadata.core.license_expression:
+ metadata_file += f"License-Expression:
{metadata.core.license_expression}\n"
+
+ if metadata.core.license_files:
+ for license_file in metadata.core.license_files:
+ metadata_file += f"License-File: {license_file}\n"
+
+ if metadata.core.keywords:
+ metadata_file += f"Keywords: {','.join(metadata.core.keywords)}\n"
+
+ if metadata.core.classifiers:
+ for classifier in metadata.core.classifiers:
+ metadata_file += f"Classifier: {classifier}\n"
+
+ if metadata.core.requires_python:
+ metadata_file += f"Requires-Python: {metadata.core.requires_python}\n"
+
+ if metadata.core.dependencies:
+ for dependency in metadata.core.dependencies:
+ metadata_file += f"Requires-Dist: {dependency}\n"
+
+ if extra_dependencies:
+ for dependency in extra_dependencies:
+ metadata_file += f"Requires-Dist: {dependency}\n"
+
+ if metadata.core.optional_dependencies:
+ for option, dependencies in
metadata.core.optional_dependencies.items():
+ metadata_file += f"Provides-Extra: {option}\n"
+ for dependency in dependencies:
+ if ";" in dependency:
+ dep_name, dep_env_marker = dependency.split(";",
maxsplit=1)
+ metadata_file += f"Requires-Dist: {dep_name};
({dep_env_marker.strip()}) and extra == {option!r}\n"
+ elif "@ " in dependency:
+ metadata_file += f"Requires-Dist: {dependency} ; extra ==
{option!r}\n"
+ else:
+ metadata_file += f"Requires-Dist: {dependency}; extra ==
{option!r}\n"
+
+ if metadata.core.readme:
+ metadata_file += f"Description-Content-Type:
{metadata.core.readme_content_type}\n"
+ metadata_file += f"\n{metadata.core.readme}"
+
+ return metadata_file
+
+
+def construct_metadata_file_2_5(metadata: ProjectMetadata, extra_dependencies:
tuple[str] | None = None) -> str:
+ """
+ https://peps.python.org/pep-0794/
+ """
+ metadata_file = "Metadata-Version: 2.5\n"
+ metadata_file += f"Name: {metadata.core.raw_name}\n"
+ metadata_file += f"Version: {metadata.version}\n"
+
+ if metadata.core.import_names is not None:
+ if not metadata.core.import_names and not
metadata.core.import_namespaces:
+ # Projects MAY set `import-names` an empty array and not set
`import-namespaces`
+ # at all in a `pyproject.toml` file (e.g. `import-names = []`). To
match this,
+ # projects MAY have an empty `Import-Name` field in their
metadata. This represents
+ # a project with NO import names, public or private (i.e. there
are no Python modules
+ # of any kind in the distribution file).
+ metadata_file += "Import-Name\n"
+
+ for import_name in metadata.core.import_names:
+ _name = f"{import_name}; private" if import_name.startswith("_")
else import_name
+ metadata_file += f"Import-Name: {_name}\n"
+
+ if metadata.core.import_namespaces:
+ for import_namespace in metadata.core.import_namespaces:
+ _name = f"{import_namespace}; private" if
import_namespace.startswith("_") else import_namespace
+ metadata_file += f"Import-Namespace: {_name}\n"
+
+ if metadata.core.dynamic:
+ # Ordered set
for field in {
core_metadata_field: None
for project_field in metadata.core.dynamic
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hatchling-1.29.0/tests/downstream/requirements.txt
new/hatchling-1.30.1/tests/downstream/requirements.txt
--- old/hatchling-1.29.0/tests/downstream/requirements.txt 2020-02-02
01:00:00.000000000 +0100
+++ new/hatchling-1.30.1/tests/downstream/requirements.txt 2020-02-02
01:00:00.000000000 +0100
@@ -2,4 +2,4 @@
packaging
requests
tomli
-virtualenv>=20.13.1
+virtualenv>=21