Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_build_py.py481 linesDownload Raw Back to tests
1import os2import shutil3import stat4import warnings5from pathlib import Path6from unittest.mock import Mock7 8import jaraco.path9import pytest10 11from setuptools import SetuptoolsDeprecationWarning12from setuptools.dist import Distribution13 14from .textwrap import DALS15 16 17def test_directories_in_package_data_glob(tmpdir_cwd):18    """19    Directories matching the glob in package_data should20    not be included in the package data.21 22    Regression test for #261.23    """24    dist = Distribution(25        dict(26            script_name='setup.py',27            script_args=['build_py'],28            packages=[''],29            package_data={'': ['path/*']},30        )31    )32    os.makedirs('path/subpath')33    dist.parse_command_line()34    dist.run_commands()35 36 37def test_recursive_in_package_data_glob(tmpdir_cwd):38    """39    Files matching recursive globs (**) in package_data should40    be included in the package data.41 42    #180643    """44    dist = Distribution(45        dict(46            script_name='setup.py',47            script_args=['build_py'],48            packages=[''],49            package_data={'': ['path/**/data']},50        )51    )52    os.makedirs('path/subpath/subsubpath')53    open('path/subpath/subsubpath/data', 'wb').close()54 55    dist.parse_command_line()56    dist.run_commands()57 58    assert stat.S_ISREG(os.stat('build/lib/path/subpath/subsubpath/data').st_mode), (59        "File is not included"60    )61 62 63def test_read_only(tmpdir_cwd):64    """65    Ensure read-only flag is not preserved in copy66    for package modules and package data, as that67    causes problems with deleting read-only files on68    Windows.69 70    #145171    """72    dist = Distribution(73        dict(74            script_name='setup.py',75            script_args=['build_py'],76            packages=['pkg'],77            package_data={'pkg': ['data.dat']},78        )79    )80    os.makedirs('pkg')81    open('pkg/__init__.py', 'wb').close()82    open('pkg/data.dat', 'wb').close()83    os.chmod('pkg/__init__.py', stat.S_IREAD)84    os.chmod('pkg/data.dat', stat.S_IREAD)85    dist.parse_command_line()86    dist.run_commands()87    shutil.rmtree('build')88 89 90@pytest.mark.xfail(91    'platform.system() == "Windows"',92    reason="On Windows, files do not have executable bits",93    raises=AssertionError,94    strict=True,95)96def test_executable_data(tmpdir_cwd):97    """98    Ensure executable bit is preserved in copy for99    package data, as users rely on it for scripts.100 101    #2041102    """103    dist = Distribution(104        dict(105            script_name='setup.py',106            script_args=['build_py'],107            packages=['pkg'],108            package_data={'pkg': ['run-me']},109        )110    )111    os.makedirs('pkg')112    open('pkg/__init__.py', 'wb').close()113    open('pkg/run-me', 'wb').close()114    os.chmod('pkg/run-me', 0o700)115 116    dist.parse_command_line()117    dist.run_commands()118 119    assert os.stat('build/lib/pkg/run-me').st_mode & stat.S_IEXEC, (120        "Script is not executable"121    )122 123 124EXAMPLE_WITH_MANIFEST = {125    "setup.cfg": DALS(126        """127        [metadata]128        name = mypkg129        version = 42130 131        [options]132        include_package_data = True133        packages = find:134 135        [options.packages.find]136        exclude = *.tests*137        """138    ),139    "mypkg": {140        "__init__.py": "",141        "resource_file.txt": "",142        "tests": {143            "__init__.py": "",144            "test_mypkg.py": "",145            "test_file.txt": "",146        },147    },148    "MANIFEST.in": DALS(149        """150        global-include *.py *.txt151        global-exclude *.py[cod]152        prune dist153        prune build154        prune *.egg-info155        """156    ),157}158 159 160def test_excluded_subpackages(tmpdir_cwd):161    jaraco.path.build(EXAMPLE_WITH_MANIFEST)162    dist = Distribution({"script_name": "%PEP 517%"})163    dist.parse_config_files()164 165    build_py = dist.get_command_obj("build_py")166 167    msg = r"Python recognizes 'mypkg\.tests' as an importable package"168    with pytest.warns(SetuptoolsDeprecationWarning, match=msg):  # noqa: PT031169        # TODO: To fix #3260 we need some transition period to deprecate the170        # existing behavior of `include_package_data`. After the transition, we171        # should remove the warning and fix the behavior.172 173        if os.getenv("SETUPTOOLS_USE_DISTUTILS") == "stdlib":174            # pytest.warns reset the warning filter temporarily175            # https://github.com/pytest-dev/pytest/issues/4011#issuecomment-423494810176            warnings.filterwarnings(177                "ignore",178                "'encoding' argument not specified",179                module="distutils.text_file",180                # This warning is already fixed in pypa/distutils but not in stdlib181            )182 183        build_py.finalize_options()184        build_py.run()185 186    build_dir = Path(dist.get_command_obj("build_py").build_lib)187    assert (build_dir / "mypkg/__init__.py").exists()188    assert (build_dir / "mypkg/resource_file.txt").exists()189 190    # Setuptools is configured to ignore `mypkg.tests`, therefore the following191    # files/dirs should not be included in the distribution.192    for f in [193        "mypkg/tests/__init__.py",194        "mypkg/tests/test_mypkg.py",195        "mypkg/tests/test_file.txt",196        "mypkg/tests",197    ]:198        with pytest.raises(AssertionError):199            # TODO: Enforce the following assertion once #3260 is fixed200            # (remove context manager and the following xfail).201            assert not (build_dir / f).exists()202 203    pytest.xfail("#3260")204 205 206@pytest.mark.filterwarnings("ignore::setuptools.SetuptoolsDeprecationWarning")207def test_existing_egg_info(tmpdir_cwd, monkeypatch):208    """When provided with the ``existing_egg_info_dir`` attribute, build_py should not209    attempt to run egg_info again.210    """211    # == Pre-condition ==212    # Generate an egg-info dir213    jaraco.path.build(EXAMPLE_WITH_MANIFEST)214    dist = Distribution({"script_name": "%PEP 517%"})215    dist.parse_config_files()216    assert dist.include_package_data217 218    egg_info = dist.get_command_obj("egg_info")219    dist.run_command("egg_info")220    egg_info_dir = next(Path(egg_info.egg_base).glob("*.egg-info"))221    assert egg_info_dir.is_dir()222 223    # == Setup ==224    build_py = dist.get_command_obj("build_py")225    build_py.finalize_options()226    egg_info = dist.get_command_obj("egg_info")227    egg_info_run = Mock(side_effect=egg_info.run)228    monkeypatch.setattr(egg_info, "run", egg_info_run)229 230    # == Remove caches ==231    # egg_info is called when build_py looks for data_files, which gets cached.232    # We need to ensure it is not cached yet, otherwise it may impact on the tests233    build_py.__dict__.pop('data_files', None)234    dist.reinitialize_command(egg_info)235 236    # == Sanity check ==237    # Ensure that if existing_egg_info is not given, build_py attempts to run egg_info238    build_py.existing_egg_info_dir = None239    build_py.run()240    egg_info_run.assert_called()241 242    # == Remove caches ==243    egg_info_run.reset_mock()244    build_py.__dict__.pop('data_files', None)245    dist.reinitialize_command(egg_info)246 247    # == Actual test ==248    # Ensure that if existing_egg_info_dir is given, egg_info doesn't run249    build_py.existing_egg_info_dir = egg_info_dir250    build_py.run()251    egg_info_run.assert_not_called()252    assert build_py.data_files253 254    # Make sure the list of outputs is actually OK255    outputs = map(lambda x: x.replace(os.sep, "/"), build_py.get_outputs())256    assert outputs257    example = str(Path(build_py.build_lib, "mypkg/__init__.py")).replace(os.sep, "/")258    assert example in outputs259 260 261EXAMPLE_ARBITRARY_MAPPING = {262    "pyproject.toml": DALS(263        """264        [project]265        name = "mypkg"266        version = "42"267 268        [tool.setuptools]269        packages = ["mypkg", "mypkg.sub1", "mypkg.sub2", "mypkg.sub2.nested"]270 271        [tool.setuptools.package-dir]272        "" = "src"273        "mypkg.sub2" = "src/mypkg/_sub2"274        "mypkg.sub2.nested" = "other"275        """276    ),277    "src": {278        "mypkg": {279            "__init__.py": "",280            "resource_file.txt": "",281            "sub1": {282                "__init__.py": "",283                "mod1.py": "",284            },285            "_sub2": {286                "mod2.py": "",287            },288        },289    },290    "other": {291        "__init__.py": "",292        "mod3.py": "",293    },294    "MANIFEST.in": DALS(295        """296        global-include *.py *.txt297        global-exclude *.py[cod]298        """299    ),300}301 302 303def test_get_outputs(tmpdir_cwd):304    jaraco.path.build(EXAMPLE_ARBITRARY_MAPPING)305    dist = Distribution({"script_name": "%test%"})306    dist.parse_config_files()307 308    build_py = dist.get_command_obj("build_py")309    build_py.editable_mode = True310    build_py.ensure_finalized()311    build_lib = build_py.build_lib.replace(os.sep, "/")312    outputs = {x.replace(os.sep, "/") for x in build_py.get_outputs()}313    assert outputs == {314        f"{build_lib}/mypkg/__init__.py",315        f"{build_lib}/mypkg/resource_file.txt",316        f"{build_lib}/mypkg/sub1/__init__.py",317        f"{build_lib}/mypkg/sub1/mod1.py",318        f"{build_lib}/mypkg/sub2/mod2.py",319        f"{build_lib}/mypkg/sub2/nested/__init__.py",320        f"{build_lib}/mypkg/sub2/nested/mod3.py",321    }322    mapping = {323        k.replace(os.sep, "/"): v.replace(os.sep, "/")324        for k, v in build_py.get_output_mapping().items()325    }326    assert mapping == {327        f"{build_lib}/mypkg/__init__.py": "src/mypkg/__init__.py",328        f"{build_lib}/mypkg/resource_file.txt": "src/mypkg/resource_file.txt",329        f"{build_lib}/mypkg/sub1/__init__.py": "src/mypkg/sub1/__init__.py",330        f"{build_lib}/mypkg/sub1/mod1.py": "src/mypkg/sub1/mod1.py",331        f"{build_lib}/mypkg/sub2/mod2.py": "src/mypkg/_sub2/mod2.py",332        f"{build_lib}/mypkg/sub2/nested/__init__.py": "other/__init__.py",333        f"{build_lib}/mypkg/sub2/nested/mod3.py": "other/mod3.py",334    }335 336 337class TestTypeInfoFiles:338    PYPROJECTS = {339        "default_pyproject": DALS(340            """341            [project]342            name = "foo"343            version = "1"344            """345        ),346        "dont_include_package_data": DALS(347            """348            [project]349            name = "foo"350            version = "1"351 352            [tool.setuptools]353            include-package-data = false354            """355        ),356        "exclude_type_info": DALS(357            """358            [project]359            name = "foo"360            version = "1"361 362            [tool.setuptools]363            include-package-data = false364 365            [tool.setuptools.exclude-package-data]366            "*" = ["py.typed", "*.pyi"]367            """368        ),369    }370 371    EXAMPLES = {372        "simple_namespace": {373            "directory_structure": {374                "foo": {375                    "bar.pyi": "",376                    "py.typed": "",377                    "__init__.py": "",378                }379            },380            "expected_type_files": {"foo/bar.pyi", "foo/py.typed"},381        },382        "nested_inside_namespace": {383            "directory_structure": {384                "foo": {385                    "bar": {386                        "py.typed": "",387                        "mod.pyi": "",388                    }389                }390            },391            "expected_type_files": {"foo/bar/mod.pyi", "foo/bar/py.typed"},392        },393        "namespace_nested_inside_regular": {394            "directory_structure": {395                "foo": {396                    "namespace": {397                        "foo.pyi": "",398                    },399                    "__init__.pyi": "",400                    "py.typed": "",401                }402            },403            "expected_type_files": {404                "foo/namespace/foo.pyi",405                "foo/__init__.pyi",406                "foo/py.typed",407            },408        },409    }410 411    @pytest.mark.parametrize(412        "pyproject",413        [414            "default_pyproject",415            pytest.param(416                "dont_include_package_data",417                marks=pytest.mark.xfail(reason="pypa/setuptools#4350"),418            ),419        ],420    )421    @pytest.mark.parametrize("example", EXAMPLES.keys())422    def test_type_files_included_by_default(self, tmpdir_cwd, pyproject, example):423        structure = {424            **self.EXAMPLES[example]["directory_structure"],425            "pyproject.toml": self.PYPROJECTS[pyproject],426        }427        expected_type_files = self.EXAMPLES[example]["expected_type_files"]428        jaraco.path.build(structure)429 430        build_py = get_finalized_build_py()431        outputs = get_outputs(build_py)432        assert expected_type_files <= outputs433 434    @pytest.mark.parametrize("pyproject", ["exclude_type_info"])435    @pytest.mark.parametrize("example", EXAMPLES.keys())436    def test_type_files_can_be_excluded(self, tmpdir_cwd, pyproject, example):437        structure = {438            **self.EXAMPLES[example]["directory_structure"],439            "pyproject.toml": self.PYPROJECTS[pyproject],440        }441        expected_type_files = self.EXAMPLES[example]["expected_type_files"]442        jaraco.path.build(structure)443 444        build_py = get_finalized_build_py()445        outputs = get_outputs(build_py)446        assert expected_type_files.isdisjoint(outputs)447 448    def test_stub_only_package(self, tmpdir_cwd):449        structure = {450            "pyproject.toml": DALS(451                """452                [project]453                name = "foo-stubs"454                version = "1"455                """456            ),457            "foo-stubs": {"__init__.pyi": "", "bar.pyi": ""},458        }459        expected_type_files = {"foo-stubs/__init__.pyi", "foo-stubs/bar.pyi"}460        jaraco.path.build(structure)461 462        build_py = get_finalized_build_py()463        outputs = get_outputs(build_py)464        assert expected_type_files <= outputs465 466 467def get_finalized_build_py(script_name="%build_py-test%"):468    dist = Distribution({"script_name": script_name})469    dist.parse_config_files()470    build_py = dist.get_command_obj("build_py")471    build_py.finalize_options()472    return build_py473 474 475def get_outputs(build_py):476    build_dir = Path(build_py.build_lib)477    return {478        os.path.relpath(x, build_dir).replace(os.sep, "/")479        for x in build_py.get_outputs()480    }481 
codekingpro/portable-devtools · Team Ai