diff _postprocess-sdist.py @ 397:c033f4072c14

FIX: _postprocess-sdist now works for compressed archives and configuration in pyproject.toml. While there: adjusted the Makefile accordingly.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 16 Feb 2026 15:22:37 +0100
parents c19a21180a8f
children 669dd560f21a
line wrap: on
line diff
--- a/_postprocess-sdist.py	Mon Feb 16 15:16:18 2026 +0100
+++ b/_postprocess-sdist.py	Mon Feb 16 15:22:37 2026 +0100
@@ -1,77 +1,90 @@
 # -*- coding: utf-8 -*-
 # :-
-# SPDX-FileCopyrightText: © 2025 Franz Glasner
+# SPDX-FileCopyrightText: © 2025-2026 Franz Glasner
 # SPDX-License-Identifier: BSD-3-Clause
 # :-
-"""Postprocress a .tar-sdist to include tests/data with symlinks as symlinks.
+"""Postprocress a .tar.gz-sdist to include tests/data with symlinks as symlinks.
 
 Produce an sdist with all the data in :file:`tests/data/`::
 
   rm -rf dist py_cutils.egg-info
-  python setup.py sdist
+  python -m build
   python _postprocess-sdist.py
-  gzip dist/*.tar
 
 """
 
 from __future__ import print_function, absolute_import
 
 try:
-    from configparser import ConfigParser
+    import tomllib
 except ImportError:
-    from ConfigParser import SafeConfigParser as ConfigParser
+    import tomli as tomllib
 import importlib
+import os
 import io
-import os
 import tarfile
+import gzip
 
 
 def main():
-    with io.open("setup.cfg", "rt", encoding="utf-8") as cfgfile:
-        cp = ConfigParser()
-        if hasattr(cp, "read_file"):
-            cp.read_file(cfgfile, "setup.cfg")
+    with open("pyproject.toml", "rb") as cfgfile:
+        cfg = tomllib.load(cfgfile)
+    project_name = cfg["project"]["name"]
+    normalized_project_name = project_name.replace("-", "_")
+    project_version = cfg["project"].get("version")
+    if project_version is None:
+        assert "version" in cfg["project"]["dynamic"]
+        project_version = cfg["tool"]["setuptools"]["dynamic"]["version"]
+        if "attr" in project_version:
+            vermodname, dummy, vermodattr = (project_version["attr"]
+                                             .strip()
+                                             .rpartition('.'))
+            assert dummy is not None and vermodattr is not None
+            vermod = importlib.import_module(vermodname)
+            project_version = getattr(vermod, vermodattr)
         else:
-            cp.readfp(cfgfile, "setup.cfg")
-    project_name = cp.get("metadata", "name")
-    project_version = cp.get("metadata", "version")
-    if project_version.startswith("attr:"):
-        vermodname, dummy, vermodattr = (project_version[5:]
-                                         .strip()
-                                         .rpartition('.'))
-        assert dummy is not None and vermodattr is not None
-        vermod = importlib.import_module(vermodname)
-        project_version = getattr(vermod, vermodattr)
-    elif project_version.startswith("file:"):
-        assert False
+            assert False
+    #
+    # PEP 625 requires that sdists are of the form
+    # <normalized_project_name>-<project_version>.tar.gz
     #
-    # Compressed tar files cannot be modified by Python: make sure the
-    # originally generated archive is uncompressed.
-    #
-    assert cp.get("sdist", "formats") == "tar"
-
-    archive_name = "{}-{}.tar".format(project_name, project_version)
+    archive_name = "{}-{}.tar.gz".format(
+        normalized_project_name, project_version)
+    uncompressed_archive_name = "{}-{}.tar".format(
+        normalized_project_name, project_version)
     archive_path = "dist/" + archive_name
+    uncompressed_archive_path = "dist/" + uncompressed_archive_name
     assert os.path.isfile(archive_path)
+    assert not os.path.isfile(uncompressed_archive_path)
 
     # the directory within the archive
-    archive_path_prefix = "{}-{}".format(project_name, project_version)
+    archive_path_prefix = "{}-{}".format(
+        normalized_project_name, project_version)
 
-    egg_directory = "{}.egg-info".format(project_name.replace("-", "_"))
+    egg_directory = "{}.egg-info".format(normalized_project_name)
     assert os.path.isdir(egg_directory)
     sources_txt_path = "{}/SOURCES.txt".format(egg_directory)
     sources_txt_arcname = "{}/{}/SOURCES.txt".format(
         archive_path_prefix,
         egg_directory)
 
-    with tarfile.TarFile(archive_path, "r") as tf:
+    # Uncompress
+    with gzip.GzipFile(filename=archive_path, mode="rb") as ca:
+        with open(uncompressed_archive_path, "wb") as uca:
+            while True:
+                data = ca.read(64*1024)
+                if not data:
+                    break
+                uca.write(data)
+
+    with tarfile.TarFile(uncompressed_archive_path, "r") as tf:
         sf = tf.extractfile(sources_txt_arcname)
         try:
             sources_txt = sf.read()
         finally:
             sf.close()
 
-    with tarfile.TarFile(archive_path, "a") as tf:
+    with tarfile.TarFile(uncompressed_archive_path, "a") as tf:
         arcname = "{}/tests/data".format(archive_path_prefix)
         try:
             info = tf.getmember(arcname)
@@ -113,6 +126,18 @@
         #
         tf.addfile(sources_info, sf)
 
+    # Compress
+    with open(uncompressed_archive_path, "rb") as uca:
+        with open(archive_path, "wb") as ca:
+            with gzip.GzipFile(filename=uncompressed_archive_name,
+                               fileobj=ca,
+                               mode="wb") as gzfile:
+                while True:
+                    data = uca.read(64*1024)
+                    if not data:
+                        break
+                    gzfile.write(data)
+
 
 def b(buf, encoding="ascii"):
     if isinstance(buf, bytes):