aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/setuptools/_distutils/tests
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/setuptools/_distutils/tests')
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/__init__.py42
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/compat/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/compat/py39.py40
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/support.py134
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_archive_util.py353
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist.py47
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist_dumb.py78
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist_rpm.py127
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build.py49
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_clib.py134
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_ext.py628
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_py.py196
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_scripts.py96
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_check.py194
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_clean.py45
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_cmd.py107
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_config_cmd.py87
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_core.py130
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_dir_util.py139
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_dist.py552
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_extension.py117
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_file_util.py95
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_filelist.py336
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install.py245
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_data.py74
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_headers.py33
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_lib.py110
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_scripts.py52
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_log.py12
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_modified.py126
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_sdist.py470
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_spawn.py141
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_sysconfig.py319
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_text_file.py127
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_util.py243
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_version.py80
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_versionpredicate.py0
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/unix_compat.py17
38 files changed, 5775 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/__init__.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/__init__.py
new file mode 100644
index 00000000..5a8ab061
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/__init__.py
@@ -0,0 +1,42 @@
+"""
+Test suite for distutils.
+
+Tests for the command classes in the distutils.command package are
+included in distutils.tests as well, instead of using a separate
+distutils.command.tests package, since command identification is done
+by import rather than matching pre-defined names.
+"""
+
+import shutil
+from collections.abc import Sequence
+
+
+def missing_compiler_executable(cmd_names: Sequence[str] = []): # pragma: no cover
+ """Check if the compiler components used to build the interpreter exist.
+
+ Check for the existence of the compiler executables whose names are listed
+ in 'cmd_names' or all the compiler executables when 'cmd_names' is empty
+ and return the first missing executable or None when none is found
+ missing.
+
+ """
+ from distutils import ccompiler, errors, sysconfig
+
+ compiler = ccompiler.new_compiler()
+ sysconfig.customize_compiler(compiler)
+ if compiler.compiler_type == "msvc":
+ # MSVC has no executables, so check whether initialization succeeds
+ try:
+ compiler.initialize()
+ except errors.DistutilsPlatformError:
+ return "msvc"
+ for name in compiler.executables:
+ if cmd_names and name not in cmd_names:
+ continue
+ cmd = getattr(compiler, name)
+ if cmd_names:
+ assert cmd is not None, f"the '{name}' executable is not configured"
+ elif not cmd:
+ continue
+ if shutil.which(cmd[0]) is None:
+ return cmd[0]
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/compat/__init__.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/compat/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/compat/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/compat/py39.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/compat/py39.py
new file mode 100644
index 00000000..aca3939a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/compat/py39.py
@@ -0,0 +1,40 @@
+import sys
+
+if sys.version_info >= (3, 10):
+ from test.support.import_helper import (
+ CleanImport as CleanImport,
+ )
+ from test.support.import_helper import (
+ DirsOnSysPath as DirsOnSysPath,
+ )
+ from test.support.os_helper import (
+ EnvironmentVarGuard as EnvironmentVarGuard,
+ )
+ from test.support.os_helper import (
+ rmtree as rmtree,
+ )
+ from test.support.os_helper import (
+ skip_unless_symlink as skip_unless_symlink,
+ )
+ from test.support.os_helper import (
+ unlink as unlink,
+ )
+else:
+ from test.support import (
+ CleanImport as CleanImport,
+ )
+ from test.support import (
+ DirsOnSysPath as DirsOnSysPath,
+ )
+ from test.support import (
+ EnvironmentVarGuard as EnvironmentVarGuard,
+ )
+ from test.support import (
+ rmtree as rmtree,
+ )
+ from test.support import (
+ skip_unless_symlink as skip_unless_symlink,
+ )
+ from test.support import (
+ unlink as unlink,
+ )
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/support.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/support.py
new file mode 100644
index 00000000..9cd2b8a9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/support.py
@@ -0,0 +1,134 @@
+"""Support code for distutils test cases."""
+
+import itertools
+import os
+import pathlib
+import shutil
+import sys
+import sysconfig
+import tempfile
+from distutils.core import Distribution
+
+import pytest
+from more_itertools import always_iterable
+
+
+@pytest.mark.usefixtures('distutils_managed_tempdir')
+class TempdirManager:
+ """
+ Mix-in class that handles temporary directories for test cases.
+ """
+
+ def mkdtemp(self):
+ """Create a temporary directory that will be cleaned up.
+
+ Returns the path of the directory.
+ """
+ d = tempfile.mkdtemp()
+ self.tempdirs.append(d)
+ return d
+
+ def write_file(self, path, content='xxx'):
+ """Writes a file in the given path.
+
+ path can be a string or a sequence.
+ """
+ pathlib.Path(*always_iterable(path)).write_text(content, encoding='utf-8')
+
+ def create_dist(self, pkg_name='foo', **kw):
+ """Will generate a test environment.
+
+ This function creates:
+ - a Distribution instance using keywords
+ - a temporary directory with a package structure
+
+ It returns the package directory and the distribution
+ instance.
+ """
+ tmp_dir = self.mkdtemp()
+ pkg_dir = os.path.join(tmp_dir, pkg_name)
+ os.mkdir(pkg_dir)
+ dist = Distribution(attrs=kw)
+
+ return pkg_dir, dist
+
+
+class DummyCommand:
+ """Class to store options for retrieval via set_undefined_options()."""
+
+ def __init__(self, **kwargs):
+ vars(self).update(kwargs)
+
+ def ensure_finalized(self):
+ pass
+
+
+def copy_xxmodule_c(directory):
+ """Helper for tests that need the xxmodule.c source file.
+
+ Example use:
+
+ def test_compile(self):
+ copy_xxmodule_c(self.tmpdir)
+ self.assertIn('xxmodule.c', os.listdir(self.tmpdir))
+
+ If the source file can be found, it will be copied to *directory*. If not,
+ the test will be skipped. Errors during copy are not caught.
+ """
+ shutil.copy(_get_xxmodule_path(), os.path.join(directory, 'xxmodule.c'))
+
+
+def _get_xxmodule_path():
+ source_name = 'xxmodule.c' if sys.version_info > (3, 9) else 'xxmodule-3.8.c'
+ return os.path.join(os.path.dirname(__file__), source_name)
+
+
+def fixup_build_ext(cmd):
+ """Function needed to make build_ext tests pass.
+
+ When Python was built with --enable-shared on Unix, -L. is not enough to
+ find libpython<blah>.so, because regrtest runs in a tempdir, not in the
+ source directory where the .so lives.
+
+ When Python was built with in debug mode on Windows, build_ext commands
+ need their debug attribute set, and it is not done automatically for
+ some reason.
+
+ This function handles both of these things. Example use:
+
+ cmd = build_ext(dist)
+ support.fixup_build_ext(cmd)
+ cmd.ensure_finalized()
+
+ Unlike most other Unix platforms, Mac OS X embeds absolute paths
+ to shared libraries into executables, so the fixup is not needed there.
+ """
+ if os.name == 'nt':
+ cmd.debug = sys.executable.endswith('_d.exe')
+ elif sysconfig.get_config_var('Py_ENABLE_SHARED'):
+ # To further add to the shared builds fun on Unix, we can't just add
+ # library_dirs to the Extension() instance because that doesn't get
+ # plumbed through to the final compiler command.
+ runshared = sysconfig.get_config_var('RUNSHARED')
+ if runshared is None:
+ cmd.library_dirs = ['.']
+ else:
+ if sys.platform == 'darwin':
+ cmd.library_dirs = []
+ else:
+ name, equals, value = runshared.partition('=')
+ cmd.library_dirs = [d for d in value.split(os.pathsep) if d]
+
+
+def combine_markers(cls):
+ """
+ pytest will honor markers as found on the class, but when
+ markers are on multiple subclasses, only one appears. Use
+ this decorator to combine those markers.
+ """
+ cls.pytestmark = [
+ mark
+ for base in itertools.chain([cls], cls.__bases__)
+ for mark in getattr(base, 'pytestmark', [])
+ ]
+ return cls
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_archive_util.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_archive_util.py
new file mode 100644
index 00000000..3e4ed75a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_archive_util.py
@@ -0,0 +1,353 @@
+"""Tests for distutils.archive_util."""
+
+import functools
+import operator
+import os
+import pathlib
+import sys
+import tarfile
+from distutils import archive_util
+from distutils.archive_util import (
+ ARCHIVE_FORMATS,
+ check_archive_formats,
+ make_archive,
+ make_tarball,
+ make_zipfile,
+)
+from distutils.spawn import spawn
+from distutils.tests import support
+from os.path import splitdrive
+
+import path
+import pytest
+from test.support import patch
+
+from .unix_compat import UID_0_SUPPORT, grp, pwd, require_uid_0, require_unix_id
+
+
+def can_fs_encode(filename):
+ """
+ Return True if the filename can be saved in the file system.
+ """
+ if os.path.supports_unicode_filenames:
+ return True
+ try:
+ filename.encode(sys.getfilesystemencoding())
+ except UnicodeEncodeError:
+ return False
+ return True
+
+
+def all_equal(values):
+ return functools.reduce(operator.eq, values)
+
+
+def same_drive(*paths):
+ return all_equal(pathlib.Path(path).drive for path in paths)
+
+
+class ArchiveUtilTestCase(support.TempdirManager):
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_make_tarball(self, name='archive'):
+ # creating something to tar
+ tmpdir = self._create_files()
+ self._make_tarball(tmpdir, name, '.tar.gz')
+ # trying an uncompressed one
+ self._make_tarball(tmpdir, name, '.tar', compress=None)
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_make_tarball_gzip(self):
+ tmpdir = self._create_files()
+ self._make_tarball(tmpdir, 'archive', '.tar.gz', compress='gzip')
+
+ def test_make_tarball_bzip2(self):
+ pytest.importorskip('bz2')
+ tmpdir = self._create_files()
+ self._make_tarball(tmpdir, 'archive', '.tar.bz2', compress='bzip2')
+
+ def test_make_tarball_xz(self):
+ pytest.importorskip('lzma')
+ tmpdir = self._create_files()
+ self._make_tarball(tmpdir, 'archive', '.tar.xz', compress='xz')
+
+ @pytest.mark.skipif("not can_fs_encode('årchiv')")
+ def test_make_tarball_latin1(self):
+ """
+ Mirror test_make_tarball, except filename contains latin characters.
+ """
+ self.test_make_tarball('årchiv') # note this isn't a real word
+
+ @pytest.mark.skipif("not can_fs_encode('のアーカイブ')")
+ def test_make_tarball_extended(self):
+ """
+ Mirror test_make_tarball, except filename contains extended
+ characters outside the latin charset.
+ """
+ self.test_make_tarball('のアーカイブ') # japanese for archive
+
+ def _make_tarball(self, tmpdir, target_name, suffix, **kwargs):
+ tmpdir2 = self.mkdtemp()
+ if same_drive(tmpdir, tmpdir2):
+ pytest.skip("source and target should be on same drive")
+
+ base_name = os.path.join(tmpdir2, target_name)
+
+ # working with relative paths to avoid tar warnings
+ with path.Path(tmpdir):
+ make_tarball(splitdrive(base_name)[1], 'dist', **kwargs)
+
+ # check if the compressed tarball was created
+ tarball = base_name + suffix
+ assert os.path.exists(tarball)
+ assert self._tarinfo(tarball) == self._created_files
+
+ def _tarinfo(self, path):
+ tar = tarfile.open(path)
+ try:
+ names = tar.getnames()
+ names.sort()
+ return names
+ finally:
+ tar.close()
+
+ _zip_created_files = [
+ 'dist/',
+ 'dist/file1',
+ 'dist/file2',
+ 'dist/sub/',
+ 'dist/sub/file3',
+ 'dist/sub2/',
+ ]
+ _created_files = [p.rstrip('/') for p in _zip_created_files]
+
+ def _create_files(self):
+ # creating something to tar
+ tmpdir = self.mkdtemp()
+ dist = os.path.join(tmpdir, 'dist')
+ os.mkdir(dist)
+ self.write_file([dist, 'file1'], 'xxx')
+ self.write_file([dist, 'file2'], 'xxx')
+ os.mkdir(os.path.join(dist, 'sub'))
+ self.write_file([dist, 'sub', 'file3'], 'xxx')
+ os.mkdir(os.path.join(dist, 'sub2'))
+ return tmpdir
+
+ @pytest.mark.usefixtures('needs_zlib')
+ @pytest.mark.skipif("not (shutil.which('tar') and shutil.which('gzip'))")
+ def test_tarfile_vs_tar(self):
+ tmpdir = self._create_files()
+ tmpdir2 = self.mkdtemp()
+ base_name = os.path.join(tmpdir2, 'archive')
+ old_dir = os.getcwd()
+ os.chdir(tmpdir)
+ try:
+ make_tarball(base_name, 'dist')
+ finally:
+ os.chdir(old_dir)
+
+ # check if the compressed tarball was created
+ tarball = base_name + '.tar.gz'
+ assert os.path.exists(tarball)
+
+ # now create another tarball using `tar`
+ tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
+ tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
+ gzip_cmd = ['gzip', '-f', '-9', 'archive2.tar']
+ old_dir = os.getcwd()
+ os.chdir(tmpdir)
+ try:
+ spawn(tar_cmd)
+ spawn(gzip_cmd)
+ finally:
+ os.chdir(old_dir)
+
+ assert os.path.exists(tarball2)
+ # let's compare both tarballs
+ assert self._tarinfo(tarball) == self._created_files
+ assert self._tarinfo(tarball2) == self._created_files
+
+ # trying an uncompressed one
+ base_name = os.path.join(tmpdir2, 'archive')
+ old_dir = os.getcwd()
+ os.chdir(tmpdir)
+ try:
+ make_tarball(base_name, 'dist', compress=None)
+ finally:
+ os.chdir(old_dir)
+ tarball = base_name + '.tar'
+ assert os.path.exists(tarball)
+
+ # now for a dry_run
+ base_name = os.path.join(tmpdir2, 'archive')
+ old_dir = os.getcwd()
+ os.chdir(tmpdir)
+ try:
+ make_tarball(base_name, 'dist', compress=None, dry_run=True)
+ finally:
+ os.chdir(old_dir)
+ tarball = base_name + '.tar'
+ assert os.path.exists(tarball)
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_make_zipfile(self):
+ zipfile = pytest.importorskip('zipfile')
+ # creating something to tar
+ tmpdir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ with path.Path(tmpdir):
+ make_zipfile(base_name, 'dist')
+
+ # check if the compressed tarball was created
+ tarball = base_name + '.zip'
+ assert os.path.exists(tarball)
+ with zipfile.ZipFile(tarball) as zf:
+ assert sorted(zf.namelist()) == self._zip_created_files
+
+ def test_make_zipfile_no_zlib(self):
+ zipfile = pytest.importorskip('zipfile')
+ patch(self, archive_util.zipfile, 'zlib', None) # force zlib ImportError
+
+ called = []
+ zipfile_class = zipfile.ZipFile
+
+ def fake_zipfile(*a, **kw):
+ if kw.get('compression', None) == zipfile.ZIP_STORED:
+ called.append((a, kw))
+ return zipfile_class(*a, **kw)
+
+ patch(self, archive_util.zipfile, 'ZipFile', fake_zipfile)
+
+ # create something to tar and compress
+ tmpdir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ with path.Path(tmpdir):
+ make_zipfile(base_name, 'dist')
+
+ tarball = base_name + '.zip'
+ assert called == [((tarball, "w"), {'compression': zipfile.ZIP_STORED})]
+ assert os.path.exists(tarball)
+ with zipfile.ZipFile(tarball) as zf:
+ assert sorted(zf.namelist()) == self._zip_created_files
+
+ def test_check_archive_formats(self):
+ assert check_archive_formats(['gztar', 'xxx', 'zip']) == 'xxx'
+ assert (
+ check_archive_formats(['gztar', 'bztar', 'xztar', 'ztar', 'tar', 'zip'])
+ is None
+ )
+
+ def test_make_archive(self):
+ tmpdir = self.mkdtemp()
+ base_name = os.path.join(tmpdir, 'archive')
+ with pytest.raises(ValueError):
+ make_archive(base_name, 'xxx')
+
+ def test_make_archive_cwd(self):
+ current_dir = os.getcwd()
+
+ def _breaks(*args, **kw):
+ raise RuntimeError()
+
+ ARCHIVE_FORMATS['xxx'] = (_breaks, [], 'xxx file')
+ try:
+ try:
+ make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
+ except Exception:
+ pass
+ assert os.getcwd() == current_dir
+ finally:
+ ARCHIVE_FORMATS.pop('xxx')
+
+ def test_make_archive_tar(self):
+ base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ res = make_archive(base_name, 'tar', base_dir, 'dist')
+ assert os.path.exists(res)
+ assert os.path.basename(res) == 'archive.tar'
+ assert self._tarinfo(res) == self._created_files
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_make_archive_gztar(self):
+ base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ res = make_archive(base_name, 'gztar', base_dir, 'dist')
+ assert os.path.exists(res)
+ assert os.path.basename(res) == 'archive.tar.gz'
+ assert self._tarinfo(res) == self._created_files
+
+ def test_make_archive_bztar(self):
+ pytest.importorskip('bz2')
+ base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ res = make_archive(base_name, 'bztar', base_dir, 'dist')
+ assert os.path.exists(res)
+ assert os.path.basename(res) == 'archive.tar.bz2'
+ assert self._tarinfo(res) == self._created_files
+
+ def test_make_archive_xztar(self):
+ pytest.importorskip('lzma')
+ base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ res = make_archive(base_name, 'xztar', base_dir, 'dist')
+ assert os.path.exists(res)
+ assert os.path.basename(res) == 'archive.tar.xz'
+ assert self._tarinfo(res) == self._created_files
+
+ def test_make_archive_owner_group(self):
+ # testing make_archive with owner and group, with various combinations
+ # this works even if there's not gid/uid support
+ if UID_0_SUPPORT:
+ group = grp.getgrgid(0)[0]
+ owner = pwd.getpwuid(0)[0]
+ else:
+ group = owner = 'root'
+
+ base_dir = self._create_files()
+ root_dir = self.mkdtemp()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ res = make_archive(
+ base_name, 'zip', root_dir, base_dir, owner=owner, group=group
+ )
+ assert os.path.exists(res)
+
+ res = make_archive(base_name, 'zip', root_dir, base_dir)
+ assert os.path.exists(res)
+
+ res = make_archive(
+ base_name, 'tar', root_dir, base_dir, owner=owner, group=group
+ )
+ assert os.path.exists(res)
+
+ res = make_archive(
+ base_name, 'tar', root_dir, base_dir, owner='kjhkjhkjg', group='oihohoh'
+ )
+ assert os.path.exists(res)
+
+ @pytest.mark.usefixtures('needs_zlib')
+ @require_unix_id
+ @require_uid_0
+ def test_tarfile_root_owner(self):
+ tmpdir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ old_dir = os.getcwd()
+ os.chdir(tmpdir)
+ group = grp.getgrgid(0)[0]
+ owner = pwd.getpwuid(0)[0]
+ try:
+ archive_name = make_tarball(
+ base_name, 'dist', compress=None, owner=owner, group=group
+ )
+ finally:
+ os.chdir(old_dir)
+
+ # check if the compressed tarball was created
+ assert os.path.exists(archive_name)
+
+ # now checks the rights
+ archive = tarfile.open(archive_name)
+ try:
+ for member in archive.getmembers():
+ assert member.uid == 0
+ assert member.gid == 0
+ finally:
+ archive.close()
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist.py
new file mode 100644
index 00000000..d5696fc3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist.py
@@ -0,0 +1,47 @@
+"""Tests for distutils.command.bdist."""
+
+from distutils.command.bdist import bdist
+from distutils.tests import support
+
+
+class TestBuild(support.TempdirManager):
+ def test_formats(self):
+ # let's create a command and make sure
+ # we can set the format
+ dist = self.create_dist()[1]
+ cmd = bdist(dist)
+ cmd.formats = ['gztar']
+ cmd.ensure_finalized()
+ assert cmd.formats == ['gztar']
+
+ # what formats does bdist offer?
+ formats = [
+ 'bztar',
+ 'gztar',
+ 'rpm',
+ 'tar',
+ 'xztar',
+ 'zip',
+ 'ztar',
+ ]
+ found = sorted(cmd.format_commands)
+ assert found == formats
+
+ def test_skip_build(self):
+ # bug #10946: bdist --skip-build should trickle down to subcommands
+ dist = self.create_dist()[1]
+ cmd = bdist(dist)
+ cmd.skip_build = True
+ cmd.ensure_finalized()
+ dist.command_obj['bdist'] = cmd
+
+ names = [
+ 'bdist_dumb',
+ ] # bdist_rpm does not support --skip-build
+
+ for name in names:
+ subcmd = cmd.get_finalized_command(name)
+ if getattr(subcmd, '_unsupported', False):
+ # command is not supported on this build
+ continue
+ assert subcmd.skip_build, f'{name} should take --skip-build from bdist'
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist_dumb.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist_dumb.py
new file mode 100644
index 00000000..1fc51d24
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist_dumb.py
@@ -0,0 +1,78 @@
+"""Tests for distutils.command.bdist_dumb."""
+
+import os
+import sys
+import zipfile
+from distutils.command.bdist_dumb import bdist_dumb
+from distutils.core import Distribution
+from distutils.tests import support
+
+import pytest
+
+SETUP_PY = """\
+from distutils.core import setup
+import foo
+
+setup(name='foo', version='0.1', py_modules=['foo'],
+ url='xxx', author='xxx', author_email='xxx')
+
+"""
+
+
+@support.combine_markers
+@pytest.mark.usefixtures('save_env')
+@pytest.mark.usefixtures('save_argv')
+@pytest.mark.usefixtures('save_cwd')
+class TestBuildDumb(
+ support.TempdirManager,
+):
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_simple_built(self):
+ # let's create a simple package
+ tmp_dir = self.mkdtemp()
+ pkg_dir = os.path.join(tmp_dir, 'foo')
+ os.mkdir(pkg_dir)
+ self.write_file((pkg_dir, 'setup.py'), SETUP_PY)
+ self.write_file((pkg_dir, 'foo.py'), '#')
+ self.write_file((pkg_dir, 'MANIFEST.in'), 'include foo.py')
+ self.write_file((pkg_dir, 'README'), '')
+
+ dist = Distribution({
+ 'name': 'foo',
+ 'version': '0.1',
+ 'py_modules': ['foo'],
+ 'url': 'xxx',
+ 'author': 'xxx',
+ 'author_email': 'xxx',
+ })
+ dist.script_name = 'setup.py'
+ os.chdir(pkg_dir)
+
+ sys.argv = ['setup.py']
+ cmd = bdist_dumb(dist)
+
+ # so the output is the same no matter
+ # what is the platform
+ cmd.format = 'zip'
+
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # see what we have
+ dist_created = os.listdir(os.path.join(pkg_dir, 'dist'))
+ base = f"{dist.get_fullname()}.{cmd.plat_name}.zip"
+
+ assert dist_created == [base]
+
+ # now let's check what we have in the zip file
+ fp = zipfile.ZipFile(os.path.join('dist', base))
+ try:
+ contents = fp.namelist()
+ finally:
+ fp.close()
+
+ contents = sorted(filter(None, map(os.path.basename, contents)))
+ wanted = ['foo-0.1-py{}.{}.egg-info'.format(*sys.version_info[:2]), 'foo.py']
+ if not sys.dont_write_bytecode:
+ wanted.append(f'foo.{sys.implementation.cache_tag}.pyc')
+ assert contents == sorted(wanted)
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist_rpm.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist_rpm.py
new file mode 100644
index 00000000..75051430
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_bdist_rpm.py
@@ -0,0 +1,127 @@
+"""Tests for distutils.command.bdist_rpm."""
+
+import os
+import shutil # noqa: F401
+import sys
+from distutils.command.bdist_rpm import bdist_rpm
+from distutils.core import Distribution
+from distutils.tests import support
+
+import pytest
+from test.support import requires_zlib
+
+SETUP_PY = """\
+from distutils.core import setup
+import foo
+
+setup(name='foo', version='0.1', py_modules=['foo'],
+ url='xxx', author='xxx', author_email='xxx')
+
+"""
+
+
+@pytest.fixture(autouse=True)
+def sys_executable_encodable():
+ try:
+ sys.executable.encode('UTF-8')
+ except UnicodeEncodeError:
+ pytest.skip("sys.executable is not encodable to UTF-8")
+
+
+mac_woes = pytest.mark.skipif(
+ "not sys.platform.startswith('linux')",
+ reason='spurious sdtout/stderr output under macOS',
+)
+
+
+@pytest.mark.usefixtures('save_env')
+@pytest.mark.usefixtures('save_argv')
+@pytest.mark.usefixtures('save_cwd')
+class TestBuildRpm(
+ support.TempdirManager,
+):
+ @mac_woes
+ @requires_zlib()
+ @pytest.mark.skipif("not shutil.which('rpm')")
+ @pytest.mark.skipif("not shutil.which('rpmbuild')")
+ def test_quiet(self):
+ # let's create a package
+ tmp_dir = self.mkdtemp()
+ os.environ['HOME'] = tmp_dir # to confine dir '.rpmdb' creation
+ pkg_dir = os.path.join(tmp_dir, 'foo')
+ os.mkdir(pkg_dir)
+ self.write_file((pkg_dir, 'setup.py'), SETUP_PY)
+ self.write_file((pkg_dir, 'foo.py'), '#')
+ self.write_file((pkg_dir, 'MANIFEST.in'), 'include foo.py')
+ self.write_file((pkg_dir, 'README'), '')
+
+ dist = Distribution({
+ 'name': 'foo',
+ 'version': '0.1',
+ 'py_modules': ['foo'],
+ 'url': 'xxx',
+ 'author': 'xxx',
+ 'author_email': 'xxx',
+ })
+ dist.script_name = 'setup.py'
+ os.chdir(pkg_dir)
+
+ sys.argv = ['setup.py']
+ cmd = bdist_rpm(dist)
+ cmd.fix_python = True
+
+ # running in quiet mode
+ cmd.quiet = True
+ cmd.ensure_finalized()
+ cmd.run()
+
+ dist_created = os.listdir(os.path.join(pkg_dir, 'dist'))
+ assert 'foo-0.1-1.noarch.rpm' in dist_created
+
+ # bug #2945: upload ignores bdist_rpm files
+ assert ('bdist_rpm', 'any', 'dist/foo-0.1-1.src.rpm') in dist.dist_files
+ assert ('bdist_rpm', 'any', 'dist/foo-0.1-1.noarch.rpm') in dist.dist_files
+
+ @mac_woes
+ @requires_zlib()
+ # https://bugs.python.org/issue1533164
+ @pytest.mark.skipif("not shutil.which('rpm')")
+ @pytest.mark.skipif("not shutil.which('rpmbuild')")
+ def test_no_optimize_flag(self):
+ # let's create a package that breaks bdist_rpm
+ tmp_dir = self.mkdtemp()
+ os.environ['HOME'] = tmp_dir # to confine dir '.rpmdb' creation
+ pkg_dir = os.path.join(tmp_dir, 'foo')
+ os.mkdir(pkg_dir)
+ self.write_file((pkg_dir, 'setup.py'), SETUP_PY)
+ self.write_file((pkg_dir, 'foo.py'), '#')
+ self.write_file((pkg_dir, 'MANIFEST.in'), 'include foo.py')
+ self.write_file((pkg_dir, 'README'), '')
+
+ dist = Distribution({
+ 'name': 'foo',
+ 'version': '0.1',
+ 'py_modules': ['foo'],
+ 'url': 'xxx',
+ 'author': 'xxx',
+ 'author_email': 'xxx',
+ })
+ dist.script_name = 'setup.py'
+ os.chdir(pkg_dir)
+
+ sys.argv = ['setup.py']
+ cmd = bdist_rpm(dist)
+ cmd.fix_python = True
+
+ cmd.quiet = True
+ cmd.ensure_finalized()
+ cmd.run()
+
+ dist_created = os.listdir(os.path.join(pkg_dir, 'dist'))
+ assert 'foo-0.1-1.noarch.rpm' in dist_created
+
+ # bug #2945: upload ignores bdist_rpm files
+ assert ('bdist_rpm', 'any', 'dist/foo-0.1-1.src.rpm') in dist.dist_files
+ assert ('bdist_rpm', 'any', 'dist/foo-0.1-1.noarch.rpm') in dist.dist_files
+
+ os.remove(os.path.join(pkg_dir, 'dist', 'foo-0.1-1.noarch.rpm'))
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build.py
new file mode 100644
index 00000000..f7fe69ac
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build.py
@@ -0,0 +1,49 @@
+"""Tests for distutils.command.build."""
+
+import os
+import sys
+from distutils.command.build import build
+from distutils.tests import support
+from sysconfig import get_config_var, get_platform
+
+
+class TestBuild(support.TempdirManager):
+ def test_finalize_options(self):
+ pkg_dir, dist = self.create_dist()
+ cmd = build(dist)
+ cmd.finalize_options()
+
+ # if not specified, plat_name gets the current platform
+ assert cmd.plat_name == get_platform()
+
+ # build_purelib is build + lib
+ wanted = os.path.join(cmd.build_base, 'lib')
+ assert cmd.build_purelib == wanted
+
+ # build_platlib is 'build/lib.platform-cache_tag[-pydebug]'
+ # examples:
+ # build/lib.macosx-10.3-i386-cpython39
+ plat_spec = f'.{cmd.plat_name}-{sys.implementation.cache_tag}'
+ if get_config_var('Py_GIL_DISABLED'):
+ plat_spec += 't'
+ if hasattr(sys, 'gettotalrefcount'):
+ assert cmd.build_platlib.endswith('-pydebug')
+ plat_spec += '-pydebug'
+ wanted = os.path.join(cmd.build_base, 'lib' + plat_spec)
+ assert cmd.build_platlib == wanted
+
+ # by default, build_lib = build_purelib
+ assert cmd.build_lib == cmd.build_purelib
+
+ # build_temp is build/temp.<plat>
+ wanted = os.path.join(cmd.build_base, 'temp' + plat_spec)
+ assert cmd.build_temp == wanted
+
+ # build_scripts is build/scripts-x.x
+ wanted = os.path.join(
+ cmd.build_base, f'scripts-{sys.version_info.major}.{sys.version_info.minor}'
+ )
+ assert cmd.build_scripts == wanted
+
+ # executable is os.path.normpath(sys.executable)
+ assert cmd.executable == os.path.normpath(sys.executable)
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_clib.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_clib.py
new file mode 100644
index 00000000..f76f26bc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_clib.py
@@ -0,0 +1,134 @@
+"""Tests for distutils.command.build_clib."""
+
+import os
+from distutils.command.build_clib import build_clib
+from distutils.errors import DistutilsSetupError
+from distutils.tests import missing_compiler_executable, support
+
+import pytest
+
+
+class TestBuildCLib(support.TempdirManager):
+ def test_check_library_dist(self):
+ pkg_dir, dist = self.create_dist()
+ cmd = build_clib(dist)
+
+ # 'libraries' option must be a list
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_library_list('foo')
+
+ # each element of 'libraries' must a 2-tuple
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_library_list(['foo1', 'foo2'])
+
+ # first element of each tuple in 'libraries'
+ # must be a string (the library name)
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_library_list([(1, 'foo1'), ('name', 'foo2')])
+
+ # library name may not contain directory separators
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_library_list(
+ [('name', 'foo1'), ('another/name', 'foo2')],
+ )
+
+ # second element of each tuple must be a dictionary (build info)
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_library_list(
+ [('name', {}), ('another', 'foo2')],
+ )
+
+ # those work
+ libs = [('name', {}), ('name', {'ok': 'good'})]
+ cmd.check_library_list(libs)
+
+ def test_get_source_files(self):
+ pkg_dir, dist = self.create_dist()
+ cmd = build_clib(dist)
+
+ # "in 'libraries' option 'sources' must be present and must be
+ # a list of source filenames
+ cmd.libraries = [('name', {})]
+ with pytest.raises(DistutilsSetupError):
+ cmd.get_source_files()
+
+ cmd.libraries = [('name', {'sources': 1})]
+ with pytest.raises(DistutilsSetupError):
+ cmd.get_source_files()
+
+ cmd.libraries = [('name', {'sources': ['a', 'b']})]
+ assert cmd.get_source_files() == ['a', 'b']
+
+ cmd.libraries = [('name', {'sources': ('a', 'b')})]
+ assert cmd.get_source_files() == ['a', 'b']
+
+ cmd.libraries = [
+ ('name', {'sources': ('a', 'b')}),
+ ('name2', {'sources': ['c', 'd']}),
+ ]
+ assert cmd.get_source_files() == ['a', 'b', 'c', 'd']
+
+ def test_build_libraries(self):
+ pkg_dir, dist = self.create_dist()
+ cmd = build_clib(dist)
+
+ class FakeCompiler:
+ def compile(*args, **kw):
+ pass
+
+ create_static_lib = compile
+
+ cmd.compiler = FakeCompiler()
+
+ # build_libraries is also doing a bit of typo checking
+ lib = [('name', {'sources': 'notvalid'})]
+ with pytest.raises(DistutilsSetupError):
+ cmd.build_libraries(lib)
+
+ lib = [('name', {'sources': list()})]
+ cmd.build_libraries(lib)
+
+ lib = [('name', {'sources': tuple()})]
+ cmd.build_libraries(lib)
+
+ def test_finalize_options(self):
+ pkg_dir, dist = self.create_dist()
+ cmd = build_clib(dist)
+
+ cmd.include_dirs = 'one-dir'
+ cmd.finalize_options()
+ assert cmd.include_dirs == ['one-dir']
+
+ cmd.include_dirs = None
+ cmd.finalize_options()
+ assert cmd.include_dirs == []
+
+ cmd.distribution.libraries = 'WONTWORK'
+ with pytest.raises(DistutilsSetupError):
+ cmd.finalize_options()
+
+ @pytest.mark.skipif('platform.system() == "Windows"')
+ def test_run(self):
+ pkg_dir, dist = self.create_dist()
+ cmd = build_clib(dist)
+
+ foo_c = os.path.join(pkg_dir, 'foo.c')
+ self.write_file(foo_c, 'int main(void) { return 1;}\n')
+ cmd.libraries = [('foo', {'sources': [foo_c]})]
+
+ build_temp = os.path.join(pkg_dir, 'build')
+ os.mkdir(build_temp)
+ cmd.build_temp = build_temp
+ cmd.build_clib = build_temp
+
+ # Before we run the command, we want to make sure
+ # all commands are present on the system.
+ ccmd = missing_compiler_executable()
+ if ccmd is not None:
+ self.skipTest(f'The {ccmd!r} command is not found')
+
+ # this should work
+ cmd.run()
+
+ # let's check the result
+ assert 'libfoo.a' in os.listdir(build_temp)
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_ext.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_ext.py
new file mode 100644
index 00000000..dab0507f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_ext.py
@@ -0,0 +1,628 @@
+import contextlib
+import glob
+import importlib
+import os.path
+import platform
+import re
+import shutil
+import site
+import subprocess
+import sys
+import tempfile
+import textwrap
+import time
+from distutils import sysconfig
+from distutils.command.build_ext import build_ext
+from distutils.core import Distribution
+from distutils.errors import (
+ CompileError,
+ DistutilsPlatformError,
+ DistutilsSetupError,
+ UnknownFileError,
+)
+from distutils.extension import Extension
+from distutils.tests import missing_compiler_executable
+from distutils.tests.support import TempdirManager, copy_xxmodule_c, fixup_build_ext
+from io import StringIO
+
+import jaraco.path
+import path
+import pytest
+from test import support
+
+from .compat import py39 as import_helper
+
+
+@pytest.fixture()
+def user_site_dir(request):
+ self = request.instance
+ self.tmp_dir = self.mkdtemp()
+ self.tmp_path = path.Path(self.tmp_dir)
+ from distutils.command import build_ext
+
+ orig_user_base = site.USER_BASE
+
+ site.USER_BASE = self.mkdtemp()
+ build_ext.USER_BASE = site.USER_BASE
+
+ # bpo-30132: On Windows, a .pdb file may be created in the current
+ # working directory. Create a temporary working directory to cleanup
+ # everything at the end of the test.
+ with self.tmp_path:
+ yield
+
+ site.USER_BASE = orig_user_base
+ build_ext.USER_BASE = orig_user_base
+
+ if sys.platform == 'cygwin':
+ time.sleep(1)
+
+
+@contextlib.contextmanager
+def safe_extension_import(name, path):
+ with import_helper.CleanImport(name):
+ with extension_redirect(name, path) as new_path:
+ with import_helper.DirsOnSysPath(new_path):
+ yield
+
+
+@contextlib.contextmanager
+def extension_redirect(mod, path):
+ """
+ Tests will fail to tear down an extension module if it's been imported.
+
+ Before importing, copy the file to a temporary directory that won't
+ be cleaned up. Yield the new path.
+ """
+ if platform.system() != "Windows" and sys.platform != "cygwin":
+ yield path
+ return
+ with import_helper.DirsOnSysPath(path):
+ spec = importlib.util.find_spec(mod)
+ filename = os.path.basename(spec.origin)
+ trash_dir = tempfile.mkdtemp(prefix='deleteme')
+ dest = os.path.join(trash_dir, os.path.basename(filename))
+ shutil.copy(spec.origin, dest)
+ yield trash_dir
+ # TODO: can the file be scheduled for deletion?
+
+
+@pytest.mark.usefixtures('user_site_dir')
+class TestBuildExt(TempdirManager):
+ def build_ext(self, *args, **kwargs):
+ return build_ext(*args, **kwargs)
+
+ @pytest.mark.parametrize("copy_so", [False])
+ def test_build_ext(self, copy_so):
+ missing_compiler_executable()
+ copy_xxmodule_c(self.tmp_dir)
+ xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
+ xx_ext = Extension('xx', [xx_c])
+ if sys.platform != "win32":
+ if not copy_so:
+ xx_ext = Extension(
+ 'xx',
+ [xx_c],
+ library_dirs=['/usr/lib'],
+ libraries=['z'],
+ runtime_library_dirs=['/usr/lib'],
+ )
+ elif sys.platform == 'linux':
+ libz_so = {
+ os.path.realpath(name) for name in glob.iglob('/usr/lib*/libz.so*')
+ }
+ libz_so = sorted(libz_so, key=lambda lib_path: len(lib_path))
+ shutil.copyfile(libz_so[-1], '/tmp/libxx_z.so')
+
+ xx_ext = Extension(
+ 'xx',
+ [xx_c],
+ library_dirs=['/tmp'],
+ libraries=['xx_z'],
+ runtime_library_dirs=['/tmp'],
+ )
+ dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
+ dist.package_dir = self.tmp_dir
+ cmd = self.build_ext(dist)
+ fixup_build_ext(cmd)
+ cmd.build_lib = self.tmp_dir
+ cmd.build_temp = self.tmp_dir
+
+ old_stdout = sys.stdout
+ if not support.verbose:
+ # silence compiler output
+ sys.stdout = StringIO()
+ try:
+ cmd.ensure_finalized()
+ cmd.run()
+ finally:
+ sys.stdout = old_stdout
+
+ with safe_extension_import('xx', self.tmp_dir):
+ self._test_xx(copy_so)
+
+ if sys.platform == 'linux' and copy_so:
+ os.unlink('/tmp/libxx_z.so')
+
+ @staticmethod
+ def _test_xx(copy_so):
+ import xx # type: ignore[import-not-found] # Module generated for tests
+
+ for attr in ('error', 'foo', 'new', 'roj'):
+ assert hasattr(xx, attr)
+
+ assert xx.foo(2, 5) == 7
+ assert xx.foo(13, 15) == 28
+ assert xx.new().demo() is None
+ if support.HAVE_DOCSTRINGS:
+ doc = 'This is a template module just for instruction.'
+ assert xx.__doc__ == doc
+ assert isinstance(xx.Null(), xx.Null)
+ assert isinstance(xx.Str(), xx.Str)
+
+ if sys.platform == 'linux':
+ so_headers = subprocess.check_output(
+ ["readelf", "-d", xx.__file__], universal_newlines=True
+ )
+ import pprint
+
+ pprint.pprint(so_headers)
+ rpaths = [
+ rpath
+ for line in so_headers.split("\n")
+ if "RPATH" in line or "RUNPATH" in line
+ for rpath in line.split()[2][1:-1].split(":")
+ ]
+ if not copy_so:
+ pprint.pprint(rpaths)
+ # Linked against a library in /usr/lib{,64}
+ assert "/usr/lib" not in rpaths and "/usr/lib64" not in rpaths
+ else:
+ # Linked against a library in /tmp
+ assert "/tmp" in rpaths
+ # The import is the real test here
+
+ def test_solaris_enable_shared(self):
+ dist = Distribution({'name': 'xx'})
+ cmd = self.build_ext(dist)
+ old = sys.platform
+
+ sys.platform = 'sunos' # fooling finalize_options
+ from distutils.sysconfig import _config_vars
+
+ old_var = _config_vars.get('Py_ENABLE_SHARED')
+ _config_vars['Py_ENABLE_SHARED'] = True
+ try:
+ cmd.ensure_finalized()
+ finally:
+ sys.platform = old
+ if old_var is None:
+ del _config_vars['Py_ENABLE_SHARED']
+ else:
+ _config_vars['Py_ENABLE_SHARED'] = old_var
+
+ # make sure we get some library dirs under solaris
+ assert len(cmd.library_dirs) > 0
+
+ def test_user_site(self):
+ import site
+
+ dist = Distribution({'name': 'xx'})
+ cmd = self.build_ext(dist)
+
+ # making sure the user option is there
+ options = [name for name, short, label in cmd.user_options]
+ assert 'user' in options
+
+ # setting a value
+ cmd.user = True
+
+ # setting user based lib and include
+ lib = os.path.join(site.USER_BASE, 'lib')
+ incl = os.path.join(site.USER_BASE, 'include')
+ os.mkdir(lib)
+ os.mkdir(incl)
+
+ # let's run finalize
+ cmd.ensure_finalized()
+
+ # see if include_dirs and library_dirs
+ # were set
+ assert lib in cmd.library_dirs
+ assert lib in cmd.rpath
+ assert incl in cmd.include_dirs
+
+ def test_optional_extension(self):
+ # this extension will fail, but let's ignore this failure
+ # with the optional argument.
+ modules = [Extension('foo', ['xxx'], optional=False)]
+ dist = Distribution({'name': 'xx', 'ext_modules': modules})
+ cmd = self.build_ext(dist)
+ cmd.ensure_finalized()
+ with pytest.raises((UnknownFileError, CompileError)):
+ cmd.run() # should raise an error
+
+ modules = [Extension('foo', ['xxx'], optional=True)]
+ dist = Distribution({'name': 'xx', 'ext_modules': modules})
+ cmd = self.build_ext(dist)
+ cmd.ensure_finalized()
+ cmd.run() # should pass
+
+ def test_finalize_options(self):
+ # Make sure Python's include directories (for Python.h, pyconfig.h,
+ # etc.) are in the include search path.
+ modules = [Extension('foo', ['xxx'], optional=False)]
+ dist = Distribution({'name': 'xx', 'ext_modules': modules})
+ cmd = self.build_ext(dist)
+ cmd.finalize_options()
+
+ py_include = sysconfig.get_python_inc()
+ for p in py_include.split(os.path.pathsep):
+ assert p in cmd.include_dirs
+
+ plat_py_include = sysconfig.get_python_inc(plat_specific=True)
+ for p in plat_py_include.split(os.path.pathsep):
+ assert p in cmd.include_dirs
+
+ # make sure cmd.libraries is turned into a list
+ # if it's a string
+ cmd = self.build_ext(dist)
+ cmd.libraries = 'my_lib, other_lib lastlib'
+ cmd.finalize_options()
+ assert cmd.libraries == ['my_lib', 'other_lib', 'lastlib']
+
+ # make sure cmd.library_dirs is turned into a list
+ # if it's a string
+ cmd = self.build_ext(dist)
+ cmd.library_dirs = f'my_lib_dir{os.pathsep}other_lib_dir'
+ cmd.finalize_options()
+ assert 'my_lib_dir' in cmd.library_dirs
+ assert 'other_lib_dir' in cmd.library_dirs
+
+ # make sure rpath is turned into a list
+ # if it's a string
+ cmd = self.build_ext(dist)
+ cmd.rpath = f'one{os.pathsep}two'
+ cmd.finalize_options()
+ assert cmd.rpath == ['one', 'two']
+
+ # make sure cmd.link_objects is turned into a list
+ # if it's a string
+ cmd = build_ext(dist)
+ cmd.link_objects = 'one two,three'
+ cmd.finalize_options()
+ assert cmd.link_objects == ['one', 'two', 'three']
+
+ # XXX more tests to perform for win32
+
+ # make sure define is turned into 2-tuples
+ # strings if they are ','-separated strings
+ cmd = self.build_ext(dist)
+ cmd.define = 'one,two'
+ cmd.finalize_options()
+ assert cmd.define == [('one', '1'), ('two', '1')]
+
+ # make sure undef is turned into a list of
+ # strings if they are ','-separated strings
+ cmd = self.build_ext(dist)
+ cmd.undef = 'one,two'
+ cmd.finalize_options()
+ assert cmd.undef == ['one', 'two']
+
+ # make sure swig_opts is turned into a list
+ cmd = self.build_ext(dist)
+ cmd.swig_opts = None
+ cmd.finalize_options()
+ assert cmd.swig_opts == []
+
+ cmd = self.build_ext(dist)
+ cmd.swig_opts = '1 2'
+ cmd.finalize_options()
+ assert cmd.swig_opts == ['1', '2']
+
+ def test_check_extensions_list(self):
+ dist = Distribution()
+ cmd = self.build_ext(dist)
+ cmd.finalize_options()
+
+ # 'extensions' option must be a list of Extension instances
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_extensions_list('foo')
+
+ # each element of 'ext_modules' option must be an
+ # Extension instance or 2-tuple
+ exts = [('bar', 'foo', 'bar'), 'foo']
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_extensions_list(exts)
+
+ # first element of each tuple in 'ext_modules'
+ # must be the extension name (a string) and match
+ # a python dotted-separated name
+ exts = [('foo-bar', '')]
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_extensions_list(exts)
+
+ # second element of each tuple in 'ext_modules'
+ # must be a dictionary (build info)
+ exts = [('foo.bar', '')]
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_extensions_list(exts)
+
+ # ok this one should pass
+ exts = [('foo.bar', {'sources': [''], 'libraries': 'foo', 'some': 'bar'})]
+ cmd.check_extensions_list(exts)
+ ext = exts[0]
+ assert isinstance(ext, Extension)
+
+ # check_extensions_list adds in ext the values passed
+ # when they are in ('include_dirs', 'library_dirs', 'libraries'
+ # 'extra_objects', 'extra_compile_args', 'extra_link_args')
+ assert ext.libraries == 'foo'
+ assert not hasattr(ext, 'some')
+
+ # 'macros' element of build info dict must be 1- or 2-tuple
+ exts = [
+ (
+ 'foo.bar',
+ {
+ 'sources': [''],
+ 'libraries': 'foo',
+ 'some': 'bar',
+ 'macros': [('1', '2', '3'), 'foo'],
+ },
+ )
+ ]
+ with pytest.raises(DistutilsSetupError):
+ cmd.check_extensions_list(exts)
+
+ exts[0][1]['macros'] = [('1', '2'), ('3',)]
+ cmd.check_extensions_list(exts)
+ assert exts[0].undef_macros == ['3']
+ assert exts[0].define_macros == [('1', '2')]
+
+ def test_get_source_files(self):
+ modules = [Extension('foo', ['xxx'], optional=False)]
+ dist = Distribution({'name': 'xx', 'ext_modules': modules})
+ cmd = self.build_ext(dist)
+ cmd.ensure_finalized()
+ assert cmd.get_source_files() == ['xxx']
+
+ def test_unicode_module_names(self):
+ modules = [
+ Extension('foo', ['aaa'], optional=False),
+ Extension('föö', ['uuu'], optional=False),
+ ]
+ dist = Distribution({'name': 'xx', 'ext_modules': modules})
+ cmd = self.build_ext(dist)
+ cmd.ensure_finalized()
+ assert re.search(r'foo(_d)?\..*', cmd.get_ext_filename(modules[0].name))
+ assert re.search(r'föö(_d)?\..*', cmd.get_ext_filename(modules[1].name))
+ assert cmd.get_export_symbols(modules[0]) == ['PyInit_foo']
+ assert cmd.get_export_symbols(modules[1]) == ['PyInitU_f_1gaa']
+
+ def test_export_symbols__init__(self):
+ # https://github.com/python/cpython/issues/80074
+ # https://github.com/pypa/setuptools/issues/4826
+ modules = [
+ Extension('foo.__init__', ['aaa']),
+ Extension('föö.__init__', ['uuu']),
+ ]
+ dist = Distribution({'name': 'xx', 'ext_modules': modules})
+ cmd = self.build_ext(dist)
+ cmd.ensure_finalized()
+ assert cmd.get_export_symbols(modules[0]) == ['PyInit_foo']
+ assert cmd.get_export_symbols(modules[1]) == ['PyInitU_f_1gaa']
+
+ def test_compiler_option(self):
+ # cmd.compiler is an option and
+ # should not be overridden by a compiler instance
+ # when the command is run
+ dist = Distribution()
+ cmd = self.build_ext(dist)
+ cmd.compiler = 'unix'
+ cmd.ensure_finalized()
+ cmd.run()
+ assert cmd.compiler == 'unix'
+
+ def test_get_outputs(self):
+ missing_compiler_executable()
+ tmp_dir = self.mkdtemp()
+ c_file = os.path.join(tmp_dir, 'foo.c')
+ self.write_file(c_file, 'void PyInit_foo(void) {}\n')
+ ext = Extension('foo', [c_file], optional=False)
+ dist = Distribution({'name': 'xx', 'ext_modules': [ext]})
+ cmd = self.build_ext(dist)
+ fixup_build_ext(cmd)
+ cmd.ensure_finalized()
+ assert len(cmd.get_outputs()) == 1
+
+ cmd.build_lib = os.path.join(self.tmp_dir, 'build')
+ cmd.build_temp = os.path.join(self.tmp_dir, 'tempt')
+
+ # issue #5977 : distutils build_ext.get_outputs
+ # returns wrong result with --inplace
+ other_tmp_dir = os.path.realpath(self.mkdtemp())
+ old_wd = os.getcwd()
+ os.chdir(other_tmp_dir)
+ try:
+ cmd.inplace = True
+ cmd.run()
+ so_file = cmd.get_outputs()[0]
+ finally:
+ os.chdir(old_wd)
+ assert os.path.exists(so_file)
+ ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
+ assert so_file.endswith(ext_suffix)
+ so_dir = os.path.dirname(so_file)
+ assert so_dir == other_tmp_dir
+
+ cmd.inplace = False
+ cmd.compiler = None
+ cmd.run()
+ so_file = cmd.get_outputs()[0]
+ assert os.path.exists(so_file)
+ assert so_file.endswith(ext_suffix)
+ so_dir = os.path.dirname(so_file)
+ assert so_dir == cmd.build_lib
+
+ # inplace = False, cmd.package = 'bar'
+ build_py = cmd.get_finalized_command('build_py')
+ build_py.package_dir = {'': 'bar'}
+ path = cmd.get_ext_fullpath('foo')
+ # checking that the last directory is the build_dir
+ path = os.path.split(path)[0]
+ assert path == cmd.build_lib
+
+ # inplace = True, cmd.package = 'bar'
+ cmd.inplace = True
+ other_tmp_dir = os.path.realpath(self.mkdtemp())
+ old_wd = os.getcwd()
+ os.chdir(other_tmp_dir)
+ try:
+ path = cmd.get_ext_fullpath('foo')
+ finally:
+ os.chdir(old_wd)
+ # checking that the last directory is bar
+ path = os.path.split(path)[0]
+ lastdir = os.path.split(path)[-1]
+ assert lastdir == 'bar'
+
+ def test_ext_fullpath(self):
+ ext = sysconfig.get_config_var('EXT_SUFFIX')
+ # building lxml.etree inplace
+ # etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c')
+ # etree_ext = Extension('lxml.etree', [etree_c])
+ # dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]})
+ dist = Distribution()
+ cmd = self.build_ext(dist)
+ cmd.inplace = True
+ cmd.distribution.package_dir = {'': 'src'}
+ cmd.distribution.packages = ['lxml', 'lxml.html']
+ curdir = os.getcwd()
+ wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext)
+ path = cmd.get_ext_fullpath('lxml.etree')
+ assert wanted == path
+
+ # building lxml.etree not inplace
+ cmd.inplace = False
+ cmd.build_lib = os.path.join(curdir, 'tmpdir')
+ wanted = os.path.join(curdir, 'tmpdir', 'lxml', 'etree' + ext)
+ path = cmd.get_ext_fullpath('lxml.etree')
+ assert wanted == path
+
+ # building twisted.runner.portmap not inplace
+ build_py = cmd.get_finalized_command('build_py')
+ build_py.package_dir = {}
+ cmd.distribution.packages = ['twisted', 'twisted.runner.portmap']
+ path = cmd.get_ext_fullpath('twisted.runner.portmap')
+ wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner', 'portmap' + ext)
+ assert wanted == path
+
+ # building twisted.runner.portmap inplace
+ cmd.inplace = True
+ path = cmd.get_ext_fullpath('twisted.runner.portmap')
+ wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext)
+ assert wanted == path
+
+ @pytest.mark.skipif('platform.system() != "Darwin"')
+ @pytest.mark.usefixtures('save_env')
+ def test_deployment_target_default(self):
+ # Issue 9516: Test that, in the absence of the environment variable,
+ # an extension module is compiled with the same deployment target as
+ # the interpreter.
+ self._try_compile_deployment_target('==', None)
+
+ @pytest.mark.skipif('platform.system() != "Darwin"')
+ @pytest.mark.usefixtures('save_env')
+ def test_deployment_target_too_low(self):
+ # Issue 9516: Test that an extension module is not allowed to be
+ # compiled with a deployment target less than that of the interpreter.
+ with pytest.raises(DistutilsPlatformError):
+ self._try_compile_deployment_target('>', '10.1')
+
+ @pytest.mark.skipif('platform.system() != "Darwin"')
+ @pytest.mark.usefixtures('save_env')
+ def test_deployment_target_higher_ok(self): # pragma: no cover
+ # Issue 9516: Test that an extension module can be compiled with a
+ # deployment target higher than that of the interpreter: the ext
+ # module may depend on some newer OS feature.
+ deptarget = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
+ if deptarget:
+ # increment the minor version number (i.e. 10.6 -> 10.7)
+ deptarget = [int(x) for x in deptarget.split('.')]
+ deptarget[-1] += 1
+ deptarget = '.'.join(str(i) for i in deptarget)
+ self._try_compile_deployment_target('<', deptarget)
+
+ def _try_compile_deployment_target(self, operator, target): # pragma: no cover
+ if target is None:
+ if os.environ.get('MACOSX_DEPLOYMENT_TARGET'):
+ del os.environ['MACOSX_DEPLOYMENT_TARGET']
+ else:
+ os.environ['MACOSX_DEPLOYMENT_TARGET'] = target
+
+ jaraco.path.build(
+ {
+ 'deptargetmodule.c': textwrap.dedent(f"""\
+ #include <AvailabilityMacros.h>
+
+ int dummy;
+
+ #if TARGET {operator} MAC_OS_X_VERSION_MIN_REQUIRED
+ #else
+ #error "Unexpected target"
+ #endif
+
+ """),
+ },
+ self.tmp_path,
+ )
+
+ # get the deployment target that the interpreter was built with
+ target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
+ target = tuple(map(int, target.split('.')[0:2]))
+ # format the target value as defined in the Apple
+ # Availability Macros. We can't use the macro names since
+ # at least one value we test with will not exist yet.
+ if target[:2] < (10, 10):
+ # for 10.1 through 10.9.x -> "10n0"
+ tmpl = '{:02}{:01}0'
+ else:
+ # for 10.10 and beyond -> "10nn00"
+ if len(target) >= 2:
+ tmpl = '{:02}{:02}00'
+ else:
+ # 11 and later can have no minor version (11 instead of 11.0)
+ tmpl = '{:02}0000'
+ target = tmpl.format(*target)
+ deptarget_ext = Extension(
+ 'deptarget',
+ [self.tmp_path / 'deptargetmodule.c'],
+ extra_compile_args=[f'-DTARGET={target}'],
+ )
+ dist = Distribution({'name': 'deptarget', 'ext_modules': [deptarget_ext]})
+ dist.package_dir = self.tmp_dir
+ cmd = self.build_ext(dist)
+ cmd.build_lib = self.tmp_dir
+ cmd.build_temp = self.tmp_dir
+
+ try:
+ old_stdout = sys.stdout
+ if not support.verbose:
+ # silence compiler output
+ sys.stdout = StringIO()
+ try:
+ cmd.ensure_finalized()
+ cmd.run()
+ finally:
+ sys.stdout = old_stdout
+
+ except CompileError:
+ self.fail("Wrong deployment target during compilation")
+
+
+class TestParallelBuildExt(TestBuildExt):
+ def build_ext(self, *args, **kwargs):
+ build_ext = super().build_ext(*args, **kwargs)
+ build_ext.parallel = True
+ return build_ext
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_py.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_py.py
new file mode 100644
index 00000000..b316ed43
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_py.py
@@ -0,0 +1,196 @@
+"""Tests for distutils.command.build_py."""
+
+import os
+import sys
+from distutils.command.build_py import build_py
+from distutils.core import Distribution
+from distutils.errors import DistutilsFileError
+from distutils.tests import support
+
+import jaraco.path
+import pytest
+
+
+@support.combine_markers
+class TestBuildPy(support.TempdirManager):
+ def test_package_data(self):
+ sources = self.mkdtemp()
+ jaraco.path.build(
+ {
+ '__init__.py': "# Pretend this is a package.",
+ 'README.txt': 'Info about this package',
+ },
+ sources,
+ )
+
+ destination = self.mkdtemp()
+
+ dist = Distribution({"packages": ["pkg"], "package_dir": {"pkg": sources}})
+ # script_name need not exist, it just need to be initialized
+ dist.script_name = os.path.join(sources, "setup.py")
+ dist.command_obj["build"] = support.DummyCommand(
+ force=False, build_lib=destination
+ )
+ dist.packages = ["pkg"]
+ dist.package_data = {"pkg": ["README.txt"]}
+ dist.package_dir = {"pkg": sources}
+
+ cmd = build_py(dist)
+ cmd.compile = True
+ cmd.ensure_finalized()
+ assert cmd.package_data == dist.package_data
+
+ cmd.run()
+
+ # This makes sure the list of outputs includes byte-compiled
+ # files for Python modules but not for package data files
+ # (there shouldn't *be* byte-code files for those!).
+ assert len(cmd.get_outputs()) == 3
+ pkgdest = os.path.join(destination, "pkg")
+ files = os.listdir(pkgdest)
+ pycache_dir = os.path.join(pkgdest, "__pycache__")
+ assert "__init__.py" in files
+ assert "README.txt" in files
+ if sys.dont_write_bytecode:
+ assert not os.path.exists(pycache_dir)
+ else:
+ pyc_files = os.listdir(pycache_dir)
+ assert f"__init__.{sys.implementation.cache_tag}.pyc" in pyc_files
+
+ def test_empty_package_dir(self):
+ # See bugs #1668596/#1720897
+ sources = self.mkdtemp()
+ jaraco.path.build({'__init__.py': '', 'doc': {'testfile': ''}}, sources)
+
+ os.chdir(sources)
+ dist = Distribution({
+ "packages": ["pkg"],
+ "package_dir": {"pkg": ""},
+ "package_data": {"pkg": ["doc/*"]},
+ })
+ # script_name need not exist, it just need to be initialized
+ dist.script_name = os.path.join(sources, "setup.py")
+ dist.script_args = ["build"]
+ dist.parse_command_line()
+
+ try:
+ dist.run_commands()
+ except DistutilsFileError:
+ self.fail("failed package_data test when package_dir is ''")
+
+ @pytest.mark.skipif('sys.dont_write_bytecode')
+ def test_byte_compile(self):
+ project_dir, dist = self.create_dist(py_modules=['boiledeggs'])
+ os.chdir(project_dir)
+ self.write_file('boiledeggs.py', 'import antigravity')
+ cmd = build_py(dist)
+ cmd.compile = True
+ cmd.build_lib = 'here'
+ cmd.finalize_options()
+ cmd.run()
+
+ found = os.listdir(cmd.build_lib)
+ assert sorted(found) == ['__pycache__', 'boiledeggs.py']
+ found = os.listdir(os.path.join(cmd.build_lib, '__pycache__'))
+ assert found == [f'boiledeggs.{sys.implementation.cache_tag}.pyc']
+
+ @pytest.mark.skipif('sys.dont_write_bytecode')
+ def test_byte_compile_optimized(self):
+ project_dir, dist = self.create_dist(py_modules=['boiledeggs'])
+ os.chdir(project_dir)
+ self.write_file('boiledeggs.py', 'import antigravity')
+ cmd = build_py(dist)
+ cmd.compile = False
+ cmd.optimize = 1
+ cmd.build_lib = 'here'
+ cmd.finalize_options()
+ cmd.run()
+
+ found = os.listdir(cmd.build_lib)
+ assert sorted(found) == ['__pycache__', 'boiledeggs.py']
+ found = os.listdir(os.path.join(cmd.build_lib, '__pycache__'))
+ expect = f'boiledeggs.{sys.implementation.cache_tag}.opt-1.pyc'
+ assert sorted(found) == [expect]
+
+ def test_dir_in_package_data(self):
+ """
+ A directory in package_data should not be added to the filelist.
+ """
+ # See bug 19286
+ sources = self.mkdtemp()
+ jaraco.path.build(
+ {
+ 'pkg': {
+ '__init__.py': '',
+ 'doc': {
+ 'testfile': '',
+ # create a directory that could be incorrectly detected as a file
+ 'otherdir': {},
+ },
+ }
+ },
+ sources,
+ )
+
+ os.chdir(sources)
+ dist = Distribution({"packages": ["pkg"], "package_data": {"pkg": ["doc/*"]}})
+ # script_name need not exist, it just need to be initialized
+ dist.script_name = os.path.join(sources, "setup.py")
+ dist.script_args = ["build"]
+ dist.parse_command_line()
+
+ try:
+ dist.run_commands()
+ except DistutilsFileError:
+ self.fail("failed package_data when data dir includes a dir")
+
+ def test_dont_write_bytecode(self, caplog):
+ # makes sure byte_compile is not used
+ dist = self.create_dist()[1]
+ cmd = build_py(dist)
+ cmd.compile = True
+ cmd.optimize = 1
+
+ old_dont_write_bytecode = sys.dont_write_bytecode
+ sys.dont_write_bytecode = True
+ try:
+ cmd.byte_compile([])
+ finally:
+ sys.dont_write_bytecode = old_dont_write_bytecode
+
+ assert 'byte-compiling is disabled' in caplog.records[0].message
+
+ def test_namespace_package_does_not_warn(self, caplog):
+ """
+ Originally distutils implementation did not account for PEP 420
+ and included warns for package directories that did not contain
+ ``__init__.py`` files.
+ After the acceptance of PEP 420, these warnings don't make more sense
+ so we want to ensure there are not displayed to not confuse the users.
+ """
+ # Create a fake project structure with a package namespace:
+ tmp = self.mkdtemp()
+ jaraco.path.build({'ns': {'pkg': {'module.py': ''}}}, tmp)
+ os.chdir(tmp)
+
+ # Configure the package:
+ attrs = {
+ "name": "ns.pkg",
+ "packages": ["ns", "ns.pkg"],
+ "script_name": "setup.py",
+ }
+ dist = Distribution(attrs)
+
+ # Run code paths that would trigger the trap:
+ cmd = dist.get_command_obj("build_py")
+ cmd.finalize_options()
+ modules = cmd.find_all_modules()
+ assert len(modules) == 1
+ module_path = modules[0][-1]
+ assert module_path.replace(os.sep, "/") == "ns/pkg/module.py"
+
+ cmd.run()
+
+ assert not any(
+ "package init file" in msg and "not found" in msg for msg in caplog.messages
+ )
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_scripts.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_scripts.py
new file mode 100644
index 00000000..3582f691
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_build_scripts.py
@@ -0,0 +1,96 @@
+"""Tests for distutils.command.build_scripts."""
+
+import os
+import textwrap
+from distutils import sysconfig
+from distutils.command.build_scripts import build_scripts
+from distutils.core import Distribution
+from distutils.tests import support
+
+import jaraco.path
+
+
+class TestBuildScripts(support.TempdirManager):
+ def test_default_settings(self):
+ cmd = self.get_build_scripts_cmd("/foo/bar", [])
+ assert not cmd.force
+ assert cmd.build_dir is None
+
+ cmd.finalize_options()
+
+ assert cmd.force
+ assert cmd.build_dir == "/foo/bar"
+
+ def test_build(self):
+ source = self.mkdtemp()
+ target = self.mkdtemp()
+ expected = self.write_sample_scripts(source)
+
+ cmd = self.get_build_scripts_cmd(
+ target, [os.path.join(source, fn) for fn in expected]
+ )
+ cmd.finalize_options()
+ cmd.run()
+
+ built = os.listdir(target)
+ for name in expected:
+ assert name in built
+
+ def get_build_scripts_cmd(self, target, scripts):
+ import sys
+
+ dist = Distribution()
+ dist.scripts = scripts
+ dist.command_obj["build"] = support.DummyCommand(
+ build_scripts=target, force=True, executable=sys.executable
+ )
+ return build_scripts(dist)
+
+ @staticmethod
+ def write_sample_scripts(dir):
+ spec = {
+ 'script1.py': textwrap.dedent("""
+ #! /usr/bin/env python2.3
+ # bogus script w/ Python sh-bang
+ pass
+ """).lstrip(),
+ 'script2.py': textwrap.dedent("""
+ #!/usr/bin/python
+ # bogus script w/ Python sh-bang
+ pass
+ """).lstrip(),
+ 'shell.sh': textwrap.dedent("""
+ #!/bin/sh
+ # bogus shell script w/ sh-bang
+ exit 0
+ """).lstrip(),
+ }
+ jaraco.path.build(spec, dir)
+ return list(spec)
+
+ def test_version_int(self):
+ source = self.mkdtemp()
+ target = self.mkdtemp()
+ expected = self.write_sample_scripts(source)
+
+ cmd = self.get_build_scripts_cmd(
+ target, [os.path.join(source, fn) for fn in expected]
+ )
+ cmd.finalize_options()
+
+ # https://bugs.python.org/issue4524
+ #
+ # On linux-g++-32 with command line `./configure --enable-ipv6
+ # --with-suffix=3`, python is compiled okay but the build scripts
+ # failed when writing the name of the executable
+ old = sysconfig.get_config_vars().get('VERSION')
+ sysconfig._config_vars['VERSION'] = 4
+ try:
+ cmd.run()
+ finally:
+ if old is not None:
+ sysconfig._config_vars['VERSION'] = old
+
+ built = os.listdir(target)
+ for name in expected:
+ assert name in built
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_check.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_check.py
new file mode 100644
index 00000000..b672b1f9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_check.py
@@ -0,0 +1,194 @@
+"""Tests for distutils.command.check."""
+
+import os
+import textwrap
+from distutils.command.check import check
+from distutils.errors import DistutilsSetupError
+from distutils.tests import support
+
+import pytest
+
+try:
+ import pygments
+except ImportError:
+ pygments = None
+
+
+HERE = os.path.dirname(__file__)
+
+
+@support.combine_markers
+class TestCheck(support.TempdirManager):
+ def _run(self, metadata=None, cwd=None, **options):
+ if metadata is None:
+ metadata = {}
+ if cwd is not None:
+ old_dir = os.getcwd()
+ os.chdir(cwd)
+ pkg_info, dist = self.create_dist(**metadata)
+ cmd = check(dist)
+ cmd.initialize_options()
+ for name, value in options.items():
+ setattr(cmd, name, value)
+ cmd.ensure_finalized()
+ cmd.run()
+ if cwd is not None:
+ os.chdir(old_dir)
+ return cmd
+
+ def test_check_metadata(self):
+ # let's run the command with no metadata at all
+ # by default, check is checking the metadata
+ # should have some warnings
+ cmd = self._run()
+ assert cmd._warnings == 1
+
+ # now let's add the required fields
+ # and run it again, to make sure we don't get
+ # any warning anymore
+ metadata = {
+ 'url': 'xxx',
+ 'author': 'xxx',
+ 'author_email': 'xxx',
+ 'name': 'xxx',
+ 'version': 'xxx',
+ }
+ cmd = self._run(metadata)
+ assert cmd._warnings == 0
+
+ # now with the strict mode, we should
+ # get an error if there are missing metadata
+ with pytest.raises(DistutilsSetupError):
+ self._run({}, **{'strict': 1})
+
+ # and of course, no error when all metadata are present
+ cmd = self._run(metadata, strict=True)
+ assert cmd._warnings == 0
+
+ # now a test with non-ASCII characters
+ metadata = {
+ 'url': 'xxx',
+ 'author': '\u00c9ric',
+ 'author_email': 'xxx',
+ 'name': 'xxx',
+ 'version': 'xxx',
+ 'description': 'Something about esszet \u00df',
+ 'long_description': 'More things about esszet \u00df',
+ }
+ cmd = self._run(metadata)
+ assert cmd._warnings == 0
+
+ def test_check_author_maintainer(self):
+ for kind in ("author", "maintainer"):
+ # ensure no warning when author_email or maintainer_email is given
+ # (the spec allows these fields to take the form "Name <email>")
+ metadata = {
+ 'url': 'xxx',
+ kind + '_email': 'Name <name@email.com>',
+ 'name': 'xxx',
+ 'version': 'xxx',
+ }
+ cmd = self._run(metadata)
+ assert cmd._warnings == 0
+
+ # the check should not warn if only email is given
+ metadata[kind + '_email'] = 'name@email.com'
+ cmd = self._run(metadata)
+ assert cmd._warnings == 0
+
+ # the check should not warn if only the name is given
+ metadata[kind] = "Name"
+ del metadata[kind + '_email']
+ cmd = self._run(metadata)
+ assert cmd._warnings == 0
+
+ def test_check_document(self):
+ pytest.importorskip('docutils')
+ pkg_info, dist = self.create_dist()
+ cmd = check(dist)
+
+ # let's see if it detects broken rest
+ broken_rest = 'title\n===\n\ntest'
+ msgs = cmd._check_rst_data(broken_rest)
+ assert len(msgs) == 1
+
+ # and non-broken rest
+ rest = 'title\n=====\n\ntest'
+ msgs = cmd._check_rst_data(rest)
+ assert len(msgs) == 0
+
+ def test_check_restructuredtext(self):
+ pytest.importorskip('docutils')
+ # let's see if it detects broken rest in long_description
+ broken_rest = 'title\n===\n\ntest'
+ pkg_info, dist = self.create_dist(long_description=broken_rest)
+ cmd = check(dist)
+ cmd.check_restructuredtext()
+ assert cmd._warnings == 1
+
+ # let's see if we have an error with strict=True
+ metadata = {
+ 'url': 'xxx',
+ 'author': 'xxx',
+ 'author_email': 'xxx',
+ 'name': 'xxx',
+ 'version': 'xxx',
+ 'long_description': broken_rest,
+ }
+ with pytest.raises(DistutilsSetupError):
+ self._run(metadata, **{'strict': 1, 'restructuredtext': 1})
+
+ # and non-broken rest, including a non-ASCII character to test #12114
+ metadata['long_description'] = 'title\n=====\n\ntest \u00df'
+ cmd = self._run(metadata, strict=True, restructuredtext=True)
+ assert cmd._warnings == 0
+
+ # check that includes work to test #31292
+ metadata['long_description'] = 'title\n=====\n\n.. include:: includetest.rst'
+ cmd = self._run(metadata, cwd=HERE, strict=True, restructuredtext=True)
+ assert cmd._warnings == 0
+
+ def test_check_restructuredtext_with_syntax_highlight(self):
+ pytest.importorskip('docutils')
+ # Don't fail if there is a `code` or `code-block` directive
+
+ example_rst_docs = [
+ textwrap.dedent(
+ """\
+ Here's some code:
+
+ .. code:: python
+
+ def foo():
+ pass
+ """
+ ),
+ textwrap.dedent(
+ """\
+ Here's some code:
+
+ .. code-block:: python
+
+ def foo():
+ pass
+ """
+ ),
+ ]
+
+ for rest_with_code in example_rst_docs:
+ pkg_info, dist = self.create_dist(long_description=rest_with_code)
+ cmd = check(dist)
+ cmd.check_restructuredtext()
+ msgs = cmd._check_rst_data(rest_with_code)
+ if pygments is not None:
+ assert len(msgs) == 0
+ else:
+ assert len(msgs) == 1
+ assert (
+ str(msgs[0][1])
+ == 'Cannot analyze code. Pygments package not found.'
+ )
+
+ def test_check_all(self):
+ with pytest.raises(DistutilsSetupError):
+ self._run({}, **{'strict': 1, 'restructuredtext': 1})
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_clean.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_clean.py
new file mode 100644
index 00000000..cc78f30f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_clean.py
@@ -0,0 +1,45 @@
+"""Tests for distutils.command.clean."""
+
+import os
+from distutils.command.clean import clean
+from distutils.tests import support
+
+
+class TestClean(support.TempdirManager):
+ def test_simple_run(self):
+ pkg_dir, dist = self.create_dist()
+ cmd = clean(dist)
+
+ # let's add some elements clean should remove
+ dirs = [
+ (d, os.path.join(pkg_dir, d))
+ for d in (
+ 'build_temp',
+ 'build_lib',
+ 'bdist_base',
+ 'build_scripts',
+ 'build_base',
+ )
+ ]
+
+ for name, path in dirs:
+ os.mkdir(path)
+ setattr(cmd, name, path)
+ if name == 'build_base':
+ continue
+ for f in ('one', 'two', 'three'):
+ self.write_file(os.path.join(path, f))
+
+ # let's run the command
+ cmd.all = 1
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # make sure the files where removed
+ for _name, path in dirs:
+ assert not os.path.exists(path), f'{path} was not removed'
+
+ # let's run the command again (should spit warnings but succeed)
+ cmd.all = 1
+ cmd.ensure_finalized()
+ cmd.run()
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_cmd.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_cmd.py
new file mode 100644
index 00000000..76e8f598
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_cmd.py
@@ -0,0 +1,107 @@
+"""Tests for distutils.cmd."""
+
+import os
+from distutils import debug
+from distutils.cmd import Command
+from distutils.dist import Distribution
+from distutils.errors import DistutilsOptionError
+
+import pytest
+
+
+class MyCmd(Command):
+ def initialize_options(self):
+ pass
+
+
+@pytest.fixture
+def cmd(request):
+ return MyCmd(Distribution())
+
+
+class TestCommand:
+ def test_ensure_string_list(self, cmd):
+ cmd.not_string_list = ['one', 2, 'three']
+ cmd.yes_string_list = ['one', 'two', 'three']
+ cmd.not_string_list2 = object()
+ cmd.yes_string_list2 = 'ok'
+ cmd.ensure_string_list('yes_string_list')
+ cmd.ensure_string_list('yes_string_list2')
+
+ with pytest.raises(DistutilsOptionError):
+ cmd.ensure_string_list('not_string_list')
+
+ with pytest.raises(DistutilsOptionError):
+ cmd.ensure_string_list('not_string_list2')
+
+ cmd.option1 = 'ok,dok'
+ cmd.ensure_string_list('option1')
+ assert cmd.option1 == ['ok', 'dok']
+
+ cmd.option2 = ['xxx', 'www']
+ cmd.ensure_string_list('option2')
+
+ cmd.option3 = ['ok', 2]
+ with pytest.raises(DistutilsOptionError):
+ cmd.ensure_string_list('option3')
+
+ def test_make_file(self, cmd):
+ # making sure it raises when infiles is not a string or a list/tuple
+ with pytest.raises(TypeError):
+ cmd.make_file(infiles=True, outfile='', func='func', args=())
+
+ # making sure execute gets called properly
+ def _execute(func, args, exec_msg, level):
+ assert exec_msg == 'generating out from in'
+
+ cmd.force = True
+ cmd.execute = _execute
+ cmd.make_file(infiles='in', outfile='out', func='func', args=())
+
+ def test_dump_options(self, cmd):
+ msgs = []
+
+ def _announce(msg, level):
+ msgs.append(msg)
+
+ cmd.announce = _announce
+ cmd.option1 = 1
+ cmd.option2 = 1
+ cmd.user_options = [('option1', '', ''), ('option2', '', '')]
+ cmd.dump_options()
+
+ wanted = ["command options for 'MyCmd':", ' option1 = 1', ' option2 = 1']
+ assert msgs == wanted
+
+ def test_ensure_string(self, cmd):
+ cmd.option1 = 'ok'
+ cmd.ensure_string('option1')
+
+ cmd.option2 = None
+ cmd.ensure_string('option2', 'xxx')
+ assert hasattr(cmd, 'option2')
+
+ cmd.option3 = 1
+ with pytest.raises(DistutilsOptionError):
+ cmd.ensure_string('option3')
+
+ def test_ensure_filename(self, cmd):
+ cmd.option1 = __file__
+ cmd.ensure_filename('option1')
+ cmd.option2 = 'xxx'
+ with pytest.raises(DistutilsOptionError):
+ cmd.ensure_filename('option2')
+
+ def test_ensure_dirname(self, cmd):
+ cmd.option1 = os.path.dirname(__file__) or os.curdir
+ cmd.ensure_dirname('option1')
+ cmd.option2 = 'xxx'
+ with pytest.raises(DistutilsOptionError):
+ cmd.ensure_dirname('option2')
+
+ def test_debug_print(self, cmd, capsys, monkeypatch):
+ cmd.debug_print('xxx')
+ assert capsys.readouterr().out == ''
+ monkeypatch.setattr(debug, 'DEBUG', True)
+ cmd.debug_print('xxx')
+ assert capsys.readouterr().out == 'xxx\n'
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_config_cmd.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_config_cmd.py
new file mode 100644
index 00000000..ebee2ef9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_config_cmd.py
@@ -0,0 +1,87 @@
+"""Tests for distutils.command.config."""
+
+import os
+import sys
+from distutils._log import log
+from distutils.command.config import config, dump_file
+from distutils.tests import missing_compiler_executable, support
+
+import more_itertools
+import path
+import pytest
+
+
+@pytest.fixture(autouse=True)
+def info_log(request, monkeypatch):
+ self = request.instance
+ self._logs = []
+ monkeypatch.setattr(log, 'info', self._info)
+
+
+@support.combine_markers
+class TestConfig(support.TempdirManager):
+ def _info(self, msg, *args):
+ for line in msg.splitlines():
+ self._logs.append(line)
+
+ def test_dump_file(self):
+ this_file = path.Path(__file__).with_suffix('.py')
+ with this_file.open(encoding='utf-8') as f:
+ numlines = more_itertools.ilen(f)
+
+ dump_file(this_file, 'I am the header')
+ assert len(self._logs) == numlines + 1
+
+ @pytest.mark.skipif('platform.system() == "Windows"')
+ def test_search_cpp(self):
+ cmd = missing_compiler_executable(['preprocessor'])
+ if cmd is not None:
+ self.skipTest(f'The {cmd!r} command is not found')
+ pkg_dir, dist = self.create_dist()
+ cmd = config(dist)
+ cmd._check_compiler()
+ compiler = cmd.compiler
+ if sys.platform[:3] == "aix" and "xlc" in compiler.preprocessor[0].lower():
+ self.skipTest(
+ 'xlc: The -E option overrides the -P, -o, and -qsyntaxonly options'
+ )
+
+ # simple pattern searches
+ match = cmd.search_cpp(pattern='xxx', body='/* xxx */')
+ assert match == 0
+
+ match = cmd.search_cpp(pattern='_configtest', body='/* xxx */')
+ assert match == 1
+
+ def test_finalize_options(self):
+ # finalize_options does a bit of transformation
+ # on options
+ pkg_dir, dist = self.create_dist()
+ cmd = config(dist)
+ cmd.include_dirs = f'one{os.pathsep}two'
+ cmd.libraries = 'one'
+ cmd.library_dirs = f'three{os.pathsep}four'
+ cmd.ensure_finalized()
+
+ assert cmd.include_dirs == ['one', 'two']
+ assert cmd.libraries == ['one']
+ assert cmd.library_dirs == ['three', 'four']
+
+ def test_clean(self):
+ # _clean removes files
+ tmp_dir = self.mkdtemp()
+ f1 = os.path.join(tmp_dir, 'one')
+ f2 = os.path.join(tmp_dir, 'two')
+
+ self.write_file(f1, 'xxx')
+ self.write_file(f2, 'xxx')
+
+ for f in (f1, f2):
+ assert os.path.exists(f)
+
+ pkg_dir, dist = self.create_dist()
+ cmd = config(dist)
+ cmd._clean(f1, f2)
+
+ for f in (f1, f2):
+ assert not os.path.exists(f)
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_core.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_core.py
new file mode 100644
index 00000000..bad3fb7e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_core.py
@@ -0,0 +1,130 @@
+"""Tests for distutils.core."""
+
+import distutils.core
+import io
+import os
+import sys
+from distutils.dist import Distribution
+
+import pytest
+
+# setup script that uses __file__
+setup_using___file__ = """\
+
+__file__
+
+from distutils.core import setup
+setup()
+"""
+
+setup_prints_cwd = """\
+
+import os
+print(os.getcwd())
+
+from distutils.core import setup
+setup()
+"""
+
+setup_does_nothing = """\
+from distutils.core import setup
+setup()
+"""
+
+
+setup_defines_subclass = """\
+from distutils.core import setup
+from distutils.command.install import install as _install
+
+class install(_install):
+ sub_commands = _install.sub_commands + ['cmd']
+
+setup(cmdclass={'install': install})
+"""
+
+setup_within_if_main = """\
+from distutils.core import setup
+
+def main():
+ return setup(name="setup_within_if_main")
+
+if __name__ == "__main__":
+ main()
+"""
+
+
+@pytest.fixture(autouse=True)
+def save_stdout(monkeypatch):
+ monkeypatch.setattr(sys, 'stdout', sys.stdout)
+
+
+@pytest.fixture
+def temp_file(tmp_path):
+ return tmp_path / 'file'
+
+
+@pytest.mark.usefixtures('save_env')
+@pytest.mark.usefixtures('save_argv')
+class TestCore:
+ def test_run_setup_provides_file(self, temp_file):
+ # Make sure the script can use __file__; if that's missing, the test
+ # setup.py script will raise NameError.
+ temp_file.write_text(setup_using___file__, encoding='utf-8')
+ distutils.core.run_setup(temp_file)
+
+ def test_run_setup_preserves_sys_argv(self, temp_file):
+ # Make sure run_setup does not clobber sys.argv
+ argv_copy = sys.argv.copy()
+ temp_file.write_text(setup_does_nothing, encoding='utf-8')
+ distutils.core.run_setup(temp_file)
+ assert sys.argv == argv_copy
+
+ def test_run_setup_defines_subclass(self, temp_file):
+ # Make sure the script can use __file__; if that's missing, the test
+ # setup.py script will raise NameError.
+ temp_file.write_text(setup_defines_subclass, encoding='utf-8')
+ dist = distutils.core.run_setup(temp_file)
+ install = dist.get_command_obj('install')
+ assert 'cmd' in install.sub_commands
+
+ def test_run_setup_uses_current_dir(self, tmp_path):
+ """
+ Test that the setup script is run with the current directory
+ as its own current directory.
+ """
+ sys.stdout = io.StringIO()
+ cwd = os.getcwd()
+
+ # Create a directory and write the setup.py file there:
+ setup_py = tmp_path / 'setup.py'
+ setup_py.write_text(setup_prints_cwd, encoding='utf-8')
+ distutils.core.run_setup(setup_py)
+
+ output = sys.stdout.getvalue()
+ if output.endswith("\n"):
+ output = output[:-1]
+ assert cwd == output
+
+ def test_run_setup_within_if_main(self, temp_file):
+ temp_file.write_text(setup_within_if_main, encoding='utf-8')
+ dist = distutils.core.run_setup(temp_file, stop_after="config")
+ assert isinstance(dist, Distribution)
+ assert dist.get_name() == "setup_within_if_main"
+
+ def test_run_commands(self, temp_file):
+ sys.argv = ['setup.py', 'build']
+ temp_file.write_text(setup_within_if_main, encoding='utf-8')
+ dist = distutils.core.run_setup(temp_file, stop_after="commandline")
+ assert 'build' not in dist.have_run
+ distutils.core.run_commands(dist)
+ assert 'build' in dist.have_run
+
+ def test_debug_mode(self, capsys, monkeypatch):
+ # this covers the code called when DEBUG is set
+ sys.argv = ['setup.py', '--name']
+ distutils.core.setup(name='bar')
+ assert capsys.readouterr().out == 'bar\n'
+ monkeypatch.setattr(distutils.core, 'DEBUG', True)
+ distutils.core.setup(name='bar')
+ wanted = "options (after parsing config files):\n"
+ assert capsys.readouterr().out.startswith(wanted)
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_dir_util.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_dir_util.py
new file mode 100644
index 00000000..326cb346
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_dir_util.py
@@ -0,0 +1,139 @@
+"""Tests for distutils.dir_util."""
+
+import os
+import pathlib
+import stat
+import sys
+import unittest.mock as mock
+from distutils import dir_util, errors
+from distutils.dir_util import (
+ copy_tree,
+ create_tree,
+ ensure_relative,
+ mkpath,
+ remove_tree,
+)
+from distutils.tests import support
+
+import jaraco.path
+import path
+import pytest
+
+
+@pytest.fixture(autouse=True)
+def stuff(request, monkeypatch, distutils_managed_tempdir):
+ self = request.instance
+ tmp_dir = self.mkdtemp()
+ self.root_target = os.path.join(tmp_dir, 'deep')
+ self.target = os.path.join(self.root_target, 'here')
+ self.target2 = os.path.join(tmp_dir, 'deep2')
+
+
+class TestDirUtil(support.TempdirManager):
+ def test_mkpath_remove_tree_verbosity(self, caplog):
+ mkpath(self.target, verbose=False)
+ assert not caplog.records
+ remove_tree(self.root_target, verbose=False)
+
+ mkpath(self.target, verbose=True)
+ wanted = [f'creating {self.target}']
+ assert caplog.messages == wanted
+ caplog.clear()
+
+ remove_tree(self.root_target, verbose=True)
+ wanted = [f"removing '{self.root_target}' (and everything under it)"]
+ assert caplog.messages == wanted
+
+ @pytest.mark.skipif("platform.system() == 'Windows'")
+ def test_mkpath_with_custom_mode(self):
+ # Get and set the current umask value for testing mode bits.
+ umask = os.umask(0o002)
+ os.umask(umask)
+ mkpath(self.target, 0o700)
+ assert stat.S_IMODE(os.stat(self.target).st_mode) == 0o700 & ~umask
+ mkpath(self.target2, 0o555)
+ assert stat.S_IMODE(os.stat(self.target2).st_mode) == 0o555 & ~umask
+
+ def test_create_tree_verbosity(self, caplog):
+ create_tree(self.root_target, ['one', 'two', 'three'], verbose=False)
+ assert caplog.messages == []
+ remove_tree(self.root_target, verbose=False)
+
+ wanted = [f'creating {self.root_target}']
+ create_tree(self.root_target, ['one', 'two', 'three'], verbose=True)
+ assert caplog.messages == wanted
+
+ remove_tree(self.root_target, verbose=False)
+
+ def test_copy_tree_verbosity(self, caplog):
+ mkpath(self.target, verbose=False)
+
+ copy_tree(self.target, self.target2, verbose=False)
+ assert caplog.messages == []
+
+ remove_tree(self.root_target, verbose=False)
+
+ mkpath(self.target, verbose=False)
+ a_file = path.Path(self.target) / 'ok.txt'
+ jaraco.path.build({'ok.txt': 'some content'}, self.target)
+
+ wanted = [f'copying {a_file} -> {self.target2}']
+ copy_tree(self.target, self.target2, verbose=True)
+ assert caplog.messages == wanted
+
+ remove_tree(self.root_target, verbose=False)
+ remove_tree(self.target2, verbose=False)
+
+ def test_copy_tree_skips_nfs_temp_files(self):
+ mkpath(self.target, verbose=False)
+
+ jaraco.path.build({'ok.txt': 'some content', '.nfs123abc': ''}, self.target)
+
+ copy_tree(self.target, self.target2)
+ assert os.listdir(self.target2) == ['ok.txt']
+
+ remove_tree(self.root_target, verbose=False)
+ remove_tree(self.target2, verbose=False)
+
+ def test_ensure_relative(self):
+ if os.sep == '/':
+ assert ensure_relative('/home/foo') == 'home/foo'
+ assert ensure_relative('some/path') == 'some/path'
+ else: # \\
+ assert ensure_relative('c:\\home\\foo') == 'c:home\\foo'
+ assert ensure_relative('home\\foo') == 'home\\foo'
+
+ def test_copy_tree_exception_in_listdir(self):
+ """
+ An exception in listdir should raise a DistutilsFileError
+ """
+ with (
+ mock.patch("os.listdir", side_effect=OSError()),
+ pytest.raises(errors.DistutilsFileError),
+ ):
+ src = self.tempdirs[-1]
+ dir_util.copy_tree(src, None)
+
+ def test_mkpath_exception_uncached(self, monkeypatch, tmp_path):
+ """
+ Caching should not remember failed attempts.
+
+ pypa/distutils#304
+ """
+
+ class FailPath(pathlib.Path):
+ def mkdir(self, *args, **kwargs):
+ raise OSError("Failed to create directory")
+
+ if sys.version_info < (3, 12):
+ _flavour = pathlib.Path()._flavour
+
+ target = tmp_path / 'foodir'
+
+ with pytest.raises(errors.DistutilsFileError):
+ mkpath(FailPath(target))
+
+ assert not target.exists()
+
+ mkpath(target)
+ assert target.exists()
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_dist.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_dist.py
new file mode 100644
index 00000000..2c5beebe
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_dist.py
@@ -0,0 +1,552 @@
+"""Tests for distutils.dist."""
+
+import email
+import email.generator
+import email.policy
+import functools
+import io
+import os
+import sys
+import textwrap
+import unittest.mock as mock
+import warnings
+from distutils.cmd import Command
+from distutils.dist import Distribution, fix_help_options
+from distutils.tests import support
+from typing import ClassVar
+
+import jaraco.path
+import pytest
+
+pydistutils_cfg = '.' * (os.name == 'posix') + 'pydistutils.cfg'
+
+
+class test_dist(Command):
+ """Sample distutils extension command."""
+
+ user_options: ClassVar[list[tuple[str, str, str]]] = [
+ ("sample-option=", "S", "help text"),
+ ]
+
+ def initialize_options(self):
+ self.sample_option = None
+
+
+class TestDistribution(Distribution):
+ """Distribution subclasses that avoids the default search for
+ configuration files.
+
+ The ._config_files attribute must be set before
+ .parse_config_files() is called.
+ """
+
+ def find_config_files(self):
+ return self._config_files
+
+
+@pytest.fixture
+def clear_argv():
+ del sys.argv[1:]
+
+
+@support.combine_markers
+@pytest.mark.usefixtures('save_env')
+@pytest.mark.usefixtures('save_argv')
+class TestDistributionBehavior(support.TempdirManager):
+ def create_distribution(self, configfiles=()):
+ d = TestDistribution()
+ d._config_files = configfiles
+ d.parse_config_files()
+ d.parse_command_line()
+ return d
+
+ def test_command_packages_unspecified(self, clear_argv):
+ sys.argv.append("build")
+ d = self.create_distribution()
+ assert d.get_command_packages() == ["distutils.command"]
+
+ def test_command_packages_cmdline(self, clear_argv):
+ from distutils.tests.test_dist import test_dist
+
+ sys.argv.extend([
+ "--command-packages",
+ "foo.bar,distutils.tests",
+ "test_dist",
+ "-Ssometext",
+ ])
+ d = self.create_distribution()
+ # let's actually try to load our test command:
+ assert d.get_command_packages() == [
+ "distutils.command",
+ "foo.bar",
+ "distutils.tests",
+ ]
+ cmd = d.get_command_obj("test_dist")
+ assert isinstance(cmd, test_dist)
+ assert cmd.sample_option == "sometext"
+
+ @pytest.mark.skipif(
+ 'distutils' not in Distribution.parse_config_files.__module__,
+ reason='Cannot test when virtualenv has monkey-patched Distribution',
+ )
+ def test_venv_install_options(self, tmp_path, clear_argv):
+ sys.argv.append("install")
+ file = str(tmp_path / 'file')
+
+ fakepath = '/somedir'
+
+ jaraco.path.build({
+ file: f"""
+ [install]
+ install-base = {fakepath}
+ install-platbase = {fakepath}
+ install-lib = {fakepath}
+ install-platlib = {fakepath}
+ install-purelib = {fakepath}
+ install-headers = {fakepath}
+ install-scripts = {fakepath}
+ install-data = {fakepath}
+ prefix = {fakepath}
+ exec-prefix = {fakepath}
+ home = {fakepath}
+ user = {fakepath}
+ root = {fakepath}
+ """,
+ })
+
+ # Base case: Not in a Virtual Environment
+ with mock.patch.multiple(sys, prefix='/a', base_prefix='/a'):
+ d = self.create_distribution([file])
+
+ option_tuple = (file, fakepath)
+
+ result_dict = {
+ 'install_base': option_tuple,
+ 'install_platbase': option_tuple,
+ 'install_lib': option_tuple,
+ 'install_platlib': option_tuple,
+ 'install_purelib': option_tuple,
+ 'install_headers': option_tuple,
+ 'install_scripts': option_tuple,
+ 'install_data': option_tuple,
+ 'prefix': option_tuple,
+ 'exec_prefix': option_tuple,
+ 'home': option_tuple,
+ 'user': option_tuple,
+ 'root': option_tuple,
+ }
+
+ assert sorted(d.command_options.get('install').keys()) == sorted(
+ result_dict.keys()
+ )
+
+ for key, value in d.command_options.get('install').items():
+ assert value == result_dict[key]
+
+ # Test case: In a Virtual Environment
+ with mock.patch.multiple(sys, prefix='/a', base_prefix='/b'):
+ d = self.create_distribution([file])
+
+ for key in result_dict.keys():
+ assert key not in d.command_options.get('install', {})
+
+ def test_command_packages_configfile(self, tmp_path, clear_argv):
+ sys.argv.append("build")
+ file = str(tmp_path / "file")
+ jaraco.path.build({
+ file: """
+ [global]
+ command_packages = foo.bar, splat
+ """,
+ })
+
+ d = self.create_distribution([file])
+ assert d.get_command_packages() == ["distutils.command", "foo.bar", "splat"]
+
+ # ensure command line overrides config:
+ sys.argv[1:] = ["--command-packages", "spork", "build"]
+ d = self.create_distribution([file])
+ assert d.get_command_packages() == ["distutils.command", "spork"]
+
+ # Setting --command-packages to '' should cause the default to
+ # be used even if a config file specified something else:
+ sys.argv[1:] = ["--command-packages", "", "build"]
+ d = self.create_distribution([file])
+ assert d.get_command_packages() == ["distutils.command"]
+
+ def test_empty_options(self, request):
+ # an empty options dictionary should not stay in the
+ # list of attributes
+
+ # catching warnings
+ warns = []
+
+ def _warn(msg):
+ warns.append(msg)
+
+ request.addfinalizer(
+ functools.partial(setattr, warnings, 'warn', warnings.warn)
+ )
+ warnings.warn = _warn
+ dist = Distribution(
+ attrs={
+ 'author': 'xxx',
+ 'name': 'xxx',
+ 'version': 'xxx',
+ 'url': 'xxxx',
+ 'options': {},
+ }
+ )
+
+ assert len(warns) == 0
+ assert 'options' not in dir(dist)
+
+ def test_finalize_options(self):
+ attrs = {'keywords': 'one,two', 'platforms': 'one,two'}
+
+ dist = Distribution(attrs=attrs)
+ dist.finalize_options()
+
+ # finalize_option splits platforms and keywords
+ assert dist.metadata.platforms == ['one', 'two']
+ assert dist.metadata.keywords == ['one', 'two']
+
+ attrs = {'keywords': 'foo bar', 'platforms': 'foo bar'}
+ dist = Distribution(attrs=attrs)
+ dist.finalize_options()
+ assert dist.metadata.platforms == ['foo bar']
+ assert dist.metadata.keywords == ['foo bar']
+
+ def test_get_command_packages(self):
+ dist = Distribution()
+ assert dist.command_packages is None
+ cmds = dist.get_command_packages()
+ assert cmds == ['distutils.command']
+ assert dist.command_packages == ['distutils.command']
+
+ dist.command_packages = 'one,two'
+ cmds = dist.get_command_packages()
+ assert cmds == ['distutils.command', 'one', 'two']
+
+ def test_announce(self):
+ # make sure the level is known
+ dist = Distribution()
+ with pytest.raises(TypeError):
+ dist.announce('ok', level='ok2')
+
+ def test_find_config_files_disable(self, temp_home):
+ # Ticket #1180: Allow user to disable their home config file.
+ jaraco.path.build({pydistutils_cfg: '[distutils]\n'}, temp_home)
+
+ d = Distribution()
+ all_files = d.find_config_files()
+
+ d = Distribution(attrs={'script_args': ['--no-user-cfg']})
+ files = d.find_config_files()
+
+ # make sure --no-user-cfg disables the user cfg file
+ assert len(all_files) - 1 == len(files)
+
+ def test_script_args_list_coercion(self):
+ d = Distribution(attrs={'script_args': ('build', '--no-user-cfg')})
+
+ # make sure script_args is a list even if it started as a different iterable
+ assert d.script_args == ['build', '--no-user-cfg']
+
+ @pytest.mark.skipif(
+ 'platform.system() == "Windows"',
+ reason='Windows does not honor chmod 000',
+ )
+ def test_find_config_files_permission_error(self, fake_home):
+ """
+ Finding config files should not fail when directory is inaccessible.
+ """
+ fake_home.joinpath(pydistutils_cfg).write_text('', encoding='utf-8')
+ fake_home.chmod(0o000)
+ Distribution().find_config_files()
+
+
+@pytest.mark.usefixtures('save_env')
+@pytest.mark.usefixtures('save_argv')
+class TestMetadata(support.TempdirManager):
+ def format_metadata(self, dist):
+ sio = io.StringIO()
+ dist.metadata.write_pkg_file(sio)
+ return sio.getvalue()
+
+ def test_simple_metadata(self):
+ attrs = {"name": "package", "version": "1.0"}
+ dist = Distribution(attrs)
+ meta = self.format_metadata(dist)
+ assert "Metadata-Version: 1.0" in meta
+ assert "provides:" not in meta.lower()
+ assert "requires:" not in meta.lower()
+ assert "obsoletes:" not in meta.lower()
+
+ def test_provides(self):
+ attrs = {
+ "name": "package",
+ "version": "1.0",
+ "provides": ["package", "package.sub"],
+ }
+ dist = Distribution(attrs)
+ assert dist.metadata.get_provides() == ["package", "package.sub"]
+ assert dist.get_provides() == ["package", "package.sub"]
+ meta = self.format_metadata(dist)
+ assert "Metadata-Version: 1.1" in meta
+ assert "requires:" not in meta.lower()
+ assert "obsoletes:" not in meta.lower()
+
+ def test_provides_illegal(self):
+ with pytest.raises(ValueError):
+ Distribution(
+ {"name": "package", "version": "1.0", "provides": ["my.pkg (splat)"]},
+ )
+
+ def test_requires(self):
+ attrs = {
+ "name": "package",
+ "version": "1.0",
+ "requires": ["other", "another (==1.0)"],
+ }
+ dist = Distribution(attrs)
+ assert dist.metadata.get_requires() == ["other", "another (==1.0)"]
+ assert dist.get_requires() == ["other", "another (==1.0)"]
+ meta = self.format_metadata(dist)
+ assert "Metadata-Version: 1.1" in meta
+ assert "provides:" not in meta.lower()
+ assert "Requires: other" in meta
+ assert "Requires: another (==1.0)" in meta
+ assert "obsoletes:" not in meta.lower()
+
+ def test_requires_illegal(self):
+ with pytest.raises(ValueError):
+ Distribution(
+ {"name": "package", "version": "1.0", "requires": ["my.pkg (splat)"]},
+ )
+
+ def test_requires_to_list(self):
+ attrs = {"name": "package", "requires": iter(["other"])}
+ dist = Distribution(attrs)
+ assert isinstance(dist.metadata.requires, list)
+
+ def test_obsoletes(self):
+ attrs = {
+ "name": "package",
+ "version": "1.0",
+ "obsoletes": ["other", "another (<1.0)"],
+ }
+ dist = Distribution(attrs)
+ assert dist.metadata.get_obsoletes() == ["other", "another (<1.0)"]
+ assert dist.get_obsoletes() == ["other", "another (<1.0)"]
+ meta = self.format_metadata(dist)
+ assert "Metadata-Version: 1.1" in meta
+ assert "provides:" not in meta.lower()
+ assert "requires:" not in meta.lower()
+ assert "Obsoletes: other" in meta
+ assert "Obsoletes: another (<1.0)" in meta
+
+ def test_obsoletes_illegal(self):
+ with pytest.raises(ValueError):
+ Distribution(
+ {"name": "package", "version": "1.0", "obsoletes": ["my.pkg (splat)"]},
+ )
+
+ def test_obsoletes_to_list(self):
+ attrs = {"name": "package", "obsoletes": iter(["other"])}
+ dist = Distribution(attrs)
+ assert isinstance(dist.metadata.obsoletes, list)
+
+ def test_classifier(self):
+ attrs = {
+ 'name': 'Boa',
+ 'version': '3.0',
+ 'classifiers': ['Programming Language :: Python :: 3'],
+ }
+ dist = Distribution(attrs)
+ assert dist.get_classifiers() == ['Programming Language :: Python :: 3']
+ meta = self.format_metadata(dist)
+ assert 'Metadata-Version: 1.1' in meta
+
+ def test_classifier_invalid_type(self, caplog):
+ attrs = {
+ 'name': 'Boa',
+ 'version': '3.0',
+ 'classifiers': ('Programming Language :: Python :: 3',),
+ }
+ d = Distribution(attrs)
+ # should have warning about passing a non-list
+ assert 'should be a list' in caplog.messages[0]
+ # should be converted to a list
+ assert isinstance(d.metadata.classifiers, list)
+ assert d.metadata.classifiers == list(attrs['classifiers'])
+
+ def test_keywords(self):
+ attrs = {
+ 'name': 'Monty',
+ 'version': '1.0',
+ 'keywords': ['spam', 'eggs', 'life of brian'],
+ }
+ dist = Distribution(attrs)
+ assert dist.get_keywords() == ['spam', 'eggs', 'life of brian']
+
+ def test_keywords_invalid_type(self, caplog):
+ attrs = {
+ 'name': 'Monty',
+ 'version': '1.0',
+ 'keywords': ('spam', 'eggs', 'life of brian'),
+ }
+ d = Distribution(attrs)
+ # should have warning about passing a non-list
+ assert 'should be a list' in caplog.messages[0]
+ # should be converted to a list
+ assert isinstance(d.metadata.keywords, list)
+ assert d.metadata.keywords == list(attrs['keywords'])
+
+ def test_platforms(self):
+ attrs = {
+ 'name': 'Monty',
+ 'version': '1.0',
+ 'platforms': ['GNU/Linux', 'Some Evil Platform'],
+ }
+ dist = Distribution(attrs)
+ assert dist.get_platforms() == ['GNU/Linux', 'Some Evil Platform']
+
+ def test_platforms_invalid_types(self, caplog):
+ attrs = {
+ 'name': 'Monty',
+ 'version': '1.0',
+ 'platforms': ('GNU/Linux', 'Some Evil Platform'),
+ }
+ d = Distribution(attrs)
+ # should have warning about passing a non-list
+ assert 'should be a list' in caplog.messages[0]
+ # should be converted to a list
+ assert isinstance(d.metadata.platforms, list)
+ assert d.metadata.platforms == list(attrs['platforms'])
+
+ def test_download_url(self):
+ attrs = {
+ 'name': 'Boa',
+ 'version': '3.0',
+ 'download_url': 'http://example.org/boa',
+ }
+ dist = Distribution(attrs)
+ meta = self.format_metadata(dist)
+ assert 'Metadata-Version: 1.1' in meta
+
+ def test_long_description(self):
+ long_desc = textwrap.dedent(
+ """\
+ example::
+ We start here
+ and continue here
+ and end here."""
+ )
+ attrs = {"name": "package", "version": "1.0", "long_description": long_desc}
+
+ dist = Distribution(attrs)
+ meta = self.format_metadata(dist)
+ meta = meta.replace('\n' + 8 * ' ', '\n')
+ assert long_desc in meta
+
+ def test_custom_pydistutils(self, temp_home):
+ """
+ pydistutils.cfg is found
+ """
+ jaraco.path.build({pydistutils_cfg: ''}, temp_home)
+ config_path = temp_home / pydistutils_cfg
+
+ assert str(config_path) in Distribution().find_config_files()
+
+ def test_extra_pydistutils(self, monkeypatch, tmp_path):
+ jaraco.path.build({'overrides.cfg': ''}, tmp_path)
+ filename = tmp_path / 'overrides.cfg'
+ monkeypatch.setenv('DIST_EXTRA_CONFIG', str(filename))
+ assert str(filename) in Distribution().find_config_files()
+
+ def test_fix_help_options(self):
+ help_tuples = [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
+ fancy_options = fix_help_options(help_tuples)
+ assert fancy_options[0] == ('a', 'b', 'c')
+ assert fancy_options[1] == (1, 2, 3)
+
+ def test_show_help(self, request, capsys):
+ # smoke test, just makes sure some help is displayed
+ dist = Distribution()
+ sys.argv = []
+ dist.help = True
+ dist.script_name = 'setup.py'
+ dist.parse_command_line()
+
+ output = [
+ line for line in capsys.readouterr().out.split('\n') if line.strip() != ''
+ ]
+ assert output
+
+ def test_read_metadata(self):
+ attrs = {
+ "name": "package",
+ "version": "1.0",
+ "long_description": "desc",
+ "description": "xxx",
+ "download_url": "http://example.com",
+ "keywords": ['one', 'two'],
+ "requires": ['foo'],
+ }
+
+ dist = Distribution(attrs)
+ metadata = dist.metadata
+
+ # write it then reloads it
+ PKG_INFO = io.StringIO()
+ metadata.write_pkg_file(PKG_INFO)
+ PKG_INFO.seek(0)
+ metadata.read_pkg_file(PKG_INFO)
+
+ assert metadata.name == "package"
+ assert metadata.version == "1.0"
+ assert metadata.description == "xxx"
+ assert metadata.download_url == 'http://example.com'
+ assert metadata.keywords == ['one', 'two']
+ assert metadata.platforms is None
+ assert metadata.obsoletes is None
+ assert metadata.requires == ['foo']
+
+ def test_round_trip_through_email_generator(self):
+ """
+ In pypa/setuptools#4033, it was shown that once PKG-INFO is
+ re-generated using ``email.generator.Generator``, some control
+ characters might cause problems.
+ """
+ # Given a PKG-INFO file ...
+ attrs = {
+ "name": "package",
+ "version": "1.0",
+ "long_description": "hello\x0b\nworld\n",
+ }
+ dist = Distribution(attrs)
+ metadata = dist.metadata
+
+ with io.StringIO() as buffer:
+ metadata.write_pkg_file(buffer)
+ msg = buffer.getvalue()
+
+ # ... when it is read and re-written using stdlib's email library,
+ orig = email.message_from_string(msg)
+ policy = email.policy.EmailPolicy(
+ utf8=True,
+ mangle_from_=False,
+ max_line_length=0,
+ )
+ with io.StringIO() as buffer:
+ email.generator.Generator(buffer, policy=policy).flatten(orig)
+
+ buffer.seek(0)
+ regen = email.message_from_file(buffer)
+
+ # ... then it should be the same as the original
+ # (except for the specific line break characters)
+ orig_desc = set(orig["Description"].splitlines())
+ regen_desc = set(regen["Description"].splitlines())
+ assert regen_desc == orig_desc
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_extension.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_extension.py
new file mode 100644
index 00000000..5e8e7682
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_extension.py
@@ -0,0 +1,117 @@
+"""Tests for distutils.extension."""
+
+import os
+import pathlib
+import warnings
+from distutils.extension import Extension, read_setup_file
+
+import pytest
+from test.support.warnings_helper import check_warnings
+
+
+class TestExtension:
+ def test_read_setup_file(self):
+ # trying to read a Setup file
+ # (sample extracted from the PyGame project)
+ setup = os.path.join(os.path.dirname(__file__), 'Setup.sample')
+
+ exts = read_setup_file(setup)
+ names = [ext.name for ext in exts]
+ names.sort()
+
+ # here are the extensions read_setup_file should have created
+ # out of the file
+ wanted = [
+ '_arraysurfarray',
+ '_camera',
+ '_numericsndarray',
+ '_numericsurfarray',
+ 'base',
+ 'bufferproxy',
+ 'cdrom',
+ 'color',
+ 'constants',
+ 'display',
+ 'draw',
+ 'event',
+ 'fastevent',
+ 'font',
+ 'gfxdraw',
+ 'image',
+ 'imageext',
+ 'joystick',
+ 'key',
+ 'mask',
+ 'mixer',
+ 'mixer_music',
+ 'mouse',
+ 'movie',
+ 'overlay',
+ 'pixelarray',
+ 'pypm',
+ 'rect',
+ 'rwobject',
+ 'scrap',
+ 'surface',
+ 'surflock',
+ 'time',
+ 'transform',
+ ]
+
+ assert names == wanted
+
+ def test_extension_init(self):
+ # the first argument, which is the name, must be a string
+ with pytest.raises(TypeError):
+ Extension(1, [])
+ ext = Extension('name', [])
+ assert ext.name == 'name'
+
+ # the second argument, which is the list of files, must
+ # be an iterable of strings or PathLike objects, and not a string
+ with pytest.raises(TypeError):
+ Extension('name', 'file')
+ with pytest.raises(TypeError):
+ Extension('name', ['file', 1])
+ ext = Extension('name', ['file1', 'file2'])
+ assert ext.sources == ['file1', 'file2']
+ ext = Extension('name', [pathlib.Path('file1'), pathlib.Path('file2')])
+ assert ext.sources == ['file1', 'file2']
+
+ # any non-string iterable of strings or PathLike objects should work
+ ext = Extension('name', ('file1', 'file2')) # tuple
+ assert ext.sources == ['file1', 'file2']
+ ext = Extension('name', {'file1', 'file2'}) # set
+ assert sorted(ext.sources) == ['file1', 'file2']
+ ext = Extension('name', iter(['file1', 'file2'])) # iterator
+ assert ext.sources == ['file1', 'file2']
+ ext = Extension('name', [pathlib.Path('file1'), 'file2']) # mixed types
+ assert ext.sources == ['file1', 'file2']
+
+ # others arguments have defaults
+ for attr in (
+ 'include_dirs',
+ 'define_macros',
+ 'undef_macros',
+ 'library_dirs',
+ 'libraries',
+ 'runtime_library_dirs',
+ 'extra_objects',
+ 'extra_compile_args',
+ 'extra_link_args',
+ 'export_symbols',
+ 'swig_opts',
+ 'depends',
+ ):
+ assert getattr(ext, attr) == []
+
+ assert ext.language is None
+ assert ext.optional is None
+
+ # if there are unknown keyword options, warn about them
+ with check_warnings() as w:
+ warnings.simplefilter('always')
+ ext = Extension('name', ['file1', 'file2'], chic=True)
+
+ assert len(w.warnings) == 1
+ assert str(w.warnings[0].message) == "Unknown Extension options: 'chic'"
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_file_util.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_file_util.py
new file mode 100644
index 00000000..a75d4a03
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_file_util.py
@@ -0,0 +1,95 @@
+"""Tests for distutils.file_util."""
+
+import errno
+import os
+import unittest.mock as mock
+from distutils.errors import DistutilsFileError
+from distutils.file_util import copy_file, move_file
+
+import jaraco.path
+import pytest
+
+
+@pytest.fixture(autouse=True)
+def stuff(request, tmp_path):
+ self = request.instance
+ self.source = tmp_path / 'f1'
+ self.target = tmp_path / 'f2'
+ self.target_dir = tmp_path / 'd1'
+
+
+class TestFileUtil:
+ def test_move_file_verbosity(self, caplog):
+ jaraco.path.build({self.source: 'some content'})
+
+ move_file(self.source, self.target, verbose=False)
+ assert not caplog.messages
+
+ # back to original state
+ move_file(self.target, self.source, verbose=False)
+
+ move_file(self.source, self.target, verbose=True)
+ wanted = [f'moving {self.source} -> {self.target}']
+ assert caplog.messages == wanted
+
+ # back to original state
+ move_file(self.target, self.source, verbose=False)
+
+ caplog.clear()
+ # now the target is a dir
+ os.mkdir(self.target_dir)
+ move_file(self.source, self.target_dir, verbose=True)
+ wanted = [f'moving {self.source} -> {self.target_dir}']
+ assert caplog.messages == wanted
+
+ def test_move_file_exception_unpacking_rename(self):
+ # see issue 22182
+ with (
+ mock.patch("os.rename", side_effect=OSError("wrong", 1)),
+ pytest.raises(DistutilsFileError),
+ ):
+ jaraco.path.build({self.source: 'spam eggs'})
+ move_file(self.source, self.target, verbose=False)
+
+ def test_move_file_exception_unpacking_unlink(self):
+ # see issue 22182
+ with (
+ mock.patch("os.rename", side_effect=OSError(errno.EXDEV, "wrong")),
+ mock.patch("os.unlink", side_effect=OSError("wrong", 1)),
+ pytest.raises(DistutilsFileError),
+ ):
+ jaraco.path.build({self.source: 'spam eggs'})
+ move_file(self.source, self.target, verbose=False)
+
+ def test_copy_file_hard_link(self):
+ jaraco.path.build({self.source: 'some content'})
+ # Check first that copy_file() will not fall back on copying the file
+ # instead of creating the hard link.
+ try:
+ os.link(self.source, self.target)
+ except OSError as e:
+ self.skipTest(f'os.link: {e}')
+ else:
+ self.target.unlink()
+ st = os.stat(self.source)
+ copy_file(self.source, self.target, link='hard')
+ st2 = os.stat(self.source)
+ st3 = os.stat(self.target)
+ assert os.path.samestat(st, st2), (st, st2)
+ assert os.path.samestat(st2, st3), (st2, st3)
+ assert self.source.read_text(encoding='utf-8') == 'some content'
+
+ def test_copy_file_hard_link_failure(self):
+ # If hard linking fails, copy_file() falls back on copying file
+ # (some special filesystems don't support hard linking even under
+ # Unix, see issue #8876).
+ jaraco.path.build({self.source: 'some content'})
+ st = os.stat(self.source)
+ with mock.patch("os.link", side_effect=OSError(0, "linking unsupported")):
+ copy_file(self.source, self.target, link='hard')
+ st2 = os.stat(self.source)
+ st3 = os.stat(self.target)
+ assert os.path.samestat(st, st2), (st, st2)
+ assert not os.path.samestat(st2, st3), (st2, st3)
+ for fn in (self.source, self.target):
+ assert fn.read_text(encoding='utf-8') == 'some content'
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_filelist.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_filelist.py
new file mode 100644
index 00000000..130e6fb5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_filelist.py
@@ -0,0 +1,336 @@
+"""Tests for distutils.filelist."""
+
+import logging
+import os
+import re
+from distutils import debug, filelist
+from distutils.errors import DistutilsTemplateError
+from distutils.filelist import FileList, glob_to_re, translate_pattern
+
+import jaraco.path
+import pytest
+
+from .compat import py39 as os_helper
+
+MANIFEST_IN = """\
+include ok
+include xo
+exclude xo
+include foo.tmp
+include buildout.cfg
+global-include *.x
+global-include *.txt
+global-exclude *.tmp
+recursive-include f *.oo
+recursive-exclude global *.x
+graft dir
+prune dir3
+"""
+
+
+def make_local_path(s):
+ """Converts '/' in a string to os.sep"""
+ return s.replace('/', os.sep)
+
+
+class TestFileList:
+ def assertNoWarnings(self, caplog):
+ warnings = [rec for rec in caplog.records if rec.levelno == logging.WARNING]
+ assert not warnings
+ caplog.clear()
+
+ def assertWarnings(self, caplog):
+ warnings = [rec for rec in caplog.records if rec.levelno == logging.WARNING]
+ assert warnings
+ caplog.clear()
+
+ def test_glob_to_re(self):
+ sep = os.sep
+ if os.sep == '\\':
+ sep = re.escape(os.sep)
+
+ for glob, regex in (
+ # simple cases
+ ('foo*', r'(?s:foo[^%(sep)s]*)\Z'),
+ ('foo?', r'(?s:foo[^%(sep)s])\Z'),
+ ('foo??', r'(?s:foo[^%(sep)s][^%(sep)s])\Z'),
+ # special cases
+ (r'foo\\*', r'(?s:foo\\\\[^%(sep)s]*)\Z'),
+ (r'foo\\\*', r'(?s:foo\\\\\\[^%(sep)s]*)\Z'),
+ ('foo????', r'(?s:foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s])\Z'),
+ (r'foo\\??', r'(?s:foo\\\\[^%(sep)s][^%(sep)s])\Z'),
+ ):
+ regex = regex % {'sep': sep}
+ assert glob_to_re(glob) == regex
+
+ def test_process_template_line(self):
+ # testing all MANIFEST.in template patterns
+ file_list = FileList()
+ mlp = make_local_path
+
+ # simulated file list
+ file_list.allfiles = [
+ 'foo.tmp',
+ 'ok',
+ 'xo',
+ 'four.txt',
+ 'buildout.cfg',
+ # filelist does not filter out VCS directories,
+ # it's sdist that does
+ mlp('.hg/last-message.txt'),
+ mlp('global/one.txt'),
+ mlp('global/two.txt'),
+ mlp('global/files.x'),
+ mlp('global/here.tmp'),
+ mlp('f/o/f.oo'),
+ mlp('dir/graft-one'),
+ mlp('dir/dir2/graft2'),
+ mlp('dir3/ok'),
+ mlp('dir3/sub/ok.txt'),
+ ]
+
+ for line in MANIFEST_IN.split('\n'):
+ if line.strip() == '':
+ continue
+ file_list.process_template_line(line)
+
+ wanted = [
+ 'ok',
+ 'buildout.cfg',
+ 'four.txt',
+ mlp('.hg/last-message.txt'),
+ mlp('global/one.txt'),
+ mlp('global/two.txt'),
+ mlp('f/o/f.oo'),
+ mlp('dir/graft-one'),
+ mlp('dir/dir2/graft2'),
+ ]
+
+ assert file_list.files == wanted
+
+ def test_debug_print(self, capsys, monkeypatch):
+ file_list = FileList()
+ file_list.debug_print('xxx')
+ assert capsys.readouterr().out == ''
+
+ monkeypatch.setattr(debug, 'DEBUG', True)
+ file_list.debug_print('xxx')
+ assert capsys.readouterr().out == 'xxx\n'
+
+ def test_set_allfiles(self):
+ file_list = FileList()
+ files = ['a', 'b', 'c']
+ file_list.set_allfiles(files)
+ assert file_list.allfiles == files
+
+ def test_remove_duplicates(self):
+ file_list = FileList()
+ file_list.files = ['a', 'b', 'a', 'g', 'c', 'g']
+ # files must be sorted beforehand (sdist does it)
+ file_list.sort()
+ file_list.remove_duplicates()
+ assert file_list.files == ['a', 'b', 'c', 'g']
+
+ def test_translate_pattern(self):
+ # not regex
+ assert hasattr(translate_pattern('a', anchor=True, is_regex=False), 'search')
+
+ # is a regex
+ regex = re.compile('a')
+ assert translate_pattern(regex, anchor=True, is_regex=True) == regex
+
+ # plain string flagged as regex
+ assert hasattr(translate_pattern('a', anchor=True, is_regex=True), 'search')
+
+ # glob support
+ assert translate_pattern('*.py', anchor=True, is_regex=False).search(
+ 'filelist.py'
+ )
+
+ def test_exclude_pattern(self):
+ # return False if no match
+ file_list = FileList()
+ assert not file_list.exclude_pattern('*.py')
+
+ # return True if files match
+ file_list = FileList()
+ file_list.files = ['a.py', 'b.py']
+ assert file_list.exclude_pattern('*.py')
+
+ # test excludes
+ file_list = FileList()
+ file_list.files = ['a.py', 'a.txt']
+ file_list.exclude_pattern('*.py')
+ assert file_list.files == ['a.txt']
+
+ def test_include_pattern(self):
+ # return False if no match
+ file_list = FileList()
+ file_list.set_allfiles([])
+ assert not file_list.include_pattern('*.py')
+
+ # return True if files match
+ file_list = FileList()
+ file_list.set_allfiles(['a.py', 'b.txt'])
+ assert file_list.include_pattern('*.py')
+
+ # test * matches all files
+ file_list = FileList()
+ assert file_list.allfiles is None
+ file_list.set_allfiles(['a.py', 'b.txt'])
+ file_list.include_pattern('*')
+ assert file_list.allfiles == ['a.py', 'b.txt']
+
+ def test_process_template(self, caplog):
+ mlp = make_local_path
+ # invalid lines
+ file_list = FileList()
+ for action in (
+ 'include',
+ 'exclude',
+ 'global-include',
+ 'global-exclude',
+ 'recursive-include',
+ 'recursive-exclude',
+ 'graft',
+ 'prune',
+ 'blarg',
+ ):
+ with pytest.raises(DistutilsTemplateError):
+ file_list.process_template_line(action)
+
+ # include
+ file_list = FileList()
+ file_list.set_allfiles(['a.py', 'b.txt', mlp('d/c.py')])
+
+ file_list.process_template_line('include *.py')
+ assert file_list.files == ['a.py']
+ self.assertNoWarnings(caplog)
+
+ file_list.process_template_line('include *.rb')
+ assert file_list.files == ['a.py']
+ self.assertWarnings(caplog)
+
+ # exclude
+ file_list = FileList()
+ file_list.files = ['a.py', 'b.txt', mlp('d/c.py')]
+
+ file_list.process_template_line('exclude *.py')
+ assert file_list.files == ['b.txt', mlp('d/c.py')]
+ self.assertNoWarnings(caplog)
+
+ file_list.process_template_line('exclude *.rb')
+ assert file_list.files == ['b.txt', mlp('d/c.py')]
+ self.assertWarnings(caplog)
+
+ # global-include
+ file_list = FileList()
+ file_list.set_allfiles(['a.py', 'b.txt', mlp('d/c.py')])
+
+ file_list.process_template_line('global-include *.py')
+ assert file_list.files == ['a.py', mlp('d/c.py')]
+ self.assertNoWarnings(caplog)
+
+ file_list.process_template_line('global-include *.rb')
+ assert file_list.files == ['a.py', mlp('d/c.py')]
+ self.assertWarnings(caplog)
+
+ # global-exclude
+ file_list = FileList()
+ file_list.files = ['a.py', 'b.txt', mlp('d/c.py')]
+
+ file_list.process_template_line('global-exclude *.py')
+ assert file_list.files == ['b.txt']
+ self.assertNoWarnings(caplog)
+
+ file_list.process_template_line('global-exclude *.rb')
+ assert file_list.files == ['b.txt']
+ self.assertWarnings(caplog)
+
+ # recursive-include
+ file_list = FileList()
+ file_list.set_allfiles(['a.py', mlp('d/b.py'), mlp('d/c.txt'), mlp('d/d/e.py')])
+
+ file_list.process_template_line('recursive-include d *.py')
+ assert file_list.files == [mlp('d/b.py'), mlp('d/d/e.py')]
+ self.assertNoWarnings(caplog)
+
+ file_list.process_template_line('recursive-include e *.py')
+ assert file_list.files == [mlp('d/b.py'), mlp('d/d/e.py')]
+ self.assertWarnings(caplog)
+
+ # recursive-exclude
+ file_list = FileList()
+ file_list.files = ['a.py', mlp('d/b.py'), mlp('d/c.txt'), mlp('d/d/e.py')]
+
+ file_list.process_template_line('recursive-exclude d *.py')
+ assert file_list.files == ['a.py', mlp('d/c.txt')]
+ self.assertNoWarnings(caplog)
+
+ file_list.process_template_line('recursive-exclude e *.py')
+ assert file_list.files == ['a.py', mlp('d/c.txt')]
+ self.assertWarnings(caplog)
+
+ # graft
+ file_list = FileList()
+ file_list.set_allfiles(['a.py', mlp('d/b.py'), mlp('d/d/e.py'), mlp('f/f.py')])
+
+ file_list.process_template_line('graft d')
+ assert file_list.files == [mlp('d/b.py'), mlp('d/d/e.py')]
+ self.assertNoWarnings(caplog)
+
+ file_list.process_template_line('graft e')
+ assert file_list.files == [mlp('d/b.py'), mlp('d/d/e.py')]
+ self.assertWarnings(caplog)
+
+ # prune
+ file_list = FileList()
+ file_list.files = ['a.py', mlp('d/b.py'), mlp('d/d/e.py'), mlp('f/f.py')]
+
+ file_list.process_template_line('prune d')
+ assert file_list.files == ['a.py', mlp('f/f.py')]
+ self.assertNoWarnings(caplog)
+
+ file_list.process_template_line('prune e')
+ assert file_list.files == ['a.py', mlp('f/f.py')]
+ self.assertWarnings(caplog)
+
+
+class TestFindAll:
+ @os_helper.skip_unless_symlink
+ def test_missing_symlink(self, temp_cwd):
+ os.symlink('foo', 'bar')
+ assert filelist.findall() == []
+
+ def test_basic_discovery(self, temp_cwd):
+ """
+ When findall is called with no parameters or with
+ '.' as the parameter, the dot should be omitted from
+ the results.
+ """
+ jaraco.path.build({'foo': {'file1.txt': ''}, 'bar': {'file2.txt': ''}})
+ file1 = os.path.join('foo', 'file1.txt')
+ file2 = os.path.join('bar', 'file2.txt')
+ expected = [file2, file1]
+ assert sorted(filelist.findall()) == expected
+
+ def test_non_local_discovery(self, tmp_path):
+ """
+ When findall is called with another path, the full
+ path name should be returned.
+ """
+ jaraco.path.build({'file1.txt': ''}, tmp_path)
+ expected = [str(tmp_path / 'file1.txt')]
+ assert filelist.findall(tmp_path) == expected
+
+ @os_helper.skip_unless_symlink
+ def test_symlink_loop(self, tmp_path):
+ jaraco.path.build(
+ {
+ 'link-to-parent': jaraco.path.Symlink('.'),
+ 'somefile': '',
+ },
+ tmp_path,
+ )
+ files = filelist.findall(tmp_path)
+ assert len(files) == 1
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install.py
new file mode 100644
index 00000000..b3ffb2e6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install.py
@@ -0,0 +1,245 @@
+"""Tests for distutils.command.install."""
+
+import logging
+import os
+import pathlib
+import site
+import sys
+from distutils import sysconfig
+from distutils.command import install as install_module
+from distutils.command.build_ext import build_ext
+from distutils.command.install import INSTALL_SCHEMES, install
+from distutils.core import Distribution
+from distutils.errors import DistutilsOptionError
+from distutils.extension import Extension
+from distutils.tests import missing_compiler_executable, support
+from distutils.util import is_mingw
+
+import pytest
+
+
+def _make_ext_name(modname):
+ return modname + sysconfig.get_config_var('EXT_SUFFIX')
+
+
+@support.combine_markers
+@pytest.mark.usefixtures('save_env')
+class TestInstall(
+ support.TempdirManager,
+):
+ @pytest.mark.xfail(
+ 'platform.system() == "Windows" and sys.version_info > (3, 11)',
+ reason="pypa/distutils#148",
+ )
+ def test_home_installation_scheme(self):
+ # This ensure two things:
+ # - that --home generates the desired set of directory names
+ # - test --home is supported on all platforms
+ builddir = self.mkdtemp()
+ destination = os.path.join(builddir, "installation")
+
+ dist = Distribution({"name": "foopkg"})
+ # script_name need not exist, it just need to be initialized
+ dist.script_name = os.path.join(builddir, "setup.py")
+ dist.command_obj["build"] = support.DummyCommand(
+ build_base=builddir,
+ build_lib=os.path.join(builddir, "lib"),
+ )
+
+ cmd = install(dist)
+ cmd.home = destination
+ cmd.ensure_finalized()
+
+ assert cmd.install_base == destination
+ assert cmd.install_platbase == destination
+
+ def check_path(got, expected):
+ got = os.path.normpath(got)
+ expected = os.path.normpath(expected)
+ assert got == expected
+
+ impl_name = sys.implementation.name.replace("cpython", "python")
+ libdir = os.path.join(destination, "lib", impl_name)
+ check_path(cmd.install_lib, libdir)
+ _platlibdir = getattr(sys, "platlibdir", "lib")
+ platlibdir = os.path.join(destination, _platlibdir, impl_name)
+ check_path(cmd.install_platlib, platlibdir)
+ check_path(cmd.install_purelib, libdir)
+ check_path(
+ cmd.install_headers,
+ os.path.join(destination, "include", impl_name, "foopkg"),
+ )
+ check_path(cmd.install_scripts, os.path.join(destination, "bin"))
+ check_path(cmd.install_data, destination)
+
+ def test_user_site(self, monkeypatch):
+ # test install with --user
+ # preparing the environment for the test
+ self.tmpdir = self.mkdtemp()
+ orig_site = site.USER_SITE
+ orig_base = site.USER_BASE
+ monkeypatch.setattr(site, 'USER_BASE', os.path.join(self.tmpdir, 'B'))
+ monkeypatch.setattr(site, 'USER_SITE', os.path.join(self.tmpdir, 'S'))
+ monkeypatch.setattr(install_module, 'USER_BASE', site.USER_BASE)
+ monkeypatch.setattr(install_module, 'USER_SITE', site.USER_SITE)
+
+ def _expanduser(path):
+ if path.startswith('~'):
+ return os.path.normpath(self.tmpdir + path[1:])
+ return path
+
+ monkeypatch.setattr(os.path, 'expanduser', _expanduser)
+
+ for key in ('nt_user', 'posix_user'):
+ assert key in INSTALL_SCHEMES
+
+ dist = Distribution({'name': 'xx'})
+ cmd = install(dist)
+
+ # making sure the user option is there
+ options = [name for name, short, label in cmd.user_options]
+ assert 'user' in options
+
+ # setting a value
+ cmd.user = True
+
+ # user base and site shouldn't be created yet
+ assert not os.path.exists(site.USER_BASE)
+ assert not os.path.exists(site.USER_SITE)
+
+ # let's run finalize
+ cmd.ensure_finalized()
+
+ # now they should
+ assert os.path.exists(site.USER_BASE)
+ assert os.path.exists(site.USER_SITE)
+
+ assert 'userbase' in cmd.config_vars
+ assert 'usersite' in cmd.config_vars
+
+ actual_headers = os.path.relpath(cmd.install_headers, site.USER_BASE)
+ if os.name == 'nt' and not is_mingw():
+ site_path = os.path.relpath(os.path.dirname(orig_site), orig_base)
+ include = os.path.join(site_path, 'Include')
+ else:
+ include = sysconfig.get_python_inc(0, '')
+ expect_headers = os.path.join(include, 'xx')
+
+ assert os.path.normcase(actual_headers) == os.path.normcase(expect_headers)
+
+ def test_handle_extra_path(self):
+ dist = Distribution({'name': 'xx', 'extra_path': 'path,dirs'})
+ cmd = install(dist)
+
+ # two elements
+ cmd.handle_extra_path()
+ assert cmd.extra_path == ['path', 'dirs']
+ assert cmd.extra_dirs == 'dirs'
+ assert cmd.path_file == 'path'
+
+ # one element
+ cmd.extra_path = ['path']
+ cmd.handle_extra_path()
+ assert cmd.extra_path == ['path']
+ assert cmd.extra_dirs == 'path'
+ assert cmd.path_file == 'path'
+
+ # none
+ dist.extra_path = cmd.extra_path = None
+ cmd.handle_extra_path()
+ assert cmd.extra_path is None
+ assert cmd.extra_dirs == ''
+ assert cmd.path_file is None
+
+ # three elements (no way !)
+ cmd.extra_path = 'path,dirs,again'
+ with pytest.raises(DistutilsOptionError):
+ cmd.handle_extra_path()
+
+ def test_finalize_options(self):
+ dist = Distribution({'name': 'xx'})
+ cmd = install(dist)
+
+ # must supply either prefix/exec-prefix/home or
+ # install-base/install-platbase -- not both
+ cmd.prefix = 'prefix'
+ cmd.install_base = 'base'
+ with pytest.raises(DistutilsOptionError):
+ cmd.finalize_options()
+
+ # must supply either home or prefix/exec-prefix -- not both
+ cmd.install_base = None
+ cmd.home = 'home'
+ with pytest.raises(DistutilsOptionError):
+ cmd.finalize_options()
+
+ # can't combine user with prefix/exec_prefix/home or
+ # install_(plat)base
+ cmd.prefix = None
+ cmd.user = 'user'
+ with pytest.raises(DistutilsOptionError):
+ cmd.finalize_options()
+
+ def test_record(self):
+ install_dir = self.mkdtemp()
+ project_dir, dist = self.create_dist(py_modules=['hello'], scripts=['sayhi'])
+ os.chdir(project_dir)
+ self.write_file('hello.py', "def main(): print('o hai')")
+ self.write_file('sayhi', 'from hello import main; main()')
+
+ cmd = install(dist)
+ dist.command_obj['install'] = cmd
+ cmd.root = install_dir
+ cmd.record = os.path.join(project_dir, 'filelist')
+ cmd.ensure_finalized()
+ cmd.run()
+
+ content = pathlib.Path(cmd.record).read_text(encoding='utf-8')
+
+ found = [pathlib.Path(line).name for line in content.splitlines()]
+ expected = [
+ 'hello.py',
+ f'hello.{sys.implementation.cache_tag}.pyc',
+ 'sayhi',
+ 'UNKNOWN-0.0.0-py{}.{}.egg-info'.format(*sys.version_info[:2]),
+ ]
+ assert found == expected
+
+ def test_record_extensions(self):
+ cmd = missing_compiler_executable()
+ if cmd is not None:
+ pytest.skip(f'The {cmd!r} command is not found')
+ install_dir = self.mkdtemp()
+ project_dir, dist = self.create_dist(
+ ext_modules=[Extension('xx', ['xxmodule.c'])]
+ )
+ os.chdir(project_dir)
+ support.copy_xxmodule_c(project_dir)
+
+ buildextcmd = build_ext(dist)
+ support.fixup_build_ext(buildextcmd)
+ buildextcmd.ensure_finalized()
+
+ cmd = install(dist)
+ dist.command_obj['install'] = cmd
+ dist.command_obj['build_ext'] = buildextcmd
+ cmd.root = install_dir
+ cmd.record = os.path.join(project_dir, 'filelist')
+ cmd.ensure_finalized()
+ cmd.run()
+
+ content = pathlib.Path(cmd.record).read_text(encoding='utf-8')
+
+ found = [pathlib.Path(line).name for line in content.splitlines()]
+ expected = [
+ _make_ext_name('xx'),
+ 'UNKNOWN-0.0.0-py{}.{}.egg-info'.format(*sys.version_info[:2]),
+ ]
+ assert found == expected
+
+ def test_debug_mode(self, caplog, monkeypatch):
+ # this covers the code called when DEBUG is set
+ monkeypatch.setattr(install_module, 'DEBUG', True)
+ caplog.set_level(logging.DEBUG)
+ self.test_record()
+ assert any(rec for rec in caplog.records if rec.levelno == logging.DEBUG)
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_data.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_data.py
new file mode 100644
index 00000000..c800f86c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_data.py
@@ -0,0 +1,74 @@
+"""Tests for distutils.command.install_data."""
+
+import os
+import pathlib
+from distutils.command.install_data import install_data
+from distutils.tests import support
+
+import pytest
+
+
+@pytest.mark.usefixtures('save_env')
+class TestInstallData(
+ support.TempdirManager,
+):
+ def test_simple_run(self):
+ pkg_dir, dist = self.create_dist()
+ cmd = install_data(dist)
+ cmd.install_dir = inst = os.path.join(pkg_dir, 'inst')
+
+ # data_files can contain
+ # - simple files
+ # - a Path object
+ # - a tuple with a path, and a list of file
+ one = os.path.join(pkg_dir, 'one')
+ self.write_file(one, 'xxx')
+ inst2 = os.path.join(pkg_dir, 'inst2')
+ two = os.path.join(pkg_dir, 'two')
+ self.write_file(two, 'xxx')
+ three = pathlib.Path(pkg_dir) / 'three'
+ self.write_file(three, 'xxx')
+
+ cmd.data_files = [one, (inst2, [two]), three]
+ assert cmd.get_inputs() == [one, (inst2, [two]), three]
+
+ # let's run the command
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # let's check the result
+ assert len(cmd.get_outputs()) == 3
+ rthree = os.path.split(one)[-1]
+ assert os.path.exists(os.path.join(inst, rthree))
+ rtwo = os.path.split(two)[-1]
+ assert os.path.exists(os.path.join(inst2, rtwo))
+ rone = os.path.split(one)[-1]
+ assert os.path.exists(os.path.join(inst, rone))
+ cmd.outfiles = []
+
+ # let's try with warn_dir one
+ cmd.warn_dir = True
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # let's check the result
+ assert len(cmd.get_outputs()) == 3
+ assert os.path.exists(os.path.join(inst, rthree))
+ assert os.path.exists(os.path.join(inst2, rtwo))
+ assert os.path.exists(os.path.join(inst, rone))
+ cmd.outfiles = []
+
+ # now using root and empty dir
+ cmd.root = os.path.join(pkg_dir, 'root')
+ inst5 = os.path.join(pkg_dir, 'inst5')
+ four = os.path.join(cmd.install_dir, 'four')
+ self.write_file(four, 'xx')
+ cmd.data_files = [one, (inst2, [two]), three, ('inst5', [four]), (inst5, [])]
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # let's check the result
+ assert len(cmd.get_outputs()) == 5
+ assert os.path.exists(os.path.join(inst, rthree))
+ assert os.path.exists(os.path.join(inst2, rtwo))
+ assert os.path.exists(os.path.join(inst, rone))
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_headers.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_headers.py
new file mode 100644
index 00000000..2c74f06b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_headers.py
@@ -0,0 +1,33 @@
+"""Tests for distutils.command.install_headers."""
+
+import os
+from distutils.command.install_headers import install_headers
+from distutils.tests import support
+
+import pytest
+
+
+@pytest.mark.usefixtures('save_env')
+class TestInstallHeaders(
+ support.TempdirManager,
+):
+ def test_simple_run(self):
+ # we have two headers
+ header_list = self.mkdtemp()
+ header1 = os.path.join(header_list, 'header1')
+ header2 = os.path.join(header_list, 'header2')
+ self.write_file(header1)
+ self.write_file(header2)
+ headers = [header1, header2]
+
+ pkg_dir, dist = self.create_dist(headers=headers)
+ cmd = install_headers(dist)
+ assert cmd.get_inputs() == headers
+
+ # let's run the command
+ cmd.install_dir = os.path.join(pkg_dir, 'inst')
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # let's check the results
+ assert len(cmd.get_outputs()) == 2
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_lib.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_lib.py
new file mode 100644
index 00000000..f685a579
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_lib.py
@@ -0,0 +1,110 @@
+"""Tests for distutils.command.install_data."""
+
+import importlib.util
+import os
+import sys
+from distutils.command.install_lib import install_lib
+from distutils.errors import DistutilsOptionError
+from distutils.extension import Extension
+from distutils.tests import support
+
+import pytest
+
+
+@support.combine_markers
+@pytest.mark.usefixtures('save_env')
+class TestInstallLib(
+ support.TempdirManager,
+):
+ def test_finalize_options(self):
+ dist = self.create_dist()[1]
+ cmd = install_lib(dist)
+
+ cmd.finalize_options()
+ assert cmd.compile == 1
+ assert cmd.optimize == 0
+
+ # optimize must be 0, 1, or 2
+ cmd.optimize = 'foo'
+ with pytest.raises(DistutilsOptionError):
+ cmd.finalize_options()
+ cmd.optimize = '4'
+ with pytest.raises(DistutilsOptionError):
+ cmd.finalize_options()
+
+ cmd.optimize = '2'
+ cmd.finalize_options()
+ assert cmd.optimize == 2
+
+ @pytest.mark.skipif('sys.dont_write_bytecode')
+ def test_byte_compile(self):
+ project_dir, dist = self.create_dist()
+ os.chdir(project_dir)
+ cmd = install_lib(dist)
+ cmd.compile = cmd.optimize = 1
+
+ f = os.path.join(project_dir, 'foo.py')
+ self.write_file(f, '# python file')
+ cmd.byte_compile([f])
+ pyc_file = importlib.util.cache_from_source('foo.py', optimization='')
+ pyc_opt_file = importlib.util.cache_from_source(
+ 'foo.py', optimization=cmd.optimize
+ )
+ assert os.path.exists(pyc_file)
+ assert os.path.exists(pyc_opt_file)
+
+ def test_get_outputs(self):
+ project_dir, dist = self.create_dist()
+ os.chdir(project_dir)
+ os.mkdir('spam')
+ cmd = install_lib(dist)
+
+ # setting up a dist environment
+ cmd.compile = cmd.optimize = 1
+ cmd.install_dir = self.mkdtemp()
+ f = os.path.join(project_dir, 'spam', '__init__.py')
+ self.write_file(f, '# python package')
+ cmd.distribution.ext_modules = [Extension('foo', ['xxx'])]
+ cmd.distribution.packages = ['spam']
+ cmd.distribution.script_name = 'setup.py'
+
+ # get_outputs should return 4 elements: spam/__init__.py and .pyc,
+ # foo.import-tag-abiflags.so / foo.pyd
+ outputs = cmd.get_outputs()
+ assert len(outputs) == 4, outputs
+
+ def test_get_inputs(self):
+ project_dir, dist = self.create_dist()
+ os.chdir(project_dir)
+ os.mkdir('spam')
+ cmd = install_lib(dist)
+
+ # setting up a dist environment
+ cmd.compile = cmd.optimize = 1
+ cmd.install_dir = self.mkdtemp()
+ f = os.path.join(project_dir, 'spam', '__init__.py')
+ self.write_file(f, '# python package')
+ cmd.distribution.ext_modules = [Extension('foo', ['xxx'])]
+ cmd.distribution.packages = ['spam']
+ cmd.distribution.script_name = 'setup.py'
+
+ # get_inputs should return 2 elements: spam/__init__.py and
+ # foo.import-tag-abiflags.so / foo.pyd
+ inputs = cmd.get_inputs()
+ assert len(inputs) == 2, inputs
+
+ def test_dont_write_bytecode(self, caplog):
+ # makes sure byte_compile is not used
+ dist = self.create_dist()[1]
+ cmd = install_lib(dist)
+ cmd.compile = True
+ cmd.optimize = 1
+
+ old_dont_write_bytecode = sys.dont_write_bytecode
+ sys.dont_write_bytecode = True
+ try:
+ cmd.byte_compile([])
+ finally:
+ sys.dont_write_bytecode = old_dont_write_bytecode
+
+ assert 'byte-compiling is disabled' in caplog.messages[0]
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_scripts.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_scripts.py
new file mode 100644
index 00000000..868b1c22
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_install_scripts.py
@@ -0,0 +1,52 @@
+"""Tests for distutils.command.install_scripts."""
+
+import os
+from distutils.command.install_scripts import install_scripts
+from distutils.core import Distribution
+from distutils.tests import support
+
+from . import test_build_scripts
+
+
+class TestInstallScripts(support.TempdirManager):
+ def test_default_settings(self):
+ dist = Distribution()
+ dist.command_obj["build"] = support.DummyCommand(build_scripts="/foo/bar")
+ dist.command_obj["install"] = support.DummyCommand(
+ install_scripts="/splat/funk",
+ force=True,
+ skip_build=True,
+ )
+ cmd = install_scripts(dist)
+ assert not cmd.force
+ assert not cmd.skip_build
+ assert cmd.build_dir is None
+ assert cmd.install_dir is None
+
+ cmd.finalize_options()
+
+ assert cmd.force
+ assert cmd.skip_build
+ assert cmd.build_dir == "/foo/bar"
+ assert cmd.install_dir == "/splat/funk"
+
+ def test_installation(self):
+ source = self.mkdtemp()
+
+ expected = test_build_scripts.TestBuildScripts.write_sample_scripts(source)
+
+ target = self.mkdtemp()
+ dist = Distribution()
+ dist.command_obj["build"] = support.DummyCommand(build_scripts=source)
+ dist.command_obj["install"] = support.DummyCommand(
+ install_scripts=target,
+ force=True,
+ skip_build=True,
+ )
+ cmd = install_scripts(dist)
+ cmd.finalize_options()
+ cmd.run()
+
+ installed = os.listdir(target)
+ for name in expected:
+ assert name in installed
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_log.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_log.py
new file mode 100644
index 00000000..d67779fc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_log.py
@@ -0,0 +1,12 @@
+"""Tests for distutils.log"""
+
+import logging
+from distutils._log import log
+
+
+class TestLog:
+ def test_non_ascii(self, caplog):
+ caplog.set_level(logging.DEBUG)
+ log.debug('Dεbug\tMėssãge')
+ log.fatal('Fαtal\tÈrrōr')
+ assert caplog.messages == ['Dεbug\tMėssãge', 'Fαtal\tÈrrōr']
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_modified.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_modified.py
new file mode 100644
index 00000000..e35cec2d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_modified.py
@@ -0,0 +1,126 @@
+"""Tests for distutils._modified."""
+
+import os
+import types
+from distutils._modified import newer, newer_group, newer_pairwise, newer_pairwise_group
+from distutils.errors import DistutilsFileError
+from distutils.tests import support
+
+import pytest
+
+
+class TestDepUtil(support.TempdirManager):
+ def test_newer(self):
+ tmpdir = self.mkdtemp()
+ new_file = os.path.join(tmpdir, 'new')
+ old_file = os.path.abspath(__file__)
+
+ # Raise DistutilsFileError if 'new_file' does not exist.
+ with pytest.raises(DistutilsFileError):
+ newer(new_file, old_file)
+
+ # Return true if 'new_file' exists and is more recently modified than
+ # 'old_file', or if 'new_file' exists and 'old_file' doesn't.
+ self.write_file(new_file)
+ assert newer(new_file, 'I_dont_exist')
+ assert newer(new_file, old_file)
+
+ # Return false if both exist and 'old_file' is the same age or younger
+ # than 'new_file'.
+ assert not newer(old_file, new_file)
+
+ def _setup_1234(self):
+ tmpdir = self.mkdtemp()
+ sources = os.path.join(tmpdir, 'sources')
+ targets = os.path.join(tmpdir, 'targets')
+ os.mkdir(sources)
+ os.mkdir(targets)
+ one = os.path.join(sources, 'one')
+ two = os.path.join(sources, 'two')
+ three = os.path.abspath(__file__) # I am the old file
+ four = os.path.join(targets, 'four')
+ self.write_file(one)
+ self.write_file(two)
+ self.write_file(four)
+ return one, two, three, four
+
+ def test_newer_pairwise(self):
+ one, two, three, four = self._setup_1234()
+
+ assert newer_pairwise([one, two], [three, four]) == ([one], [three])
+
+ def test_newer_pairwise_mismatch(self):
+ one, two, three, four = self._setup_1234()
+
+ with pytest.raises(ValueError):
+ newer_pairwise([one], [three, four])
+
+ with pytest.raises(ValueError):
+ newer_pairwise([one, two], [three])
+
+ def test_newer_pairwise_empty(self):
+ assert newer_pairwise([], []) == ([], [])
+
+ def test_newer_pairwise_fresh(self):
+ one, two, three, four = self._setup_1234()
+
+ assert newer_pairwise([one, three], [two, four]) == ([], [])
+
+ def test_newer_group(self):
+ tmpdir = self.mkdtemp()
+ sources = os.path.join(tmpdir, 'sources')
+ os.mkdir(sources)
+ one = os.path.join(sources, 'one')
+ two = os.path.join(sources, 'two')
+ three = os.path.join(sources, 'three')
+ old_file = os.path.abspath(__file__)
+
+ # return true if 'old_file' is out-of-date with respect to any file
+ # listed in 'sources'.
+ self.write_file(one)
+ self.write_file(two)
+ self.write_file(three)
+ assert newer_group([one, two, three], old_file)
+ assert not newer_group([one, two, old_file], three)
+
+ # missing handling
+ os.remove(one)
+ with pytest.raises(OSError):
+ newer_group([one, two, old_file], three)
+
+ assert not newer_group([one, two, old_file], three, missing='ignore')
+
+ assert newer_group([one, two, old_file], three, missing='newer')
+
+
+@pytest.fixture
+def groups_target(tmp_path):
+ """
+ Set up some older sources, a target, and newer sources.
+
+ Returns a simple namespace with these values.
+ """
+ filenames = ['older.c', 'older.h', 'target.o', 'newer.c', 'newer.h']
+ paths = [tmp_path / name for name in filenames]
+
+ for mtime, path in enumerate(paths):
+ path.write_text('', encoding='utf-8')
+
+ # make sure modification times are sequential
+ os.utime(path, (mtime, mtime))
+
+ return types.SimpleNamespace(older=paths[:2], target=paths[2], newer=paths[3:])
+
+
+def test_newer_pairwise_group(groups_target):
+ older = newer_pairwise_group([groups_target.older], [groups_target.target])
+ newer = newer_pairwise_group([groups_target.newer], [groups_target.target])
+ assert older == ([], [])
+ assert newer == ([groups_target.newer], [groups_target.target])
+
+
+def test_newer_group_no_sources_no_target(tmp_path):
+ """
+ Consider no sources and no target "newer".
+ """
+ assert newer_group([], str(tmp_path / 'does-not-exist'))
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_sdist.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_sdist.py
new file mode 100644
index 00000000..6b1a376b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_sdist.py
@@ -0,0 +1,470 @@
+"""Tests for distutils.command.sdist."""
+
+import os
+import pathlib
+import shutil # noqa: F401
+import tarfile
+import zipfile
+from distutils.archive_util import ARCHIVE_FORMATS
+from distutils.command.sdist import sdist, show_formats
+from distutils.core import Distribution
+from distutils.errors import DistutilsOptionError
+from distutils.filelist import FileList
+from os.path import join
+from textwrap import dedent
+
+import jaraco.path
+import path
+import pytest
+from more_itertools import ilen
+
+from . import support
+from .unix_compat import grp, pwd, require_uid_0, require_unix_id
+
+SETUP_PY = """
+from distutils.core import setup
+import somecode
+
+setup(name='fake')
+"""
+
+MANIFEST = """\
+# file GENERATED by distutils, do NOT edit
+README
+buildout.cfg
+inroot.txt
+setup.py
+data%(sep)sdata.dt
+scripts%(sep)sscript.py
+some%(sep)sfile.txt
+some%(sep)sother_file.txt
+somecode%(sep)s__init__.py
+somecode%(sep)sdoc.dat
+somecode%(sep)sdoc.txt
+"""
+
+
+@pytest.fixture(autouse=True)
+def project_dir(request, distutils_managed_tempdir):
+ self = request.instance
+ self.tmp_dir = self.mkdtemp()
+ jaraco.path.build(
+ {
+ 'somecode': {
+ '__init__.py': '#',
+ },
+ 'README': 'xxx',
+ 'setup.py': SETUP_PY,
+ },
+ self.tmp_dir,
+ )
+ with path.Path(self.tmp_dir):
+ yield
+
+
+def clean_lines(filepath):
+ with pathlib.Path(filepath).open(encoding='utf-8') as f:
+ yield from filter(None, map(str.strip, f))
+
+
+class TestSDist(support.TempdirManager):
+ def get_cmd(self, metadata=None):
+ """Returns a cmd"""
+ if metadata is None:
+ metadata = {
+ 'name': 'ns.fake--pkg',
+ 'version': '1.0',
+ 'url': 'xxx',
+ 'author': 'xxx',
+ 'author_email': 'xxx',
+ }
+ dist = Distribution(metadata)
+ dist.script_name = 'setup.py'
+ dist.packages = ['somecode']
+ dist.include_package_data = True
+ cmd = sdist(dist)
+ cmd.dist_dir = 'dist'
+ return dist, cmd
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_prune_file_list(self):
+ # this test creates a project with some VCS dirs and an NFS rename
+ # file, then launches sdist to check they get pruned on all systems
+
+ # creating VCS directories with some files in them
+ os.mkdir(join(self.tmp_dir, 'somecode', '.svn'))
+ self.write_file((self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx')
+
+ os.mkdir(join(self.tmp_dir, 'somecode', '.hg'))
+ self.write_file((self.tmp_dir, 'somecode', '.hg', 'ok'), 'xxx')
+
+ os.mkdir(join(self.tmp_dir, 'somecode', '.git'))
+ self.write_file((self.tmp_dir, 'somecode', '.git', 'ok'), 'xxx')
+
+ self.write_file((self.tmp_dir, 'somecode', '.nfs0001'), 'xxx')
+
+ # now building a sdist
+ dist, cmd = self.get_cmd()
+
+ # zip is available universally
+ # (tar might not be installed under win32)
+ cmd.formats = ['zip']
+
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # now let's check what we have
+ dist_folder = join(self.tmp_dir, 'dist')
+ files = os.listdir(dist_folder)
+ assert files == ['ns_fake_pkg-1.0.zip']
+
+ zip_file = zipfile.ZipFile(join(dist_folder, 'ns_fake_pkg-1.0.zip'))
+ try:
+ content = zip_file.namelist()
+ finally:
+ zip_file.close()
+
+ # making sure everything has been pruned correctly
+ expected = [
+ '',
+ 'PKG-INFO',
+ 'README',
+ 'setup.py',
+ 'somecode/',
+ 'somecode/__init__.py',
+ ]
+ assert sorted(content) == ['ns_fake_pkg-1.0/' + x for x in expected]
+
+ @pytest.mark.usefixtures('needs_zlib')
+ @pytest.mark.skipif("not shutil.which('tar')")
+ @pytest.mark.skipif("not shutil.which('gzip')")
+ def test_make_distribution(self):
+ # now building a sdist
+ dist, cmd = self.get_cmd()
+
+ # creating a gztar then a tar
+ cmd.formats = ['gztar', 'tar']
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # making sure we have two files
+ dist_folder = join(self.tmp_dir, 'dist')
+ result = os.listdir(dist_folder)
+ result.sort()
+ assert result == ['ns_fake_pkg-1.0.tar', 'ns_fake_pkg-1.0.tar.gz']
+
+ os.remove(join(dist_folder, 'ns_fake_pkg-1.0.tar'))
+ os.remove(join(dist_folder, 'ns_fake_pkg-1.0.tar.gz'))
+
+ # now trying a tar then a gztar
+ cmd.formats = ['tar', 'gztar']
+
+ cmd.ensure_finalized()
+ cmd.run()
+
+ result = os.listdir(dist_folder)
+ result.sort()
+ assert result == ['ns_fake_pkg-1.0.tar', 'ns_fake_pkg-1.0.tar.gz']
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_add_defaults(self):
+ # https://bugs.python.org/issue2279
+
+ # add_default should also include
+ # data_files and package_data
+ dist, cmd = self.get_cmd()
+
+ # filling data_files by pointing files
+ # in package_data
+ dist.package_data = {'': ['*.cfg', '*.dat'], 'somecode': ['*.txt']}
+ self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#')
+ self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#')
+
+ # adding some data in data_files
+ data_dir = join(self.tmp_dir, 'data')
+ os.mkdir(data_dir)
+ self.write_file((data_dir, 'data.dt'), '#')
+ some_dir = join(self.tmp_dir, 'some')
+ os.mkdir(some_dir)
+ # make sure VCS directories are pruned (#14004)
+ hg_dir = join(self.tmp_dir, '.hg')
+ os.mkdir(hg_dir)
+ self.write_file((hg_dir, 'last-message.txt'), '#')
+ # a buggy regex used to prevent this from working on windows (#6884)
+ self.write_file((self.tmp_dir, 'buildout.cfg'), '#')
+ self.write_file((self.tmp_dir, 'inroot.txt'), '#')
+ self.write_file((some_dir, 'file.txt'), '#')
+ self.write_file((some_dir, 'other_file.txt'), '#')
+
+ dist.data_files = [
+ ('data', ['data/data.dt', 'buildout.cfg', 'inroot.txt', 'notexisting']),
+ 'some/file.txt',
+ 'some/other_file.txt',
+ ]
+
+ # adding a script
+ script_dir = join(self.tmp_dir, 'scripts')
+ os.mkdir(script_dir)
+ self.write_file((script_dir, 'script.py'), '#')
+ dist.scripts = [join('scripts', 'script.py')]
+
+ cmd.formats = ['zip']
+ cmd.use_defaults = True
+
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # now let's check what we have
+ dist_folder = join(self.tmp_dir, 'dist')
+ files = os.listdir(dist_folder)
+ assert files == ['ns_fake_pkg-1.0.zip']
+
+ zip_file = zipfile.ZipFile(join(dist_folder, 'ns_fake_pkg-1.0.zip'))
+ try:
+ content = zip_file.namelist()
+ finally:
+ zip_file.close()
+
+ # making sure everything was added
+ expected = [
+ '',
+ 'PKG-INFO',
+ 'README',
+ 'buildout.cfg',
+ 'data/',
+ 'data/data.dt',
+ 'inroot.txt',
+ 'scripts/',
+ 'scripts/script.py',
+ 'setup.py',
+ 'some/',
+ 'some/file.txt',
+ 'some/other_file.txt',
+ 'somecode/',
+ 'somecode/__init__.py',
+ 'somecode/doc.dat',
+ 'somecode/doc.txt',
+ ]
+ assert sorted(content) == ['ns_fake_pkg-1.0/' + x for x in expected]
+
+ # checking the MANIFEST
+ manifest = pathlib.Path(self.tmp_dir, 'MANIFEST').read_text(encoding='utf-8')
+ assert manifest == MANIFEST % {'sep': os.sep}
+
+ @staticmethod
+ def warnings(messages, prefix='warning: '):
+ return [msg for msg in messages if msg.startswith(prefix)]
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_metadata_check_option(self, caplog):
+ # testing the `medata-check` option
+ dist, cmd = self.get_cmd(metadata={})
+
+ # this should raise some warnings !
+ # with the `check` subcommand
+ cmd.ensure_finalized()
+ cmd.run()
+ assert len(self.warnings(caplog.messages, 'warning: check: ')) == 1
+
+ # trying with a complete set of metadata
+ caplog.clear()
+ dist, cmd = self.get_cmd()
+ cmd.ensure_finalized()
+ cmd.metadata_check = False
+ cmd.run()
+ assert len(self.warnings(caplog.messages, 'warning: check: ')) == 0
+
+ def test_show_formats(self, capsys):
+ show_formats()
+
+ # the output should be a header line + one line per format
+ num_formats = len(ARCHIVE_FORMATS.keys())
+ output = [
+ line
+ for line in capsys.readouterr().out.split('\n')
+ if line.strip().startswith('--formats=')
+ ]
+ assert len(output) == num_formats
+
+ def test_finalize_options(self):
+ dist, cmd = self.get_cmd()
+ cmd.finalize_options()
+
+ # default options set by finalize
+ assert cmd.manifest == 'MANIFEST'
+ assert cmd.template == 'MANIFEST.in'
+ assert cmd.dist_dir == 'dist'
+
+ # formats has to be a string splitable on (' ', ',') or
+ # a stringlist
+ cmd.formats = 1
+ with pytest.raises(DistutilsOptionError):
+ cmd.finalize_options()
+ cmd.formats = ['zip']
+ cmd.finalize_options()
+
+ # formats has to be known
+ cmd.formats = 'supazipa'
+ with pytest.raises(DistutilsOptionError):
+ cmd.finalize_options()
+
+ # the following tests make sure there is a nice error message instead
+ # of a traceback when parsing an invalid manifest template
+
+ def _check_template(self, content, caplog):
+ dist, cmd = self.get_cmd()
+ os.chdir(self.tmp_dir)
+ self.write_file('MANIFEST.in', content)
+ cmd.ensure_finalized()
+ cmd.filelist = FileList()
+ cmd.read_template()
+ assert len(self.warnings(caplog.messages)) == 1
+
+ def test_invalid_template_unknown_command(self, caplog):
+ self._check_template('taunt knights *', caplog)
+
+ def test_invalid_template_wrong_arguments(self, caplog):
+ # this manifest command takes one argument
+ self._check_template('prune', caplog)
+
+ @pytest.mark.skipif("platform.system() != 'Windows'")
+ def test_invalid_template_wrong_path(self, caplog):
+ # on Windows, trailing slashes are not allowed
+ # this used to crash instead of raising a warning: #8286
+ self._check_template('include examples/', caplog)
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_get_file_list(self):
+ # make sure MANIFEST is recalculated
+ dist, cmd = self.get_cmd()
+
+ # filling data_files by pointing files in package_data
+ dist.package_data = {'somecode': ['*.txt']}
+ self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#')
+ cmd.formats = ['gztar']
+ cmd.ensure_finalized()
+ cmd.run()
+
+ assert ilen(clean_lines(cmd.manifest)) == 5
+
+ # adding a file
+ self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#')
+
+ # make sure build_py is reinitialized, like a fresh run
+ build_py = dist.get_command_obj('build_py')
+ build_py.finalized = False
+ build_py.ensure_finalized()
+
+ cmd.run()
+
+ manifest2 = list(clean_lines(cmd.manifest))
+
+ # do we have the new file in MANIFEST ?
+ assert len(manifest2) == 6
+ assert 'doc2.txt' in manifest2[-1]
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_manifest_marker(self):
+ # check that autogenerated MANIFESTs have a marker
+ dist, cmd = self.get_cmd()
+ cmd.ensure_finalized()
+ cmd.run()
+
+ assert (
+ next(clean_lines(cmd.manifest))
+ == '# file GENERATED by distutils, do NOT edit'
+ )
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_manifest_comments(self):
+ # make sure comments don't cause exceptions or wrong includes
+ contents = dedent(
+ """\
+ # bad.py
+ #bad.py
+ good.py
+ """
+ )
+ dist, cmd = self.get_cmd()
+ cmd.ensure_finalized()
+ self.write_file((self.tmp_dir, cmd.manifest), contents)
+ self.write_file((self.tmp_dir, 'good.py'), '# pick me!')
+ self.write_file((self.tmp_dir, 'bad.py'), "# don't pick me!")
+ self.write_file((self.tmp_dir, '#bad.py'), "# don't pick me!")
+ cmd.run()
+ assert cmd.filelist.files == ['good.py']
+
+ @pytest.mark.usefixtures('needs_zlib')
+ def test_manual_manifest(self):
+ # check that a MANIFEST without a marker is left alone
+ dist, cmd = self.get_cmd()
+ cmd.formats = ['gztar']
+ cmd.ensure_finalized()
+ self.write_file((self.tmp_dir, cmd.manifest), 'README.manual')
+ self.write_file(
+ (self.tmp_dir, 'README.manual'),
+ 'This project maintains its MANIFEST file itself.',
+ )
+ cmd.run()
+ assert cmd.filelist.files == ['README.manual']
+
+ assert list(clean_lines(cmd.manifest)) == ['README.manual']
+
+ archive_name = join(self.tmp_dir, 'dist', 'ns_fake_pkg-1.0.tar.gz')
+ archive = tarfile.open(archive_name)
+ try:
+ filenames = [tarinfo.name for tarinfo in archive]
+ finally:
+ archive.close()
+ assert sorted(filenames) == [
+ 'ns_fake_pkg-1.0',
+ 'ns_fake_pkg-1.0/PKG-INFO',
+ 'ns_fake_pkg-1.0/README.manual',
+ ]
+
+ @pytest.mark.usefixtures('needs_zlib')
+ @require_unix_id
+ @require_uid_0
+ @pytest.mark.skipif("not shutil.which('tar')")
+ @pytest.mark.skipif("not shutil.which('gzip')")
+ def test_make_distribution_owner_group(self):
+ # now building a sdist
+ dist, cmd = self.get_cmd()
+
+ # creating a gztar and specifying the owner+group
+ cmd.formats = ['gztar']
+ cmd.owner = pwd.getpwuid(0)[0]
+ cmd.group = grp.getgrgid(0)[0]
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # making sure we have the good rights
+ archive_name = join(self.tmp_dir, 'dist', 'ns_fake_pkg-1.0.tar.gz')
+ archive = tarfile.open(archive_name)
+ try:
+ for member in archive.getmembers():
+ assert member.uid == 0
+ assert member.gid == 0
+ finally:
+ archive.close()
+
+ # building a sdist again
+ dist, cmd = self.get_cmd()
+
+ # creating a gztar
+ cmd.formats = ['gztar']
+ cmd.ensure_finalized()
+ cmd.run()
+
+ # making sure we have the good rights
+ archive_name = join(self.tmp_dir, 'dist', 'ns_fake_pkg-1.0.tar.gz')
+ archive = tarfile.open(archive_name)
+
+ # note that we are not testing the group ownership here
+ # because, depending on the platforms and the container
+ # rights (see #7408)
+ try:
+ for member in archive.getmembers():
+ assert member.uid == os.getuid()
+ finally:
+ archive.close()
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_spawn.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_spawn.py
new file mode 100644
index 00000000..3b9fc926
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_spawn.py
@@ -0,0 +1,141 @@
+"""Tests for distutils.spawn."""
+
+import os
+import stat
+import sys
+import unittest.mock as mock
+from distutils.errors import DistutilsExecError
+from distutils.spawn import find_executable, spawn
+from distutils.tests import support
+
+import path
+import pytest
+from test.support import unix_shell
+
+from .compat import py39 as os_helper
+
+
+class TestSpawn(support.TempdirManager):
+ @pytest.mark.skipif("os.name not in ('nt', 'posix')")
+ def test_spawn(self):
+ tmpdir = self.mkdtemp()
+
+ # creating something executable
+ # through the shell that returns 1
+ if sys.platform != 'win32':
+ exe = os.path.join(tmpdir, 'foo.sh')
+ self.write_file(exe, f'#!{unix_shell}\nexit 1')
+ else:
+ exe = os.path.join(tmpdir, 'foo.bat')
+ self.write_file(exe, 'exit 1')
+
+ os.chmod(exe, 0o777)
+ with pytest.raises(DistutilsExecError):
+ spawn([exe])
+
+ # now something that works
+ if sys.platform != 'win32':
+ exe = os.path.join(tmpdir, 'foo.sh')
+ self.write_file(exe, f'#!{unix_shell}\nexit 0')
+ else:
+ exe = os.path.join(tmpdir, 'foo.bat')
+ self.write_file(exe, 'exit 0')
+
+ os.chmod(exe, 0o777)
+ spawn([exe]) # should work without any error
+
+ def test_find_executable(self, tmp_path):
+ program_path = self._make_executable(tmp_path, '.exe')
+ program = program_path.name
+ program_noeext = program_path.with_suffix('').name
+ filename = str(program_path)
+ tmp_dir = path.Path(tmp_path)
+
+ # test path parameter
+ rv = find_executable(program, path=tmp_dir)
+ assert rv == filename
+
+ if sys.platform == 'win32':
+ # test without ".exe" extension
+ rv = find_executable(program_noeext, path=tmp_dir)
+ assert rv == filename
+
+ # test find in the current directory
+ with tmp_dir:
+ rv = find_executable(program)
+ assert rv == program
+
+ # test non-existent program
+ dont_exist_program = "dontexist_" + program
+ rv = find_executable(dont_exist_program, path=tmp_dir)
+ assert rv is None
+
+ # PATH='': no match, except in the current directory
+ with os_helper.EnvironmentVarGuard() as env:
+ env['PATH'] = ''
+ with (
+ mock.patch(
+ 'distutils.spawn.os.confstr', return_value=tmp_dir, create=True
+ ),
+ mock.patch('distutils.spawn.os.defpath', tmp_dir),
+ ):
+ rv = find_executable(program)
+ assert rv is None
+
+ # look in current directory
+ with tmp_dir:
+ rv = find_executable(program)
+ assert rv == program
+
+ # PATH=':': explicitly looks in the current directory
+ with os_helper.EnvironmentVarGuard() as env:
+ env['PATH'] = os.pathsep
+ with (
+ mock.patch('distutils.spawn.os.confstr', return_value='', create=True),
+ mock.patch('distutils.spawn.os.defpath', ''),
+ ):
+ rv = find_executable(program)
+ assert rv is None
+
+ # look in current directory
+ with tmp_dir:
+ rv = find_executable(program)
+ assert rv == program
+
+ # missing PATH: test os.confstr("CS_PATH") and os.defpath
+ with os_helper.EnvironmentVarGuard() as env:
+ env.pop('PATH', None)
+
+ # without confstr
+ with (
+ mock.patch(
+ 'distutils.spawn.os.confstr', side_effect=ValueError, create=True
+ ),
+ mock.patch('distutils.spawn.os.defpath', tmp_dir),
+ ):
+ rv = find_executable(program)
+ assert rv == filename
+
+ # with confstr
+ with (
+ mock.patch(
+ 'distutils.spawn.os.confstr', return_value=tmp_dir, create=True
+ ),
+ mock.patch('distutils.spawn.os.defpath', ''),
+ ):
+ rv = find_executable(program)
+ assert rv == filename
+
+ @staticmethod
+ def _make_executable(tmp_path, ext):
+ # Give the temporary program a suffix regardless of platform.
+ # It's needed on Windows and not harmful on others.
+ program = tmp_path.joinpath('program').with_suffix(ext)
+ program.write_text("", encoding='utf-8')
+ program.chmod(stat.S_IXUSR)
+ return program
+
+ def test_spawn_missing_exe(self):
+ with pytest.raises(DistutilsExecError) as ctx:
+ spawn(['does-not-exist'])
+ assert "command 'does-not-exist' failed" in str(ctx.value)
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_sysconfig.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_sysconfig.py
new file mode 100644
index 00000000..43d77c23
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_sysconfig.py
@@ -0,0 +1,319 @@
+"""Tests for distutils.sysconfig."""
+
+import contextlib
+import distutils
+import os
+import pathlib
+import subprocess
+import sys
+from distutils import sysconfig
+from distutils.ccompiler import new_compiler # noqa: F401
+from distutils.unixccompiler import UnixCCompiler
+
+import jaraco.envs
+import path
+import pytest
+from jaraco.text import trim
+from test.support import swap_item
+
+
+def _gen_makefile(root, contents):
+ jaraco.path.build({'Makefile': trim(contents)}, root)
+ return root / 'Makefile'
+
+
+@pytest.mark.usefixtures('save_env')
+class TestSysconfig:
+ def test_get_config_h_filename(self):
+ config_h = sysconfig.get_config_h_filename()
+ assert os.path.isfile(config_h)
+
+ @pytest.mark.skipif("platform.system() == 'Windows'")
+ @pytest.mark.skipif("sys.implementation.name != 'cpython'")
+ def test_get_makefile_filename(self):
+ makefile = sysconfig.get_makefile_filename()
+ assert os.path.isfile(makefile)
+
+ def test_get_python_lib(self, tmp_path):
+ assert sysconfig.get_python_lib() != sysconfig.get_python_lib(prefix=tmp_path)
+
+ def test_get_config_vars(self):
+ cvars = sysconfig.get_config_vars()
+ assert isinstance(cvars, dict)
+ assert cvars
+
+ @pytest.mark.skipif('sysconfig.IS_PYPY')
+ @pytest.mark.skipif('sysconfig.python_build')
+ @pytest.mark.xfail('platform.system() == "Windows"')
+ def test_srcdir_simple(self):
+ # See #15364.
+ srcdir = pathlib.Path(sysconfig.get_config_var('srcdir'))
+
+ assert srcdir.absolute()
+ assert srcdir.is_dir()
+
+ makefile = pathlib.Path(sysconfig.get_makefile_filename())
+ assert makefile.parent.samefile(srcdir)
+
+ @pytest.mark.skipif('sysconfig.IS_PYPY')
+ @pytest.mark.skipif('not sysconfig.python_build')
+ def test_srcdir_python_build(self):
+ # See #15364.
+ srcdir = pathlib.Path(sysconfig.get_config_var('srcdir'))
+
+ # The python executable has not been installed so srcdir
+ # should be a full source checkout.
+ Python_h = srcdir.joinpath('Include', 'Python.h')
+ assert Python_h.is_file()
+ assert sysconfig._is_python_source_dir(srcdir)
+ assert sysconfig._is_python_source_dir(str(srcdir))
+
+ def test_srcdir_independent_of_cwd(self):
+ """
+ srcdir should be independent of the current working directory
+ """
+ # See #15364.
+ srcdir = sysconfig.get_config_var('srcdir')
+ with path.Path('..'):
+ srcdir2 = sysconfig.get_config_var('srcdir')
+ assert srcdir == srcdir2
+
+ def customize_compiler(self):
+ # make sure AR gets caught
+ class compiler:
+ compiler_type = 'unix'
+ executables = UnixCCompiler.executables
+
+ def __init__(self):
+ self.exes = {}
+
+ def set_executables(self, **kw):
+ for k, v in kw.items():
+ self.exes[k] = v
+
+ sysconfig_vars = {
+ 'AR': 'sc_ar',
+ 'CC': 'sc_cc',
+ 'CXX': 'sc_cxx',
+ 'ARFLAGS': '--sc-arflags',
+ 'CFLAGS': '--sc-cflags',
+ 'CCSHARED': '--sc-ccshared',
+ 'LDSHARED': 'sc_ldshared',
+ 'SHLIB_SUFFIX': 'sc_shutil_suffix',
+ }
+
+ comp = compiler()
+ with contextlib.ExitStack() as cm:
+ for key, value in sysconfig_vars.items():
+ cm.enter_context(swap_item(sysconfig._config_vars, key, value))
+ sysconfig.customize_compiler(comp)
+
+ return comp
+
+ @pytest.mark.skipif("not isinstance(new_compiler(), UnixCCompiler)")
+ @pytest.mark.usefixtures('disable_macos_customization')
+ def test_customize_compiler(self):
+ # Make sure that sysconfig._config_vars is initialized
+ sysconfig.get_config_vars()
+
+ os.environ['AR'] = 'env_ar'
+ os.environ['CC'] = 'env_cc'
+ os.environ['CPP'] = 'env_cpp'
+ os.environ['CXX'] = 'env_cxx --env-cxx-flags'
+ os.environ['LDSHARED'] = 'env_ldshared'
+ os.environ['LDFLAGS'] = '--env-ldflags'
+ os.environ['ARFLAGS'] = '--env-arflags'
+ os.environ['CFLAGS'] = '--env-cflags'
+ os.environ['CPPFLAGS'] = '--env-cppflags'
+ os.environ['RANLIB'] = 'env_ranlib'
+
+ comp = self.customize_compiler()
+ assert comp.exes['archiver'] == 'env_ar --env-arflags'
+ assert comp.exes['preprocessor'] == 'env_cpp --env-cppflags'
+ assert comp.exes['compiler'] == 'env_cc --env-cflags --env-cppflags'
+ assert comp.exes['compiler_so'] == (
+ 'env_cc --env-cflags --env-cppflags --sc-ccshared'
+ )
+ assert (
+ comp.exes['compiler_cxx']
+ == 'env_cxx --env-cxx-flags --sc-cflags --env-cppflags'
+ )
+ assert comp.exes['linker_exe'] == 'env_cc'
+ assert comp.exes['linker_so'] == (
+ 'env_ldshared --env-ldflags --env-cflags --env-cppflags'
+ )
+ assert comp.shared_lib_extension == 'sc_shutil_suffix'
+
+ if sys.platform == "darwin":
+ assert comp.exes['ranlib'] == 'env_ranlib'
+ else:
+ assert 'ranlib' not in comp.exes
+
+ del os.environ['AR']
+ del os.environ['CC']
+ del os.environ['CPP']
+ del os.environ['CXX']
+ del os.environ['LDSHARED']
+ del os.environ['LDFLAGS']
+ del os.environ['ARFLAGS']
+ del os.environ['CFLAGS']
+ del os.environ['CPPFLAGS']
+ del os.environ['RANLIB']
+
+ comp = self.customize_compiler()
+ assert comp.exes['archiver'] == 'sc_ar --sc-arflags'
+ assert comp.exes['preprocessor'] == 'sc_cc -E'
+ assert comp.exes['compiler'] == 'sc_cc --sc-cflags'
+ assert comp.exes['compiler_so'] == 'sc_cc --sc-cflags --sc-ccshared'
+ assert comp.exes['compiler_cxx'] == 'sc_cxx --sc-cflags'
+ assert comp.exes['linker_exe'] == 'sc_cc'
+ assert comp.exes['linker_so'] == 'sc_ldshared'
+ assert comp.shared_lib_extension == 'sc_shutil_suffix'
+ assert 'ranlib' not in comp.exes
+
+ def test_parse_makefile_base(self, tmp_path):
+ makefile = _gen_makefile(
+ tmp_path,
+ """
+ CONFIG_ARGS= '--arg1=optarg1' 'ENV=LIB'
+ VAR=$OTHER
+ OTHER=foo
+ """,
+ )
+ d = sysconfig.parse_makefile(makefile)
+ assert d == {'CONFIG_ARGS': "'--arg1=optarg1' 'ENV=LIB'", 'OTHER': 'foo'}
+
+ def test_parse_makefile_literal_dollar(self, tmp_path):
+ makefile = _gen_makefile(
+ tmp_path,
+ """
+ CONFIG_ARGS= '--arg1=optarg1' 'ENV=\\$$LIB'
+ VAR=$OTHER
+ OTHER=foo
+ """,
+ )
+ d = sysconfig.parse_makefile(makefile)
+ assert d == {'CONFIG_ARGS': r"'--arg1=optarg1' 'ENV=\$LIB'", 'OTHER': 'foo'}
+
+ def test_sysconfig_module(self):
+ import sysconfig as global_sysconfig
+
+ assert global_sysconfig.get_config_var('CFLAGS') == sysconfig.get_config_var(
+ 'CFLAGS'
+ )
+ assert global_sysconfig.get_config_var('LDFLAGS') == sysconfig.get_config_var(
+ 'LDFLAGS'
+ )
+
+ # On macOS, binary installers support extension module building on
+ # various levels of the operating system with differing Xcode
+ # configurations, requiring customization of some of the
+ # compiler configuration directives to suit the environment on
+ # the installed machine. Some of these customizations may require
+ # running external programs and are thus deferred until needed by
+ # the first extension module build. Only
+ # the Distutils version of sysconfig is used for extension module
+ # builds, which happens earlier in the Distutils tests. This may
+ # cause the following tests to fail since no tests have caused
+ # the global version of sysconfig to call the customization yet.
+ # The solution for now is to simply skip this test in this case.
+ # The longer-term solution is to only have one version of sysconfig.
+ @pytest.mark.skipif("sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER')")
+ def test_sysconfig_compiler_vars(self):
+ import sysconfig as global_sysconfig
+
+ if sysconfig.get_config_var('CUSTOMIZED_OSX_COMPILER'):
+ pytest.skip('compiler flags customized')
+ assert global_sysconfig.get_config_var('LDSHARED') == sysconfig.get_config_var(
+ 'LDSHARED'
+ )
+ assert global_sysconfig.get_config_var('CC') == sysconfig.get_config_var('CC')
+
+ @pytest.mark.skipif("not sysconfig.get_config_var('EXT_SUFFIX')")
+ def test_SO_deprecation(self):
+ with pytest.warns(DeprecationWarning):
+ sysconfig.get_config_var('SO')
+
+ def test_customize_compiler_before_get_config_vars(self, tmp_path):
+ # Issue #21923: test that a Distribution compiler
+ # instance can be called without an explicit call to
+ # get_config_vars().
+ jaraco.path.build(
+ {
+ 'file': trim("""
+ from distutils.core import Distribution
+ config = Distribution().get_command_obj('config')
+ # try_compile may pass or it may fail if no compiler
+ # is found but it should not raise an exception.
+ rc = config.try_compile('int x;')
+ """)
+ },
+ tmp_path,
+ )
+ p = subprocess.Popen(
+ [sys.executable, tmp_path / 'file'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True,
+ encoding='utf-8',
+ )
+ outs, errs = p.communicate()
+ assert 0 == p.returncode, "Subprocess failed: " + outs
+
+ def test_parse_config_h(self):
+ config_h = sysconfig.get_config_h_filename()
+ input = {}
+ with open(config_h, encoding="utf-8") as f:
+ result = sysconfig.parse_config_h(f, g=input)
+ assert input is result
+ with open(config_h, encoding="utf-8") as f:
+ result = sysconfig.parse_config_h(f)
+ assert isinstance(result, dict)
+
+ @pytest.mark.skipif("platform.system() != 'Windows'")
+ @pytest.mark.skipif("sys.implementation.name != 'cpython'")
+ def test_win_ext_suffix(self):
+ assert sysconfig.get_config_var("EXT_SUFFIX").endswith(".pyd")
+ assert sysconfig.get_config_var("EXT_SUFFIX") != ".pyd"
+
+ @pytest.mark.skipif("platform.system() != 'Windows'")
+ @pytest.mark.skipif("sys.implementation.name != 'cpython'")
+ @pytest.mark.skipif(
+ '\\PCbuild\\'.casefold() not in sys.executable.casefold(),
+ reason='Need sys.executable to be in a source tree',
+ )
+ def test_win_build_venv_from_source_tree(self, tmp_path):
+ """Ensure distutils.sysconfig detects venvs from source tree builds."""
+ env = jaraco.envs.VEnv()
+ env.create_opts = env.clean_opts
+ env.root = tmp_path
+ env.ensure_env()
+ cmd = [
+ env.exe(),
+ "-c",
+ "import distutils.sysconfig; print(distutils.sysconfig.python_build)",
+ ]
+ distutils_path = os.path.dirname(os.path.dirname(distutils.__file__))
+ out = subprocess.check_output(
+ cmd, env={**os.environ, "PYTHONPATH": distutils_path}
+ )
+ assert out == "True"
+
+ def test_get_python_inc_missing_config_dir(self, monkeypatch):
+ """
+ In portable Python installations, the sysconfig will be broken,
+ pointing to the directories where the installation was built and
+ not where it currently is. In this case, ensure that the missing
+ directory isn't used for get_python_inc.
+
+ See pypa/distutils#178.
+ """
+
+ def override(name):
+ if name == 'INCLUDEPY':
+ return '/does-not-exist'
+ return sysconfig.get_config_var(name)
+
+ monkeypatch.setattr(sysconfig, 'get_config_var', override)
+
+ assert os.path.exists(sysconfig.get_python_inc())
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_text_file.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_text_file.py
new file mode 100644
index 00000000..f5111565
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_text_file.py
@@ -0,0 +1,127 @@
+"""Tests for distutils.text_file."""
+
+from distutils.tests import support
+from distutils.text_file import TextFile
+
+import jaraco.path
+import path
+
+TEST_DATA = """# test file
+
+line 3 \\
+# intervening comment
+ continues on next line
+"""
+
+
+class TestTextFile(support.TempdirManager):
+ def test_class(self):
+ # old tests moved from text_file.__main__
+ # so they are really called by the buildbots
+
+ # result 1: no fancy options
+ result1 = [
+ '# test file\n',
+ '\n',
+ 'line 3 \\\n',
+ '# intervening comment\n',
+ ' continues on next line\n',
+ ]
+
+ # result 2: just strip comments
+ result2 = ["\n", "line 3 \\\n", " continues on next line\n"]
+
+ # result 3: just strip blank lines
+ result3 = [
+ "# test file\n",
+ "line 3 \\\n",
+ "# intervening comment\n",
+ " continues on next line\n",
+ ]
+
+ # result 4: default, strip comments, blank lines,
+ # and trailing whitespace
+ result4 = ["line 3 \\", " continues on next line"]
+
+ # result 5: strip comments and blanks, plus join lines (but don't
+ # "collapse" joined lines
+ result5 = ["line 3 continues on next line"]
+
+ # result 6: strip comments and blanks, plus join lines (and
+ # "collapse" joined lines
+ result6 = ["line 3 continues on next line"]
+
+ def test_input(count, description, file, expected_result):
+ result = file.readlines()
+ assert result == expected_result
+
+ tmp_path = path.Path(self.mkdtemp())
+ filename = tmp_path / 'test.txt'
+ jaraco.path.build({filename.name: TEST_DATA}, tmp_path)
+
+ in_file = TextFile(
+ filename,
+ strip_comments=False,
+ skip_blanks=False,
+ lstrip_ws=False,
+ rstrip_ws=False,
+ )
+ try:
+ test_input(1, "no processing", in_file, result1)
+ finally:
+ in_file.close()
+
+ in_file = TextFile(
+ filename,
+ strip_comments=True,
+ skip_blanks=False,
+ lstrip_ws=False,
+ rstrip_ws=False,
+ )
+ try:
+ test_input(2, "strip comments", in_file, result2)
+ finally:
+ in_file.close()
+
+ in_file = TextFile(
+ filename,
+ strip_comments=False,
+ skip_blanks=True,
+ lstrip_ws=False,
+ rstrip_ws=False,
+ )
+ try:
+ test_input(3, "strip blanks", in_file, result3)
+ finally:
+ in_file.close()
+
+ in_file = TextFile(filename)
+ try:
+ test_input(4, "default processing", in_file, result4)
+ finally:
+ in_file.close()
+
+ in_file = TextFile(
+ filename,
+ strip_comments=True,
+ skip_blanks=True,
+ join_lines=True,
+ rstrip_ws=True,
+ )
+ try:
+ test_input(5, "join lines without collapsing", in_file, result5)
+ finally:
+ in_file.close()
+
+ in_file = TextFile(
+ filename,
+ strip_comments=True,
+ skip_blanks=True,
+ join_lines=True,
+ rstrip_ws=True,
+ collapse_join=True,
+ )
+ try:
+ test_input(6, "join lines with collapsing", in_file, result6)
+ finally:
+ in_file.close()
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_util.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_util.py
new file mode 100644
index 00000000..00c9743e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_util.py
@@ -0,0 +1,243 @@
+"""Tests for distutils.util."""
+
+import email
+import email.generator
+import email.policy
+import io
+import os
+import pathlib
+import sys
+import sysconfig as stdlib_sysconfig
+import unittest.mock as mock
+from copy import copy
+from distutils import sysconfig, util
+from distutils.errors import DistutilsByteCompileError, DistutilsPlatformError
+from distutils.util import (
+ byte_compile,
+ change_root,
+ check_environ,
+ convert_path,
+ get_host_platform,
+ get_platform,
+ grok_environment_error,
+ rfc822_escape,
+ split_quoted,
+ strtobool,
+)
+
+import pytest
+
+
+@pytest.fixture(autouse=True)
+def environment(monkeypatch):
+ monkeypatch.setattr(os, 'name', os.name)
+ monkeypatch.setattr(sys, 'platform', sys.platform)
+ monkeypatch.setattr(sys, 'version', sys.version)
+ monkeypatch.setattr(os, 'sep', os.sep)
+ monkeypatch.setattr(os.path, 'join', os.path.join)
+ monkeypatch.setattr(os.path, 'isabs', os.path.isabs)
+ monkeypatch.setattr(os.path, 'splitdrive', os.path.splitdrive)
+ monkeypatch.setattr(sysconfig, '_config_vars', copy(sysconfig._config_vars))
+
+
+@pytest.mark.usefixtures('save_env')
+class TestUtil:
+ def test_get_host_platform(self):
+ with mock.patch('os.name', 'nt'):
+ with mock.patch('sys.version', '... [... (ARM64)]'):
+ assert get_host_platform() == 'win-arm64'
+ with mock.patch('sys.version', '... [... (ARM)]'):
+ assert get_host_platform() == 'win-arm32'
+
+ with mock.patch('sys.version_info', (3, 9, 0, 'final', 0)):
+ assert get_host_platform() == stdlib_sysconfig.get_platform()
+
+ def test_get_platform(self):
+ with mock.patch('os.name', 'nt'):
+ with mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'x86'}):
+ assert get_platform() == 'win32'
+ with mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'x64'}):
+ assert get_platform() == 'win-amd64'
+ with mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'arm'}):
+ assert get_platform() == 'win-arm32'
+ with mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'arm64'}):
+ assert get_platform() == 'win-arm64'
+
+ def test_convert_path(self):
+ expected = os.sep.join(('', 'home', 'to', 'my', 'stuff'))
+ assert convert_path('/home/to/my/stuff') == expected
+ assert convert_path(pathlib.Path('/home/to/my/stuff')) == expected
+ assert convert_path('.') == os.curdir
+
+ def test_change_root(self):
+ # linux/mac
+ os.name = 'posix'
+
+ def _isabs(path):
+ return path[0] == '/'
+
+ os.path.isabs = _isabs
+
+ def _join(*path):
+ return '/'.join(path)
+
+ os.path.join = _join
+
+ assert change_root('/root', '/old/its/here') == '/root/old/its/here'
+ assert change_root('/root', 'its/here') == '/root/its/here'
+
+ # windows
+ os.name = 'nt'
+ os.sep = '\\'
+
+ def _isabs(path):
+ return path.startswith('c:\\')
+
+ os.path.isabs = _isabs
+
+ def _splitdrive(path):
+ if path.startswith('c:'):
+ return ('', path.replace('c:', ''))
+ return ('', path)
+
+ os.path.splitdrive = _splitdrive
+
+ def _join(*path):
+ return '\\'.join(path)
+
+ os.path.join = _join
+
+ assert (
+ change_root('c:\\root', 'c:\\old\\its\\here') == 'c:\\root\\old\\its\\here'
+ )
+ assert change_root('c:\\root', 'its\\here') == 'c:\\root\\its\\here'
+
+ # BugsBunny os (it's a great os)
+ os.name = 'BugsBunny'
+ with pytest.raises(DistutilsPlatformError):
+ change_root('c:\\root', 'its\\here')
+
+ # XXX platforms to be covered: mac
+
+ def test_check_environ(self):
+ util.check_environ.cache_clear()
+ os.environ.pop('HOME', None)
+
+ check_environ()
+
+ assert os.environ['PLAT'] == get_platform()
+
+ @pytest.mark.skipif("os.name != 'posix'")
+ def test_check_environ_getpwuid(self):
+ util.check_environ.cache_clear()
+ os.environ.pop('HOME', None)
+
+ import pwd
+
+ # only set pw_dir field, other fields are not used
+ result = pwd.struct_passwd((
+ None,
+ None,
+ None,
+ None,
+ None,
+ '/home/distutils',
+ None,
+ ))
+ with mock.patch.object(pwd, 'getpwuid', return_value=result):
+ check_environ()
+ assert os.environ['HOME'] == '/home/distutils'
+
+ util.check_environ.cache_clear()
+ os.environ.pop('HOME', None)
+
+ # bpo-10496: Catch pwd.getpwuid() error
+ with mock.patch.object(pwd, 'getpwuid', side_effect=KeyError):
+ check_environ()
+ assert 'HOME' not in os.environ
+
+ def test_split_quoted(self):
+ assert split_quoted('""one"" "two" \'three\' \\four') == [
+ 'one',
+ 'two',
+ 'three',
+ 'four',
+ ]
+
+ def test_strtobool(self):
+ yes = ('y', 'Y', 'yes', 'True', 't', 'true', 'True', 'On', 'on', '1')
+ no = ('n', 'no', 'f', 'false', 'off', '0', 'Off', 'No', 'N')
+
+ for y in yes:
+ assert strtobool(y)
+
+ for n in no:
+ assert not strtobool(n)
+
+ indent = 8 * ' '
+
+ @pytest.mark.parametrize(
+ "given,wanted",
+ [
+ # 0x0b, 0x0c, ..., etc are also considered a line break by Python
+ ("hello\x0b\nworld\n", f"hello\x0b{indent}\n{indent}world\n{indent}"),
+ ("hello\x1eworld", f"hello\x1e{indent}world"),
+ ("", ""),
+ (
+ "I am a\npoor\nlonesome\nheader\n",
+ f"I am a\n{indent}poor\n{indent}lonesome\n{indent}header\n{indent}",
+ ),
+ ],
+ )
+ def test_rfc822_escape(self, given, wanted):
+ """
+ We want to ensure a multi-line header parses correctly.
+
+ For interoperability, the escaped value should also "round-trip" over
+ `email.generator.Generator.flatten` and `email.message_from_*`
+ (see pypa/setuptools#4033).
+
+ The main issue is that internally `email.policy.EmailPolicy` uses
+ `splitlines` which will split on some control chars. If all the new lines
+ are not prefixed with spaces, the parser will interrupt reading
+ the current header and produce an incomplete value, while
+ incorrectly interpreting the rest of the headers as part of the payload.
+ """
+ res = rfc822_escape(given)
+
+ policy = email.policy.EmailPolicy(
+ utf8=True,
+ mangle_from_=False,
+ max_line_length=0,
+ )
+ with io.StringIO() as buffer:
+ raw = f"header: {res}\nother-header: 42\n\npayload\n"
+ orig = email.message_from_string(raw)
+ email.generator.Generator(buffer, policy=policy).flatten(orig)
+ buffer.seek(0)
+ regen = email.message_from_file(buffer)
+
+ for msg in (orig, regen):
+ assert msg.get_payload() == "payload\n"
+ assert msg["other-header"] == "42"
+ # Generator may replace control chars with `\n`
+ assert set(msg["header"].splitlines()) == set(res.splitlines())
+
+ assert res == wanted
+
+ def test_dont_write_bytecode(self):
+ # makes sure byte_compile raise a DistutilsError
+ # if sys.dont_write_bytecode is True
+ old_dont_write_bytecode = sys.dont_write_bytecode
+ sys.dont_write_bytecode = True
+ try:
+ with pytest.raises(DistutilsByteCompileError):
+ byte_compile([])
+ finally:
+ sys.dont_write_bytecode = old_dont_write_bytecode
+
+ def test_grok_environment_error(self):
+ # test obsolete function to ensure backward compat (#4931)
+ exc = OSError("Unable to find batch file")
+ msg = grok_environment_error(exc)
+ assert msg == "error: Unable to find batch file"
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_version.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_version.py
new file mode 100644
index 00000000..b68f0977
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_version.py
@@ -0,0 +1,80 @@
+"""Tests for distutils.version."""
+
+import distutils
+from distutils.version import LooseVersion, StrictVersion
+
+import pytest
+
+
+@pytest.fixture(autouse=True)
+def suppress_deprecation():
+ with distutils.version.suppress_known_deprecation():
+ yield
+
+
+class TestVersion:
+ def test_prerelease(self):
+ version = StrictVersion('1.2.3a1')
+ assert version.version == (1, 2, 3)
+ assert version.prerelease == ('a', 1)
+ assert str(version) == '1.2.3a1'
+
+ version = StrictVersion('1.2.0')
+ assert str(version) == '1.2'
+
+ def test_cmp_strict(self):
+ versions = (
+ ('1.5.1', '1.5.2b2', -1),
+ ('161', '3.10a', ValueError),
+ ('8.02', '8.02', 0),
+ ('3.4j', '1996.07.12', ValueError),
+ ('3.2.pl0', '3.1.1.6', ValueError),
+ ('2g6', '11g', ValueError),
+ ('0.9', '2.2', -1),
+ ('1.2.1', '1.2', 1),
+ ('1.1', '1.2.2', -1),
+ ('1.2', '1.1', 1),
+ ('1.2.1', '1.2.2', -1),
+ ('1.2.2', '1.2', 1),
+ ('1.2', '1.2.2', -1),
+ ('0.4.0', '0.4', 0),
+ ('1.13++', '5.5.kw', ValueError),
+ )
+
+ for v1, v2, wanted in versions:
+ try:
+ res = StrictVersion(v1)._cmp(StrictVersion(v2))
+ except ValueError:
+ if wanted is ValueError:
+ continue
+ else:
+ raise AssertionError(f"cmp({v1}, {v2}) shouldn't raise ValueError")
+ assert res == wanted, f'cmp({v1}, {v2}) should be {wanted}, got {res}'
+ res = StrictVersion(v1)._cmp(v2)
+ assert res == wanted, f'cmp({v1}, {v2}) should be {wanted}, got {res}'
+ res = StrictVersion(v1)._cmp(object())
+ assert res is NotImplemented, (
+ f'cmp({v1}, {v2}) should be NotImplemented, got {res}'
+ )
+
+ def test_cmp(self):
+ versions = (
+ ('1.5.1', '1.5.2b2', -1),
+ ('161', '3.10a', 1),
+ ('8.02', '8.02', 0),
+ ('3.4j', '1996.07.12', -1),
+ ('3.2.pl0', '3.1.1.6', 1),
+ ('2g6', '11g', -1),
+ ('0.960923', '2.2beta29', -1),
+ ('1.13++', '5.5.kw', -1),
+ )
+
+ for v1, v2, wanted in versions:
+ res = LooseVersion(v1)._cmp(LooseVersion(v2))
+ assert res == wanted, f'cmp({v1}, {v2}) should be {wanted}, got {res}'
+ res = LooseVersion(v1)._cmp(v2)
+ assert res == wanted, f'cmp({v1}, {v2}) should be {wanted}, got {res}'
+ res = LooseVersion(v1)._cmp(object())
+ assert res is NotImplemented, (
+ f'cmp({v1}, {v2}) should be NotImplemented, got {res}'
+ )
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_versionpredicate.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_versionpredicate.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/test_versionpredicate.py
diff --git a/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/unix_compat.py b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/unix_compat.py
new file mode 100644
index 00000000..a5d9ee45
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/_distutils/tests/unix_compat.py
@@ -0,0 +1,17 @@
+import sys
+
+try:
+ import grp
+ import pwd
+except ImportError:
+ grp = pwd = None
+
+import pytest
+
+UNIX_ID_SUPPORT = grp and pwd
+UID_0_SUPPORT = UNIX_ID_SUPPORT and sys.platform != "cygwin"
+
+require_unix_id = pytest.mark.skipif(
+ not UNIX_ID_SUPPORT, reason="Requires grp and pwd support"
+)
+require_uid_0 = pytest.mark.skipif(not UID_0_SUPPORT, reason="Requires UID 0 support")