Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_setupcfg.py988 linesDownload Raw Back to config
1import configparser2import contextlib3import inspect4import re5import sys6from pathlib import Path7from unittest.mock import Mock, patch8 9import pytest10from packaging.requirements import InvalidRequirement11 12from setuptools.config.setupcfg import ConfigHandler, Target, read_configuration13from setuptools.dist import Distribution, _Distribution14from setuptools.warnings import SetuptoolsDeprecationWarning15 16from ..textwrap import DALS17 18from distutils.errors import DistutilsFileError, DistutilsOptionError19 20IS_PYPY = '__pypy__' in sys.builtin_module_names21 22 23class ErrConfigHandler(ConfigHandler[Target]):24    """Erroneous handler. Fails to implement required methods."""25 26    section_prefix = "**err**"27 28 29def make_package_dir(name, base_dir, ns=False):30    dir_package = base_dir31    for dir_name in name.split('/'):32        dir_package = dir_package.mkdir(dir_name)33    init_file = None34    if not ns:35        init_file = dir_package.join('__init__.py')36        init_file.write('')37    return dir_package, init_file38 39 40def fake_env(41    tmpdir, setup_cfg, setup_py=None, encoding='ascii', package_path='fake_package'42):43    if setup_py is None:44        setup_py = 'from setuptools import setup\nsetup()\n'45 46    tmpdir.join('setup.py').write(setup_py)47    config = tmpdir.join('setup.cfg')48    config.write(setup_cfg.encode(encoding), mode='wb')49 50    package_dir, init_file = make_package_dir(package_path, tmpdir)51 52    init_file.write(53        'VERSION = (1, 2, 3)\n'54        '\n'55        'VERSION_MAJOR = 1'56        '\n'57        'def get_version():\n'58        '    return [3, 4, 5, "dev"]\n'59        '\n'60    )61 62    return package_dir, config63 64 65@contextlib.contextmanager66def get_dist(tmpdir, kwargs_initial=None, parse=True):67    kwargs_initial = kwargs_initial or {}68 69    with tmpdir.as_cwd():70        dist = Distribution(kwargs_initial)71        dist.script_name = 'setup.py'72        parse and dist.parse_config_files()73 74        yield dist75 76 77def test_parsers_implemented():78    with pytest.raises(NotImplementedError):79        handler = ErrConfigHandler(None, {}, False, Mock())80        handler.parsers81 82 83class TestConfigurationReader:84    def test_basic(self, tmpdir):85        _, config = fake_env(86            tmpdir,87            '[metadata]\n'88            'version = 10.1.1\n'89            'keywords = one, two\n'90            '\n'91            '[options]\n'92            'scripts = bin/a.py, bin/b.py\n',93        )94        config_dict = read_configuration(str(config))95        assert config_dict['metadata']['version'] == '10.1.1'96        assert config_dict['metadata']['keywords'] == ['one', 'two']97        assert config_dict['options']['scripts'] == ['bin/a.py', 'bin/b.py']98 99    def test_no_config(self, tmpdir):100        with pytest.raises(DistutilsFileError):101            read_configuration(str(tmpdir.join('setup.cfg')))102 103    def test_ignore_errors(self, tmpdir):104        _, config = fake_env(105            tmpdir,106            '[metadata]\nversion = attr: none.VERSION\nkeywords = one, two\n',107        )108        with pytest.raises(ImportError):109            read_configuration(str(config))110 111        config_dict = read_configuration(str(config), ignore_option_errors=True)112 113        assert config_dict['metadata']['keywords'] == ['one', 'two']114        assert 'version' not in config_dict['metadata']115 116        config.remove()117 118 119class TestMetadata:120    def test_basic(self, tmpdir):121        fake_env(122            tmpdir,123            '[metadata]\n'124            'version = 10.1.1\n'125            'description = Some description\n'126            'long_description_content_type = text/something\n'127            'long_description = file: README\n'128            'name = fake_name\n'129            'keywords = one, two\n'130            'provides = package, package.sub\n'131            'license = otherlic\n'132            'download_url = http://test.test.com/test/\n'133            'maintainer_email = test@test.com\n',134        )135 136        tmpdir.join('README').write('readme contents\nline2')137 138        meta_initial = {139            # This will be used so `otherlic` won't replace it.140            'license': 'BSD 3-Clause License',141        }142 143        with get_dist(tmpdir, meta_initial) as dist:144            metadata = dist.metadata145 146            assert metadata.version == '10.1.1'147            assert metadata.description == 'Some description'148            assert metadata.long_description_content_type == 'text/something'149            assert metadata.long_description == 'readme contents\nline2'150            assert metadata.provides == ['package', 'package.sub']151            assert metadata.license == 'BSD 3-Clause License'152            assert metadata.name == 'fake_name'153            assert metadata.keywords == ['one', 'two']154            assert metadata.download_url == 'http://test.test.com/test/'155            assert metadata.maintainer_email == 'test@test.com'156 157    def test_license_cfg(self, tmpdir):158        fake_env(159            tmpdir,160            DALS(161                """162            [metadata]163            name=foo164            version=0.0.1165            license=Apache 2.0166            """167            ),168        )169 170        with get_dist(tmpdir) as dist:171            metadata = dist.metadata172 173            assert metadata.name == "foo"174            assert metadata.version == "0.0.1"175            assert metadata.license == "Apache 2.0"176 177    def test_file_mixed(self, tmpdir):178        fake_env(179            tmpdir,180            '[metadata]\nlong_description = file: README.rst, CHANGES.rst\n\n',181        )182 183        tmpdir.join('README.rst').write('readme contents\nline2')184        tmpdir.join('CHANGES.rst').write('changelog contents\nand stuff')185 186        with get_dist(tmpdir) as dist:187            assert dist.metadata.long_description == (188                'readme contents\nline2\nchangelog contents\nand stuff'189            )190 191    def test_file_sandboxed(self, tmpdir):192        tmpdir.ensure("README")193        project = tmpdir.join('depth1', 'depth2')194        project.ensure(dir=True)195        fake_env(project, '[metadata]\nlong_description = file: ../../README\n')196 197        with get_dist(project, parse=False) as dist:198            with pytest.raises(DistutilsOptionError):199                dist.parse_config_files()  # file: out of sandbox200 201    def test_aliases(self, tmpdir):202        fake_env(203            tmpdir,204            '[metadata]\n'205            'author_email = test@test.com\n'206            'home_page = http://test.test.com/test/\n'207            'summary = Short summary\n'208            'platform = a, b\n'209            'classifier =\n'210            '  Framework :: Django\n'211            '  Programming Language :: Python :: 3.5\n',212        )213 214        with get_dist(tmpdir) as dist:215            metadata = dist.metadata216            assert metadata.author_email == 'test@test.com'217            assert metadata.url == 'http://test.test.com/test/'218            assert metadata.description == 'Short summary'219            assert metadata.platforms == ['a', 'b']220            assert metadata.classifiers == [221                'Framework :: Django',222                'Programming Language :: Python :: 3.5',223            ]224 225    def test_multiline(self, tmpdir):226        fake_env(227            tmpdir,228            '[metadata]\n'229            'name = fake_name\n'230            'keywords =\n'231            '  one\n'232            '  two\n'233            'classifiers =\n'234            '  Framework :: Django\n'235            '  Programming Language :: Python :: 3.5\n',236        )237        with get_dist(tmpdir) as dist:238            metadata = dist.metadata239            assert metadata.keywords == ['one', 'two']240            assert metadata.classifiers == [241                'Framework :: Django',242                'Programming Language :: Python :: 3.5',243            ]244 245    def test_dict(self, tmpdir):246        fake_env(247            tmpdir,248            '[metadata]\n'249            'project_urls =\n'250            '  Link One = https://example.com/one/\n'251            '  Link Two = https://example.com/two/\n',252        )253        with get_dist(tmpdir) as dist:254            metadata = dist.metadata255            assert metadata.project_urls == {256                'Link One': 'https://example.com/one/',257                'Link Two': 'https://example.com/two/',258            }259 260    def test_version(self, tmpdir):261        package_dir, config = fake_env(262            tmpdir, '[metadata]\nversion = attr: fake_package.VERSION\n'263        )264 265        sub_a = package_dir.mkdir('subpkg_a')266        sub_a.join('__init__.py').write('')267        sub_a.join('mod.py').write('VERSION = (2016, 11, 26)')268 269        sub_b = package_dir.mkdir('subpkg_b')270        sub_b.join('__init__.py').write('')271        sub_b.join('mod.py').write(272            'import third_party_module\nVERSION = (2016, 11, 26)'273        )274 275        with get_dist(tmpdir) as dist:276            assert dist.metadata.version == '1.2.3'277 278        config.write('[metadata]\nversion = attr: fake_package.get_version\n')279        with get_dist(tmpdir) as dist:280            assert dist.metadata.version == '3.4.5.dev'281 282        config.write('[metadata]\nversion = attr: fake_package.VERSION_MAJOR\n')283        with get_dist(tmpdir) as dist:284            assert dist.metadata.version == '1'285 286        config.write('[metadata]\nversion = attr: fake_package.subpkg_a.mod.VERSION\n')287        with get_dist(tmpdir) as dist:288            assert dist.metadata.version == '2016.11.26'289 290        config.write('[metadata]\nversion = attr: fake_package.subpkg_b.mod.VERSION\n')291        with get_dist(tmpdir) as dist:292            assert dist.metadata.version == '2016.11.26'293 294    def test_version_file(self, tmpdir):295        fake_env(tmpdir, '[metadata]\nversion = file: fake_package/version.txt\n')296        tmpdir.join('fake_package', 'version.txt').write('1.2.3\n')297 298        with get_dist(tmpdir) as dist:299            assert dist.metadata.version == '1.2.3'300 301        tmpdir.join('fake_package', 'version.txt').write('1.2.3\n4.5.6\n')302        with pytest.raises(DistutilsOptionError):303            with get_dist(tmpdir) as dist:304                dist.metadata.version305 306    def test_version_with_package_dir_simple(self, tmpdir):307        fake_env(308            tmpdir,309            '[metadata]\n'310            'version = attr: fake_package_simple.VERSION\n'311            '[options]\n'312            'package_dir =\n'313            '    = src\n',314            package_path='src/fake_package_simple',315        )316 317        with get_dist(tmpdir) as dist:318            assert dist.metadata.version == '1.2.3'319 320    def test_version_with_package_dir_rename(self, tmpdir):321        fake_env(322            tmpdir,323            '[metadata]\n'324            'version = attr: fake_package_rename.VERSION\n'325            '[options]\n'326            'package_dir =\n'327            '    fake_package_rename = fake_dir\n',328            package_path='fake_dir',329        )330 331        with get_dist(tmpdir) as dist:332            assert dist.metadata.version == '1.2.3'333 334    def test_version_with_package_dir_complex(self, tmpdir):335        fake_env(336            tmpdir,337            '[metadata]\n'338            'version = attr: fake_package_complex.VERSION\n'339            '[options]\n'340            'package_dir =\n'341            '    fake_package_complex = src/fake_dir\n',342            package_path='src/fake_dir',343        )344 345        with get_dist(tmpdir) as dist:346            assert dist.metadata.version == '1.2.3'347 348    def test_unknown_meta_item(self, tmpdir):349        fake_env(tmpdir, '[metadata]\nname = fake_name\nunknown = some\n')350        with get_dist(tmpdir, parse=False) as dist:351            dist.parse_config_files()  # Skip unknown.352 353    def test_usupported_section(self, tmpdir):354        fake_env(tmpdir, '[metadata.some]\nkey = val\n')355        with get_dist(tmpdir, parse=False) as dist:356            with pytest.raises(DistutilsOptionError):357                dist.parse_config_files()358 359    def test_classifiers(self, tmpdir):360        expected = set([361            'Framework :: Django',362            'Programming Language :: Python :: 3',363            'Programming Language :: Python :: 3.5',364        ])365 366        # From file.367        _, config = fake_env(tmpdir, '[metadata]\nclassifiers = file: classifiers\n')368 369        tmpdir.join('classifiers').write(370            'Framework :: Django\n'371            'Programming Language :: Python :: 3\n'372            'Programming Language :: Python :: 3.5\n'373        )374 375        with get_dist(tmpdir) as dist:376            assert set(dist.metadata.classifiers) == expected377 378        # From list notation379        config.write(380            '[metadata]\n'381            'classifiers =\n'382            '    Framework :: Django\n'383            '    Programming Language :: Python :: 3\n'384            '    Programming Language :: Python :: 3.5\n'385        )386        with get_dist(tmpdir) as dist:387            assert set(dist.metadata.classifiers) == expected388 389    def test_interpolation(self, tmpdir):390        fake_env(tmpdir, '[metadata]\ndescription = %(message)s\n')391        with pytest.raises(configparser.InterpolationMissingOptionError):392            with get_dist(tmpdir):393                pass394 395    def test_non_ascii_1(self, tmpdir):396        fake_env(tmpdir, '[metadata]\ndescription = éàïôñ\n', encoding='utf-8')397        with get_dist(tmpdir):398            pass399 400    def test_non_ascii_3(self, tmpdir):401        fake_env(tmpdir, '\n# -*- coding: invalid\n')402        with get_dist(tmpdir):403            pass404 405    def test_non_ascii_4(self, tmpdir):406        fake_env(407            tmpdir,408            '# -*- coding: utf-8\n[metadata]\ndescription = éàïôñ\n',409            encoding='utf-8',410        )411        with get_dist(tmpdir) as dist:412            assert dist.metadata.description == 'éàïôñ'413 414    def test_not_utf8(self, tmpdir):415        """416        Config files encoded not in UTF-8 will fail417        """418        fake_env(419            tmpdir,420            '# vim: set fileencoding=iso-8859-15 :\n[metadata]\ndescription = éàïôñ\n',421            encoding='iso-8859-15',422        )423        with pytest.raises(UnicodeDecodeError):424            with get_dist(tmpdir):425                pass426 427    @pytest.mark.parametrize(428        ("error_msg", "config", "invalid"),429        [430            (431                "Invalid dash-separated key 'author-email' in 'metadata' (setup.cfg)",432                DALS(433                    """434                    [metadata]435                    author-email = test@test.com436                    maintainer_email = foo@foo.com437                    """438                ),439                {"author-email": "test@test.com"},440            ),441            (442                "Invalid uppercase key 'Name' in 'metadata' (setup.cfg)",443                DALS(444                    """445                    [metadata]446                    Name = foo447                    description = Some description448                    """449                ),450                {"Name": "foo"},451            ),452        ],453    )454    def test_invalid_options_previously_deprecated(455        self, tmpdir, error_msg, config, invalid456    ):457        # This test and related methods can be removed when no longer needed.458        # Deprecation postponed due to push-back from the community in459        # https://github.com/pypa/setuptools/issues/4910460        fake_env(tmpdir, config)461        with pytest.warns(SetuptoolsDeprecationWarning, match=re.escape(error_msg)):462            dist = get_dist(tmpdir).__enter__()463 464        tmpdir.join('setup.cfg').remove()465 466        for field, value in invalid.items():467            attr = field.replace("-", "_").lower()468            assert getattr(dist.metadata, attr) == value469 470 471class TestOptions:472    def test_basic(self, tmpdir):473        fake_env(474            tmpdir,475            '[options]\n'476            'zip_safe = True\n'477            'include_package_data = yes\n'478            'package_dir = b=c, =src\n'479            'packages = pack_a, pack_b.subpack\n'480            'namespace_packages = pack1, pack2\n'481            'scripts = bin/one.py, bin/two.py\n'482            'eager_resources = bin/one.py, bin/two.py\n'483            'install_requires = docutils>=0.3; pack ==1.1, ==1.3; hey\n'484            'setup_requires = docutils>=0.3; spack ==1.1, ==1.3; there\n'485            'dependency_links = http://some.com/here/1, '486            'http://some.com/there/2\n'487            'python_requires = >=1.0, !=2.8\n'488            'py_modules = module1, module2\n',489        )490        deprec = pytest.warns(SetuptoolsDeprecationWarning, match="namespace_packages")491        with deprec, get_dist(tmpdir) as dist:492            assert dist.zip_safe493            assert dist.include_package_data494            assert dist.package_dir == {'': 'src', 'b': 'c'}495            assert dist.packages == ['pack_a', 'pack_b.subpack']496            assert dist.namespace_packages == ['pack1', 'pack2']497            assert dist.scripts == ['bin/one.py', 'bin/two.py']498            assert dist.dependency_links == ([499                'http://some.com/here/1',500                'http://some.com/there/2',501            ])502            assert dist.install_requires == ([503                'docutils>=0.3',504                'pack==1.1,==1.3',505                'hey',506            ])507            assert dist.setup_requires == ([508                'docutils>=0.3',509                'spack ==1.1, ==1.3',510                'there',511            ])512            assert dist.python_requires == '>=1.0, !=2.8'513            assert dist.py_modules == ['module1', 'module2']514 515    def test_multiline(self, tmpdir):516        fake_env(517            tmpdir,518            '[options]\n'519            'package_dir = \n'520            '  b=c\n'521            '  =src\n'522            'packages = \n'523            '  pack_a\n'524            '  pack_b.subpack\n'525            'namespace_packages = \n'526            '  pack1\n'527            '  pack2\n'528            'scripts = \n'529            '  bin/one.py\n'530            '  bin/two.py\n'531            'eager_resources = \n'532            '  bin/one.py\n'533            '  bin/two.py\n'534            'install_requires = \n'535            '  docutils>=0.3\n'536            '  pack ==1.1, ==1.3\n'537            '  hey\n'538            'setup_requires = \n'539            '  docutils>=0.3\n'540            '  spack ==1.1, ==1.3\n'541            '  there\n'542            'dependency_links = \n'543            '  http://some.com/here/1\n'544            '  http://some.com/there/2\n',545        )546        deprec = pytest.warns(SetuptoolsDeprecationWarning, match="namespace_packages")547        with deprec, get_dist(tmpdir) as dist:548            assert dist.package_dir == {'': 'src', 'b': 'c'}549            assert dist.packages == ['pack_a', 'pack_b.subpack']550            assert dist.namespace_packages == ['pack1', 'pack2']551            assert dist.scripts == ['bin/one.py', 'bin/two.py']552            assert dist.dependency_links == ([553                'http://some.com/here/1',554                'http://some.com/there/2',555            ])556            assert dist.install_requires == ([557                'docutils>=0.3',558                'pack==1.1,==1.3',559                'hey',560            ])561            assert dist.setup_requires == ([562                'docutils>=0.3',563                'spack ==1.1, ==1.3',564                'there',565            ])566 567    def test_package_dir_fail(self, tmpdir):568        fake_env(tmpdir, '[options]\npackage_dir = a b\n')569        with get_dist(tmpdir, parse=False) as dist:570            with pytest.raises(DistutilsOptionError):571                dist.parse_config_files()572 573    def test_package_data(self, tmpdir):574        fake_env(575            tmpdir,576            '[options.package_data]\n'577            '* = *.txt, *.rst\n'578            'hello = *.msg\n'579            '\n'580            '[options.exclude_package_data]\n'581            '* = fake1.txt, fake2.txt\n'582            'hello = *.dat\n',583        )584 585        with get_dist(tmpdir) as dist:586            assert dist.package_data == {587                '': ['*.txt', '*.rst'],588                'hello': ['*.msg'],589            }590            assert dist.exclude_package_data == {591                '': ['fake1.txt', 'fake2.txt'],592                'hello': ['*.dat'],593            }594 595    def test_packages(self, tmpdir):596        fake_env(tmpdir, '[options]\npackages = find:\n')597 598        with get_dist(tmpdir) as dist:599            assert dist.packages == ['fake_package']600 601    def test_find_directive(self, tmpdir):602        dir_package, config = fake_env(tmpdir, '[options]\npackages = find:\n')603 604        make_package_dir('sub_one', dir_package)605        make_package_dir('sub_two', dir_package)606 607        with get_dist(tmpdir) as dist:608            assert set(dist.packages) == set([609                'fake_package',610                'fake_package.sub_two',611                'fake_package.sub_one',612            ])613 614        config.write(615            '[options]\n'616            'packages = find:\n'617            '\n'618            '[options.packages.find]\n'619            'where = .\n'620            'include =\n'621            '    fake_package.sub_one\n'622            '    two\n'623        )624        with get_dist(tmpdir) as dist:625            assert dist.packages == ['fake_package.sub_one']626 627        config.write(628            '[options]\n'629            'packages = find:\n'630            '\n'631            '[options.packages.find]\n'632            'exclude =\n'633            '    fake_package.sub_one\n'634        )635        with get_dist(tmpdir) as dist:636            assert set(dist.packages) == set(['fake_package', 'fake_package.sub_two'])637 638    def test_find_namespace_directive(self, tmpdir):639        dir_package, config = fake_env(640            tmpdir, '[options]\npackages = find_namespace:\n'641        )642 643        make_package_dir('sub_one', dir_package)644        make_package_dir('sub_two', dir_package, ns=True)645 646        with get_dist(tmpdir) as dist:647            assert set(dist.packages) == {648                'fake_package',649                'fake_package.sub_two',650                'fake_package.sub_one',651            }652 653        config.write(654            '[options]\n'655            'packages = find_namespace:\n'656            '\n'657            '[options.packages.find]\n'658            'where = .\n'659            'include =\n'660            '    fake_package.sub_one\n'661            '    two\n'662        )663        with get_dist(tmpdir) as dist:664            assert dist.packages == ['fake_package.sub_one']665 666        config.write(667            '[options]\n'668            'packages = find_namespace:\n'669            '\n'670            '[options.packages.find]\n'671            'exclude =\n'672            '    fake_package.sub_one\n'673        )674        with get_dist(tmpdir) as dist:675            assert set(dist.packages) == {'fake_package', 'fake_package.sub_two'}676 677    def test_extras_require(self, tmpdir):678        fake_env(679            tmpdir,680            '[options.extras_require]\n'681            'pdf = ReportLab>=1.2; RXP\n'682            'rest = \n'683            '  docutils>=0.3\n'684            '  pack ==1.1, ==1.3\n',685        )686 687        with get_dist(tmpdir) as dist:688            assert dist.extras_require == {689                'pdf': ['ReportLab>=1.2', 'RXP'],690                'rest': ['docutils>=0.3', 'pack==1.1,==1.3'],691            }692            assert set(dist.metadata.provides_extras) == {'pdf', 'rest'}693 694    @pytest.mark.parametrize(695        "config",696        [697            "[options.extras_require]\nfoo = bar;python_version<'3'",698            "[options.extras_require]\nfoo = bar;os_name=='linux'",699            "[options.extras_require]\nfoo = bar;python_version<'3'\n",700            "[options.extras_require]\nfoo = bar;os_name=='linux'\n",701            "[options]\ninstall_requires = bar;python_version<'3'",702            "[options]\ninstall_requires = bar;os_name=='linux'",703            "[options]\ninstall_requires = bar;python_version<'3'\n",704            "[options]\ninstall_requires = bar;os_name=='linux'\n",705        ],706    )707    @pytest.mark.xfail(IS_PYPY, reason="Exceptions missing on PyPy")708    # TODO: investigate PyPy problem709    def test_raises_accidental_env_marker_misconfig(self, config, tmpdir):710        fake_env(tmpdir, config)711        match = (712            r"One of the parsed requirements in `(install_requires|extras_require.+)` "713            "looks like a valid environment marker.*"714        )715        with pytest.raises(InvalidRequirement, match=match):716            with get_dist(tmpdir) as _:717                pass718 719    @pytest.mark.parametrize(720        "config",721        [722            "[options.extras_require]\nfoo = bar;python_version<3",723            "[options.extras_require]\nfoo = bar;python_version<3\n",724            "[options]\ninstall_requires = bar;python_version<3",725            "[options]\ninstall_requires = bar;python_version<3\n",726        ],727    )728    @pytest.mark.xfail(IS_PYPY, reason="Warnings missing on PyPy (minor issue)")729    # TODO: investigate PyPy problem730    def test_warn_accidental_env_marker_misconfig(self, config, tmpdir):731        fake_env(tmpdir, config)732        match = (733            r"One of the parsed requirements in `(install_requires|extras_require.+)` "734            "looks like a valid environment marker.*"735        )736        with pytest.warns(SetuptoolsDeprecationWarning, match=match):737            with get_dist(tmpdir) as _:738                pass739 740    @pytest.mark.parametrize(741        "config",742        [743            "[options.extras_require]\nfoo =\n    bar;python_version<'3'",744            "[options.extras_require]\nfoo = bar;baz\nboo = xxx;yyy",745            "[options.extras_require]\nfoo =\n    bar;python_version<'3'\n",746            "[options.extras_require]\nfoo = bar;baz\nboo = xxx;yyy\n",747            "[options.extras_require]\nfoo =\n    bar\n    python_version<3\n",748            "[options]\ninstall_requires =\n    bar;python_version<'3'",749            "[options]\ninstall_requires = bar;baz\nboo = xxx;yyy",750            "[options]\ninstall_requires =\n    bar;python_version<'3'\n",751            "[options]\ninstall_requires = bar;baz\nboo = xxx;yyy\n",752            "[options]\ninstall_requires =\n    bar\n    python_version<3\n",753        ],754    )755    @pytest.mark.filterwarnings("error::setuptools.SetuptoolsDeprecationWarning")756    def test_nowarn_accidental_env_marker_misconfig(self, config, tmpdir, recwarn):757        fake_env(tmpdir, config)758        num_warnings = len(recwarn)759        with get_dist(tmpdir) as _:760            pass761        # The examples are valid, no warnings shown762        assert len(recwarn) == num_warnings763 764    def test_dash_preserved_extras_require(self, tmpdir):765        fake_env(tmpdir, '[options.extras_require]\nfoo-a = foo\nfoo_b = test\n')766 767        with get_dist(tmpdir) as dist:768            assert dist.extras_require == {'foo-a': ['foo'], 'foo_b': ['test']}769 770    def test_entry_points(self, tmpdir):771        _, config = fake_env(772            tmpdir,773            '[options.entry_points]\n'774            'group1 = point1 = pack.module:func, '775            '.point2 = pack.module2:func_rest [rest]\n'776            'group2 = point3 = pack.module:func2\n',777        )778 779        with get_dist(tmpdir) as dist:780            assert dist.entry_points == {781                'group1': [782                    'point1 = pack.module:func',783                    '.point2 = pack.module2:func_rest [rest]',784                ],785                'group2': ['point3 = pack.module:func2'],786            }787 788        expected = (789            '[blogtool.parsers]\n'790            '.rst = some.nested.module:SomeClass.some_classmethod[reST]\n'791        )792 793        tmpdir.join('entry_points').write(expected)794 795        # From file.796        config.write('[options]\nentry_points = file: entry_points\n')797 798        with get_dist(tmpdir) as dist:799            assert dist.entry_points == expected800 801    def test_case_sensitive_entry_points(self, tmpdir):802        fake_env(803            tmpdir,804            '[options.entry_points]\n'805            'GROUP1 = point1 = pack.module:func, '806            '.point2 = pack.module2:func_rest [rest]\n'807            'group2 = point3 = pack.module:func2\n',808        )809 810        with get_dist(tmpdir) as dist:811            assert dist.entry_points == {812                'GROUP1': [813                    'point1 = pack.module:func',814                    '.point2 = pack.module2:func_rest [rest]',815                ],816                'group2': ['point3 = pack.module:func2'],817            }818 819    def test_data_files(self, tmpdir):820        fake_env(821            tmpdir,822            '[options.data_files]\n'823            'cfg =\n'824            '      a/b.conf\n'825            '      c/d.conf\n'826            'data = e/f.dat, g/h.dat\n',827        )828 829        with get_dist(tmpdir) as dist:830            expected = [831                ('cfg', ['a/b.conf', 'c/d.conf']),832                ('data', ['e/f.dat', 'g/h.dat']),833            ]834            assert sorted(dist.data_files) == sorted(expected)835 836    def test_data_files_globby(self, tmpdir):837        fake_env(838            tmpdir,839            '[options.data_files]\n'840            'cfg =\n'841            '      a/b.conf\n'842            '      c/d.conf\n'843            'data = *.dat\n'844            'icons = \n'845            '      *.ico\n'846            'audio = \n'847            '      *.wav\n'848            '      sounds.db\n',849        )850 851        # Create dummy files for glob()'s sake:852        tmpdir.join('a.dat').write('')853        tmpdir.join('b.dat').write('')854        tmpdir.join('c.dat').write('')855        tmpdir.join('a.ico').write('')856        tmpdir.join('b.ico').write('')857        tmpdir.join('c.ico').write('')858        tmpdir.join('beep.wav').write('')859        tmpdir.join('boop.wav').write('')860        tmpdir.join('sounds.db').write('')861 862        with get_dist(tmpdir) as dist:863            expected = [864                ('cfg', ['a/b.conf', 'c/d.conf']),865                ('data', ['a.dat', 'b.dat', 'c.dat']),866                ('icons', ['a.ico', 'b.ico', 'c.ico']),867                ('audio', ['beep.wav', 'boop.wav', 'sounds.db']),868            ]869            assert sorted(dist.data_files) == sorted(expected)870 871    def test_python_requires_simple(self, tmpdir):872        fake_env(873            tmpdir,874            DALS(875                """876            [options]877            python_requires=>=2.7878            """879            ),880        )881        with get_dist(tmpdir) as dist:882            dist.parse_config_files()883 884    def test_python_requires_compound(self, tmpdir):885        fake_env(886            tmpdir,887            DALS(888                """889            [options]890            python_requires=>=2.7,!=3.0.*891            """892            ),893        )894        with get_dist(tmpdir) as dist:895            dist.parse_config_files()896 897    def test_python_requires_invalid(self, tmpdir):898        fake_env(899            tmpdir,900            DALS(901                """902            [options]903            python_requires=invalid904            """905            ),906        )907        with pytest.raises(Exception):908            with get_dist(tmpdir) as dist:909                dist.parse_config_files()910 911    def test_cmdclass(self, tmpdir):912        module_path = Path(tmpdir, "src/custom_build.py")  # auto discovery for src913        module_path.parent.mkdir(parents=True, exist_ok=True)914        module_path.write_text(915            "from distutils.core import Command\nclass CustomCmd(Command): pass\n",916            encoding="utf-8",917        )918 919        setup_cfg = """920            [options]921            cmdclass =922                customcmd = custom_build.CustomCmd923        """924        fake_env(tmpdir, inspect.cleandoc(setup_cfg))925 926        with get_dist(tmpdir) as dist:927            cmdclass = dist.cmdclass['customcmd']928            assert cmdclass.__name__ == "CustomCmd"929            assert cmdclass.__module__ == "custom_build"930            assert module_path.samefile(inspect.getfile(cmdclass))931 932    def test_requirements_file(self, tmpdir):933        fake_env(934            tmpdir,935            DALS(936                """937            [options]938            install_requires = file:requirements.txt939            [options.extras_require]940            colors = file:requirements-extra.txt941            """942            ),943        )944 945        tmpdir.join('requirements.txt').write('\ndocutils>=0.3\n\n')946        tmpdir.join('requirements-extra.txt').write('colorama')947 948        with get_dist(tmpdir) as dist:949            assert dist.install_requires == ['docutils>=0.3']950            assert dist.extras_require == {'colors': ['colorama']}951 952 953saved_dist_init = _Distribution.__init__954 955 956class TestExternalSetters:957    # During creation of the setuptools Distribution() object, we call958    # the init of the parent distutils Distribution object via959    # _Distribution.__init__ ().960    #961    # It's possible distutils calls out to various keyword962    # implementations (i.e. distutils.setup_keywords entry points)963    # that may set a range of variables.964    #965    # This wraps distutil's Distribution.__init__ and simulates966    # pbr or something else setting these values.967    def _fake_distribution_init(self, dist, attrs):968        saved_dist_init(dist, attrs)969        # see self._DISTUTILS_UNSUPPORTED_METADATA970        dist.metadata.long_description_content_type = 'text/something'971        # Test overwrite setup() args972        dist.metadata.project_urls = {973            'Link One': 'https://example.com/one/',974            'Link Two': 'https://example.com/two/',975        }976 977    @patch.object(_Distribution, '__init__', autospec=True)978    def test_external_setters(self, mock_parent_init, tmpdir):979        mock_parent_init.side_effect = self._fake_distribution_init980 981        dist = Distribution(attrs={'project_urls': {'will_be': 'ignored'}})982 983        assert dist.metadata.long_description_content_type == 'text/something'984        assert dist.metadata.project_urls == {985            'Link One': 'https://example.com/one/',986            'Link Two': 'https://example.com/two/',987        }988 
codekingpro/portable-devtools · Team Ai