about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/setuptools/tests/test_build_py.py
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/tests/test_build_py.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/setuptools/tests/test_build_py.py')
-rw-r--r--.venv/lib/python3.12/site-packages/setuptools/tests/test_build_py.py480
1 files changed, 480 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/setuptools/tests/test_build_py.py b/.venv/lib/python3.12/site-packages/setuptools/tests/test_build_py.py
new file mode 100644
index 00000000..1e3a6608
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/setuptools/tests/test_build_py.py
@@ -0,0 +1,480 @@
+import os
+import shutil
+import stat
+import warnings
+from pathlib import Path
+from unittest.mock import Mock
+
+import jaraco.path
+import pytest
+
+from setuptools import SetuptoolsDeprecationWarning
+from setuptools.dist import Distribution
+
+from .textwrap import DALS
+
+
+def test_directories_in_package_data_glob(tmpdir_cwd):
+    """
+    Directories matching the glob in package_data should
+    not be included in the package data.
+
+    Regression test for #261.
+    """
+    dist = Distribution(
+        dict(
+            script_name='setup.py',
+            script_args=['build_py'],
+            packages=[''],
+            package_data={'': ['path/*']},
+        )
+    )
+    os.makedirs('path/subpath')
+    dist.parse_command_line()
+    dist.run_commands()
+
+
+def test_recursive_in_package_data_glob(tmpdir_cwd):
+    """
+    Files matching recursive globs (**) in package_data should
+    be included in the package data.
+
+    #1806
+    """
+    dist = Distribution(
+        dict(
+            script_name='setup.py',
+            script_args=['build_py'],
+            packages=[''],
+            package_data={'': ['path/**/data']},
+        )
+    )
+    os.makedirs('path/subpath/subsubpath')
+    open('path/subpath/subsubpath/data', 'wb').close()
+
+    dist.parse_command_line()
+    dist.run_commands()
+
+    assert stat.S_ISREG(os.stat('build/lib/path/subpath/subsubpath/data').st_mode), (
+        "File is not included"
+    )
+
+
+def test_read_only(tmpdir_cwd):
+    """
+    Ensure read-only flag is not preserved in copy
+    for package modules and package data, as that
+    causes problems with deleting read-only files on
+    Windows.
+
+    #1451
+    """
+    dist = Distribution(
+        dict(
+            script_name='setup.py',
+            script_args=['build_py'],
+            packages=['pkg'],
+            package_data={'pkg': ['data.dat']},
+        )
+    )
+    os.makedirs('pkg')
+    open('pkg/__init__.py', 'wb').close()
+    open('pkg/data.dat', 'wb').close()
+    os.chmod('pkg/__init__.py', stat.S_IREAD)
+    os.chmod('pkg/data.dat', stat.S_IREAD)
+    dist.parse_command_line()
+    dist.run_commands()
+    shutil.rmtree('build')
+
+
+@pytest.mark.xfail(
+    'platform.system() == "Windows"',
+    reason="On Windows, files do not have executable bits",
+    raises=AssertionError,
+    strict=True,
+)
+def test_executable_data(tmpdir_cwd):
+    """
+    Ensure executable bit is preserved in copy for
+    package data, as users rely on it for scripts.
+
+    #2041
+    """
+    dist = Distribution(
+        dict(
+            script_name='setup.py',
+            script_args=['build_py'],
+            packages=['pkg'],
+            package_data={'pkg': ['run-me']},
+        )
+    )
+    os.makedirs('pkg')
+    open('pkg/__init__.py', 'wb').close()
+    open('pkg/run-me', 'wb').close()
+    os.chmod('pkg/run-me', 0o700)
+
+    dist.parse_command_line()
+    dist.run_commands()
+
+    assert os.stat('build/lib/pkg/run-me').st_mode & stat.S_IEXEC, (
+        "Script is not executable"
+    )
+
+
+EXAMPLE_WITH_MANIFEST = {
+    "setup.cfg": DALS(
+        """
+        [metadata]
+        name = mypkg
+        version = 42
+
+        [options]
+        include_package_data = True
+        packages = find:
+
+        [options.packages.find]
+        exclude = *.tests*
+        """
+    ),
+    "mypkg": {
+        "__init__.py": "",
+        "resource_file.txt": "",
+        "tests": {
+            "__init__.py": "",
+            "test_mypkg.py": "",
+            "test_file.txt": "",
+        },
+    },
+    "MANIFEST.in": DALS(
+        """
+        global-include *.py *.txt
+        global-exclude *.py[cod]
+        prune dist
+        prune build
+        prune *.egg-info
+        """
+    ),
+}
+
+
+def test_excluded_subpackages(tmpdir_cwd):
+    jaraco.path.build(EXAMPLE_WITH_MANIFEST)
+    dist = Distribution({"script_name": "%PEP 517%"})
+    dist.parse_config_files()
+
+    build_py = dist.get_command_obj("build_py")
+
+    msg = r"Python recognizes 'mypkg\.tests' as an importable package"
+    with pytest.warns(SetuptoolsDeprecationWarning, match=msg):
+        # TODO: To fix #3260 we need some transition period to deprecate the
+        # existing behavior of `include_package_data`. After the transition, we
+        # should remove the warning and fix the behavior.
+
+        if os.getenv("SETUPTOOLS_USE_DISTUTILS") == "stdlib":
+            # pytest.warns reset the warning filter temporarily
+            # https://github.com/pytest-dev/pytest/issues/4011#issuecomment-423494810
+            warnings.filterwarnings(
+                "ignore",
+                "'encoding' argument not specified",
+                module="distutils.text_file",
+                # This warning is already fixed in pypa/distutils but not in stdlib
+            )
+
+        build_py.finalize_options()
+        build_py.run()
+
+    build_dir = Path(dist.get_command_obj("build_py").build_lib)
+    assert (build_dir / "mypkg/__init__.py").exists()
+    assert (build_dir / "mypkg/resource_file.txt").exists()
+
+    # Setuptools is configured to ignore `mypkg.tests`, therefore the following
+    # files/dirs should not be included in the distribution.
+    for f in [
+        "mypkg/tests/__init__.py",
+        "mypkg/tests/test_mypkg.py",
+        "mypkg/tests/test_file.txt",
+        "mypkg/tests",
+    ]:
+        with pytest.raises(AssertionError):
+            # TODO: Enforce the following assertion once #3260 is fixed
+            # (remove context manager and the following xfail).
+            assert not (build_dir / f).exists()
+
+    pytest.xfail("#3260")
+
+
+@pytest.mark.filterwarnings("ignore::setuptools.SetuptoolsDeprecationWarning")
+def test_existing_egg_info(tmpdir_cwd, monkeypatch):
+    """When provided with the ``existing_egg_info_dir`` attribute, build_py should not
+    attempt to run egg_info again.
+    """
+    # == Pre-condition ==
+    # Generate an egg-info dir
+    jaraco.path.build(EXAMPLE_WITH_MANIFEST)
+    dist = Distribution({"script_name": "%PEP 517%"})
+    dist.parse_config_files()
+    assert dist.include_package_data
+
+    egg_info = dist.get_command_obj("egg_info")
+    dist.run_command("egg_info")
+    egg_info_dir = next(Path(egg_info.egg_base).glob("*.egg-info"))
+    assert egg_info_dir.is_dir()
+
+    # == Setup ==
+    build_py = dist.get_command_obj("build_py")
+    build_py.finalize_options()
+    egg_info = dist.get_command_obj("egg_info")
+    egg_info_run = Mock(side_effect=egg_info.run)
+    monkeypatch.setattr(egg_info, "run", egg_info_run)
+
+    # == Remove caches ==
+    # egg_info is called when build_py looks for data_files, which gets cached.
+    # We need to ensure it is not cached yet, otherwise it may impact on the tests
+    build_py.__dict__.pop('data_files', None)
+    dist.reinitialize_command(egg_info)
+
+    # == Sanity check ==
+    # Ensure that if existing_egg_info is not given, build_py attempts to run egg_info
+    build_py.existing_egg_info_dir = None
+    build_py.run()
+    egg_info_run.assert_called()
+
+    # == Remove caches ==
+    egg_info_run.reset_mock()
+    build_py.__dict__.pop('data_files', None)
+    dist.reinitialize_command(egg_info)
+
+    # == Actual test ==
+    # Ensure that if existing_egg_info_dir is given, egg_info doesn't run
+    build_py.existing_egg_info_dir = egg_info_dir
+    build_py.run()
+    egg_info_run.assert_not_called()
+    assert build_py.data_files
+
+    # Make sure the list of outputs is actually OK
+    outputs = map(lambda x: x.replace(os.sep, "/"), build_py.get_outputs())
+    assert outputs
+    example = str(Path(build_py.build_lib, "mypkg/__init__.py")).replace(os.sep, "/")
+    assert example in outputs
+
+
+EXAMPLE_ARBITRARY_MAPPING = {
+    "pyproject.toml": DALS(
+        """
+        [project]
+        name = "mypkg"
+        version = "42"
+
+        [tool.setuptools]
+        packages = ["mypkg", "mypkg.sub1", "mypkg.sub2", "mypkg.sub2.nested"]
+
+        [tool.setuptools.package-dir]
+        "" = "src"
+        "mypkg.sub2" = "src/mypkg/_sub2"
+        "mypkg.sub2.nested" = "other"
+        """
+    ),
+    "src": {
+        "mypkg": {
+            "__init__.py": "",
+            "resource_file.txt": "",
+            "sub1": {
+                "__init__.py": "",
+                "mod1.py": "",
+            },
+            "_sub2": {
+                "mod2.py": "",
+            },
+        },
+    },
+    "other": {
+        "__init__.py": "",
+        "mod3.py": "",
+    },
+    "MANIFEST.in": DALS(
+        """
+        global-include *.py *.txt
+        global-exclude *.py[cod]
+        """
+    ),
+}
+
+
+def test_get_outputs(tmpdir_cwd):
+    jaraco.path.build(EXAMPLE_ARBITRARY_MAPPING)
+    dist = Distribution({"script_name": "%test%"})
+    dist.parse_config_files()
+
+    build_py = dist.get_command_obj("build_py")
+    build_py.editable_mode = True
+    build_py.ensure_finalized()
+    build_lib = build_py.build_lib.replace(os.sep, "/")
+    outputs = {x.replace(os.sep, "/") for x in build_py.get_outputs()}
+    assert outputs == {
+        f"{build_lib}/mypkg/__init__.py",
+        f"{build_lib}/mypkg/resource_file.txt",
+        f"{build_lib}/mypkg/sub1/__init__.py",
+        f"{build_lib}/mypkg/sub1/mod1.py",
+        f"{build_lib}/mypkg/sub2/mod2.py",
+        f"{build_lib}/mypkg/sub2/nested/__init__.py",
+        f"{build_lib}/mypkg/sub2/nested/mod3.py",
+    }
+    mapping = {
+        k.replace(os.sep, "/"): v.replace(os.sep, "/")
+        for k, v in build_py.get_output_mapping().items()
+    }
+    assert mapping == {
+        f"{build_lib}/mypkg/__init__.py": "src/mypkg/__init__.py",
+        f"{build_lib}/mypkg/resource_file.txt": "src/mypkg/resource_file.txt",
+        f"{build_lib}/mypkg/sub1/__init__.py": "src/mypkg/sub1/__init__.py",
+        f"{build_lib}/mypkg/sub1/mod1.py": "src/mypkg/sub1/mod1.py",
+        f"{build_lib}/mypkg/sub2/mod2.py": "src/mypkg/_sub2/mod2.py",
+        f"{build_lib}/mypkg/sub2/nested/__init__.py": "other/__init__.py",
+        f"{build_lib}/mypkg/sub2/nested/mod3.py": "other/mod3.py",
+    }
+
+
+class TestTypeInfoFiles:
+    PYPROJECTS = {
+        "default_pyproject": DALS(
+            """
+            [project]
+            name = "foo"
+            version = "1"
+            """
+        ),
+        "dont_include_package_data": DALS(
+            """
+            [project]
+            name = "foo"
+            version = "1"
+
+            [tool.setuptools]
+            include-package-data = false
+            """
+        ),
+        "exclude_type_info": DALS(
+            """
+            [project]
+            name = "foo"
+            version = "1"
+
+            [tool.setuptools]
+            include-package-data = false
+
+            [tool.setuptools.exclude-package-data]
+            "*" = ["py.typed", "*.pyi"]
+            """
+        ),
+    }
+
+    EXAMPLES = {
+        "simple_namespace": {
+            "directory_structure": {
+                "foo": {
+                    "bar.pyi": "",
+                    "py.typed": "",
+                    "__init__.py": "",
+                }
+            },
+            "expected_type_files": {"foo/bar.pyi", "foo/py.typed"},
+        },
+        "nested_inside_namespace": {
+            "directory_structure": {
+                "foo": {
+                    "bar": {
+                        "py.typed": "",
+                        "mod.pyi": "",
+                    }
+                }
+            },
+            "expected_type_files": {"foo/bar/mod.pyi", "foo/bar/py.typed"},
+        },
+        "namespace_nested_inside_regular": {
+            "directory_structure": {
+                "foo": {
+                    "namespace": {
+                        "foo.pyi": "",
+                    },
+                    "__init__.pyi": "",
+                    "py.typed": "",
+                }
+            },
+            "expected_type_files": {
+                "foo/namespace/foo.pyi",
+                "foo/__init__.pyi",
+                "foo/py.typed",
+            },
+        },
+    }
+
+    @pytest.mark.parametrize(
+        "pyproject",
+        [
+            "default_pyproject",
+            pytest.param(
+                "dont_include_package_data",
+                marks=pytest.mark.xfail(reason="pypa/setuptools#4350"),
+            ),
+        ],
+    )
+    @pytest.mark.parametrize("example", EXAMPLES.keys())
+    def test_type_files_included_by_default(self, tmpdir_cwd, pyproject, example):
+        structure = {
+            **self.EXAMPLES[example]["directory_structure"],
+            "pyproject.toml": self.PYPROJECTS[pyproject],
+        }
+        expected_type_files = self.EXAMPLES[example]["expected_type_files"]
+        jaraco.path.build(structure)
+
+        build_py = get_finalized_build_py()
+        outputs = get_outputs(build_py)
+        assert expected_type_files <= outputs
+
+    @pytest.mark.parametrize("pyproject", ["exclude_type_info"])
+    @pytest.mark.parametrize("example", EXAMPLES.keys())
+    def test_type_files_can_be_excluded(self, tmpdir_cwd, pyproject, example):
+        structure = {
+            **self.EXAMPLES[example]["directory_structure"],
+            "pyproject.toml": self.PYPROJECTS[pyproject],
+        }
+        expected_type_files = self.EXAMPLES[example]["expected_type_files"]
+        jaraco.path.build(structure)
+
+        build_py = get_finalized_build_py()
+        outputs = get_outputs(build_py)
+        assert expected_type_files.isdisjoint(outputs)
+
+    def test_stub_only_package(self, tmpdir_cwd):
+        structure = {
+            "pyproject.toml": DALS(
+                """
+                [project]
+                name = "foo-stubs"
+                version = "1"
+                """
+            ),
+            "foo-stubs": {"__init__.pyi": "", "bar.pyi": ""},
+        }
+        expected_type_files = {"foo-stubs/__init__.pyi", "foo-stubs/bar.pyi"}
+        jaraco.path.build(structure)
+
+        build_py = get_finalized_build_py()
+        outputs = get_outputs(build_py)
+        assert expected_type_files <= outputs
+
+
+def get_finalized_build_py(script_name="%build_py-test%"):
+    dist = Distribution({"script_name": script_name})
+    dist.parse_config_files()
+    build_py = dist.get_command_obj("build_py")
+    build_py.finalize_options()
+    return build_py
+
+
+def get_outputs(build_py):
+    build_dir = Path(build_py.build_lib)
+    return {
+        os.path.relpath(x, build_dir).replace(os.sep, "/")
+        for x in build_py.get_outputs()
+    }