Mercurial > hgrepos > Python > apps > py-cutils
comparison _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 |
comparison
equal
deleted
inserted
replaced
| 396:1afe2758f802 | 397:c033f4072c14 |
|---|---|
| 1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
| 2 # :- | 2 # :- |
| 3 # SPDX-FileCopyrightText: © 2025 Franz Glasner | 3 # SPDX-FileCopyrightText: © 2025-2026 Franz Glasner |
| 4 # SPDX-License-Identifier: BSD-3-Clause | 4 # SPDX-License-Identifier: BSD-3-Clause |
| 5 # :- | 5 # :- |
| 6 """Postprocress a .tar-sdist to include tests/data with symlinks as symlinks. | 6 """Postprocress a .tar.gz-sdist to include tests/data with symlinks as symlinks. |
| 7 | 7 |
| 8 Produce an sdist with all the data in :file:`tests/data/`:: | 8 Produce an sdist with all the data in :file:`tests/data/`:: |
| 9 | 9 |
| 10 rm -rf dist py_cutils.egg-info | 10 rm -rf dist py_cutils.egg-info |
| 11 python setup.py sdist | 11 python -m build |
| 12 python _postprocess-sdist.py | 12 python _postprocess-sdist.py |
| 13 gzip dist/*.tar | |
| 14 | 13 |
| 15 """ | 14 """ |
| 16 | 15 |
| 17 from __future__ import print_function, absolute_import | 16 from __future__ import print_function, absolute_import |
| 18 | 17 |
| 19 try: | 18 try: |
| 20 from configparser import ConfigParser | 19 import tomllib |
| 21 except ImportError: | 20 except ImportError: |
| 22 from ConfigParser import SafeConfigParser as ConfigParser | 21 import tomli as tomllib |
| 23 import importlib | 22 import importlib |
| 23 import os | |
| 24 import io | 24 import io |
| 25 import os | |
| 26 import tarfile | 25 import tarfile |
| 26 import gzip | |
| 27 | 27 |
| 28 | 28 |
| 29 def main(): | 29 def main(): |
| 30 with io.open("setup.cfg", "rt", encoding="utf-8") as cfgfile: | 30 with open("pyproject.toml", "rb") as cfgfile: |
| 31 cp = ConfigParser() | 31 cfg = tomllib.load(cfgfile) |
| 32 if hasattr(cp, "read_file"): | 32 project_name = cfg["project"]["name"] |
| 33 cp.read_file(cfgfile, "setup.cfg") | 33 normalized_project_name = project_name.replace("-", "_") |
| 34 project_version = cfg["project"].get("version") | |
| 35 if project_version is None: | |
| 36 assert "version" in cfg["project"]["dynamic"] | |
| 37 project_version = cfg["tool"]["setuptools"]["dynamic"]["version"] | |
| 38 if "attr" in project_version: | |
| 39 vermodname, dummy, vermodattr = (project_version["attr"] | |
| 40 .strip() | |
| 41 .rpartition('.')) | |
| 42 assert dummy is not None and vermodattr is not None | |
| 43 vermod = importlib.import_module(vermodname) | |
| 44 project_version = getattr(vermod, vermodattr) | |
| 34 else: | 45 else: |
| 35 cp.readfp(cfgfile, "setup.cfg") | 46 assert False |
| 36 project_name = cp.get("metadata", "name") | |
| 37 project_version = cp.get("metadata", "version") | |
| 38 if project_version.startswith("attr:"): | |
| 39 vermodname, dummy, vermodattr = (project_version[5:] | |
| 40 .strip() | |
| 41 .rpartition('.')) | |
| 42 assert dummy is not None and vermodattr is not None | |
| 43 vermod = importlib.import_module(vermodname) | |
| 44 project_version = getattr(vermod, vermodattr) | |
| 45 elif project_version.startswith("file:"): | |
| 46 assert False | |
| 47 # | 47 # |
| 48 # Compressed tar files cannot be modified by Python: make sure the | 48 # PEP 625 requires that sdists are of the form |
| 49 # originally generated archive is uncompressed. | 49 # <normalized_project_name>-<project_version>.tar.gz |
| 50 # | 50 # |
| 51 assert cp.get("sdist", "formats") == "tar" | 51 archive_name = "{}-{}.tar.gz".format( |
| 52 | 52 normalized_project_name, project_version) |
| 53 archive_name = "{}-{}.tar".format(project_name, project_version) | 53 uncompressed_archive_name = "{}-{}.tar".format( |
| 54 normalized_project_name, project_version) | |
| 54 archive_path = "dist/" + archive_name | 55 archive_path = "dist/" + archive_name |
| 56 uncompressed_archive_path = "dist/" + uncompressed_archive_name | |
| 55 assert os.path.isfile(archive_path) | 57 assert os.path.isfile(archive_path) |
| 58 assert not os.path.isfile(uncompressed_archive_path) | |
| 56 | 59 |
| 57 # the directory within the archive | 60 # the directory within the archive |
| 58 archive_path_prefix = "{}-{}".format(project_name, project_version) | 61 archive_path_prefix = "{}-{}".format( |
| 62 normalized_project_name, project_version) | |
| 59 | 63 |
| 60 egg_directory = "{}.egg-info".format(project_name.replace("-", "_")) | 64 egg_directory = "{}.egg-info".format(normalized_project_name) |
| 61 assert os.path.isdir(egg_directory) | 65 assert os.path.isdir(egg_directory) |
| 62 sources_txt_path = "{}/SOURCES.txt".format(egg_directory) | 66 sources_txt_path = "{}/SOURCES.txt".format(egg_directory) |
| 63 sources_txt_arcname = "{}/{}/SOURCES.txt".format( | 67 sources_txt_arcname = "{}/{}/SOURCES.txt".format( |
| 64 archive_path_prefix, | 68 archive_path_prefix, |
| 65 egg_directory) | 69 egg_directory) |
| 66 | 70 |
| 67 with tarfile.TarFile(archive_path, "r") as tf: | 71 # Uncompress |
| 72 with gzip.GzipFile(filename=archive_path, mode="rb") as ca: | |
| 73 with open(uncompressed_archive_path, "wb") as uca: | |
| 74 while True: | |
| 75 data = ca.read(64*1024) | |
| 76 if not data: | |
| 77 break | |
| 78 uca.write(data) | |
| 79 | |
| 80 with tarfile.TarFile(uncompressed_archive_path, "r") as tf: | |
| 68 sf = tf.extractfile(sources_txt_arcname) | 81 sf = tf.extractfile(sources_txt_arcname) |
| 69 try: | 82 try: |
| 70 sources_txt = sf.read() | 83 sources_txt = sf.read() |
| 71 finally: | 84 finally: |
| 72 sf.close() | 85 sf.close() |
| 73 | 86 |
| 74 with tarfile.TarFile(archive_path, "a") as tf: | 87 with tarfile.TarFile(uncompressed_archive_path, "a") as tf: |
| 75 arcname = "{}/tests/data".format(archive_path_prefix) | 88 arcname = "{}/tests/data".format(archive_path_prefix) |
| 76 try: | 89 try: |
| 77 info = tf.getmember(arcname) | 90 info = tf.getmember(arcname) |
| 78 except KeyError: | 91 except KeyError: |
| 79 pass | 92 pass |
| 111 # This adds SOURCES.txt a 2nd time: this effectively overwrites | 124 # This adds SOURCES.txt a 2nd time: this effectively overwrites |
| 112 # the "earlier" one. | 125 # the "earlier" one. |
| 113 # | 126 # |
| 114 tf.addfile(sources_info, sf) | 127 tf.addfile(sources_info, sf) |
| 115 | 128 |
| 129 # Compress | |
| 130 with open(uncompressed_archive_path, "rb") as uca: | |
| 131 with open(archive_path, "wb") as ca: | |
| 132 with gzip.GzipFile(filename=uncompressed_archive_name, | |
| 133 fileobj=ca, | |
| 134 mode="wb") as gzfile: | |
| 135 while True: | |
| 136 data = uca.read(64*1024) | |
| 137 if not data: | |
| 138 break | |
| 139 gzfile.write(data) | |
| 140 | |
| 116 | 141 |
| 117 def b(buf, encoding="ascii"): | 142 def b(buf, encoding="ascii"): |
| 118 if isinstance(buf, bytes): | 143 if isinstance(buf, bytes): |
| 119 return buf | 144 return buf |
| 120 else: | 145 else: |
