CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
test_dist.py553 linesDownload Raw Back to tests
1"""Tests for distutils.dist."""2 3import email4import email.generator5import email.policy6import functools7import io8import os9import sys10import textwrap11import unittest.mock as mock12import warnings13from distutils.cmd import Command14from distutils.dist import Distribution, fix_help_options15from distutils.tests import support16from typing import ClassVar17 18import jaraco.path19import pytest20 21pydistutils_cfg = '.' * (os.name == 'posix') + 'pydistutils.cfg'22 23 24class test_dist(Command):25    """Sample distutils extension command."""26 27    user_options: ClassVar[list[tuple[str, str, str]]] = [28        ("sample-option=", "S", "help text"),29    ]30 31    def initialize_options(self):32        self.sample_option = None33 34 35class TestDistribution(Distribution):36    """Distribution subclasses that avoids the default search for37    configuration files.38 39    The ._config_files attribute must be set before40    .parse_config_files() is called.41    """42 43    def find_config_files(self):44        return self._config_files45 46 47@pytest.fixture48def clear_argv():49    del sys.argv[1:]50 51 52@support.combine_markers53@pytest.mark.usefixtures('save_env')54@pytest.mark.usefixtures('save_argv')55class TestDistributionBehavior(support.TempdirManager):56    def create_distribution(self, configfiles=()):57        d = TestDistribution()58        d._config_files = configfiles59        d.parse_config_files()60        d.parse_command_line()61        return d62 63    def test_command_packages_unspecified(self, clear_argv):64        sys.argv.append("build")65        d = self.create_distribution()66        assert d.get_command_packages() == ["distutils.command"]67 68    def test_command_packages_cmdline(self, clear_argv):69        from distutils.tests.test_dist import test_dist70 71        sys.argv.extend([72            "--command-packages",73            "foo.bar,distutils.tests",74            "test_dist",75            "-Ssometext",76        ])77        d = self.create_distribution()78        # let's actually try to load our test command:79        assert d.get_command_packages() == [80            "distutils.command",81            "foo.bar",82            "distutils.tests",83        ]84        cmd = d.get_command_obj("test_dist")85        assert isinstance(cmd, test_dist)86        assert cmd.sample_option == "sometext"87 88    @pytest.mark.skipif(89        'distutils' not in Distribution.parse_config_files.__module__,90        reason='Cannot test when virtualenv has monkey-patched Distribution',91    )92    def test_venv_install_options(self, tmp_path, clear_argv):93        sys.argv.append("install")94        file = str(tmp_path / 'file')95 96        fakepath = '/somedir'97 98        jaraco.path.build({99            file: f"""100                    [install]101                    install-base = {fakepath}102                    install-platbase = {fakepath}103                    install-lib = {fakepath}104                    install-platlib = {fakepath}105                    install-purelib = {fakepath}106                    install-headers = {fakepath}107                    install-scripts = {fakepath}108                    install-data = {fakepath}109                    prefix = {fakepath}110                    exec-prefix = {fakepath}111                    home = {fakepath}112                    user = {fakepath}113                    root = {fakepath}114                    """,115        })116 117        # Base case: Not in a Virtual Environment118        with mock.patch.multiple(sys, prefix='/a', base_prefix='/a'):119            d = self.create_distribution([file])120 121        option_tuple = (file, fakepath)122 123        result_dict = {124            'install_base': option_tuple,125            'install_platbase': option_tuple,126            'install_lib': option_tuple,127            'install_platlib': option_tuple,128            'install_purelib': option_tuple,129            'install_headers': option_tuple,130            'install_scripts': option_tuple,131            'install_data': option_tuple,132            'prefix': option_tuple,133            'exec_prefix': option_tuple,134            'home': option_tuple,135            'user': option_tuple,136            'root': option_tuple,137        }138 139        assert sorted(d.command_options.get('install').keys()) == sorted(140            result_dict.keys()141        )142 143        for key, value in d.command_options.get('install').items():144            assert value == result_dict[key]145 146        # Test case: In a Virtual Environment147        with mock.patch.multiple(sys, prefix='/a', base_prefix='/b'):148            d = self.create_distribution([file])149 150        for key in result_dict.keys():151            assert key not in d.command_options.get('install', {})152 153    def test_command_packages_configfile(self, tmp_path, clear_argv):154        sys.argv.append("build")155        file = str(tmp_path / "file")156        jaraco.path.build({157            file: """158                    [global]159                    command_packages = foo.bar, splat160                    """,161        })162 163        d = self.create_distribution([file])164        assert d.get_command_packages() == ["distutils.command", "foo.bar", "splat"]165 166        # ensure command line overrides config:167        sys.argv[1:] = ["--command-packages", "spork", "build"]168        d = self.create_distribution([file])169        assert d.get_command_packages() == ["distutils.command", "spork"]170 171        # Setting --command-packages to '' should cause the default to172        # be used even if a config file specified something else:173        sys.argv[1:] = ["--command-packages", "", "build"]174        d = self.create_distribution([file])175        assert d.get_command_packages() == ["distutils.command"]176 177    def test_empty_options(self, request):178        # an empty options dictionary should not stay in the179        # list of attributes180 181        # catching warnings182        warns = []183 184        def _warn(msg):185            warns.append(msg)186 187        request.addfinalizer(188            functools.partial(setattr, warnings, 'warn', warnings.warn)189        )190        warnings.warn = _warn191        dist = Distribution(192            attrs={193                'author': 'xxx',194                'name': 'xxx',195                'version': 'xxx',196                'url': 'xxxx',197                'options': {},198            }199        )200 201        assert len(warns) == 0202        assert 'options' not in dir(dist)203 204    def test_finalize_options(self):205        attrs = {'keywords': 'one,two', 'platforms': 'one,two'}206 207        dist = Distribution(attrs=attrs)208        dist.finalize_options()209 210        # finalize_option splits platforms and keywords211        assert dist.metadata.platforms == ['one', 'two']212        assert dist.metadata.keywords == ['one', 'two']213 214        attrs = {'keywords': 'foo bar', 'platforms': 'foo bar'}215        dist = Distribution(attrs=attrs)216        dist.finalize_options()217        assert dist.metadata.platforms == ['foo bar']218        assert dist.metadata.keywords == ['foo bar']219 220    def test_get_command_packages(self):221        dist = Distribution()222        assert dist.command_packages is None223        cmds = dist.get_command_packages()224        assert cmds == ['distutils.command']225        assert dist.command_packages == ['distutils.command']226 227        dist.command_packages = 'one,two'228        cmds = dist.get_command_packages()229        assert cmds == ['distutils.command', 'one', 'two']230 231    def test_announce(self):232        # make sure the level is known233        dist = Distribution()234        with pytest.raises(TypeError):235            dist.announce('ok', level='ok2')236 237    def test_find_config_files_disable(self, temp_home):238        # Ticket #1180: Allow user to disable their home config file.239        jaraco.path.build({pydistutils_cfg: '[distutils]\n'}, temp_home)240 241        d = Distribution()242        all_files = d.find_config_files()243 244        d = Distribution(attrs={'script_args': ['--no-user-cfg']})245        files = d.find_config_files()246 247        # make sure --no-user-cfg disables the user cfg file248        assert len(all_files) - 1 == len(files)249 250    def test_script_args_list_coercion(self):251        d = Distribution(attrs={'script_args': ('build', '--no-user-cfg')})252 253        # make sure script_args is a list even if it started as a different iterable254        assert d.script_args == ['build', '--no-user-cfg']255 256    @pytest.mark.skipif(257        'platform.system() == "Windows"',258        reason='Windows does not honor chmod 000',259    )260    def test_find_config_files_permission_error(self, fake_home):261        """262        Finding config files should not fail when directory is inaccessible.263        """264        fake_home.joinpath(pydistutils_cfg).write_text('', encoding='utf-8')265        fake_home.chmod(0o000)266        Distribution().find_config_files()267 268 269@pytest.mark.usefixtures('save_env')270@pytest.mark.usefixtures('save_argv')271class TestMetadata(support.TempdirManager):272    def format_metadata(self, dist):273        sio = io.StringIO()274        dist.metadata.write_pkg_file(sio)275        return sio.getvalue()276 277    def test_simple_metadata(self):278        attrs = {"name": "package", "version": "1.0"}279        dist = Distribution(attrs)280        meta = self.format_metadata(dist)281        assert "Metadata-Version: 1.0" in meta282        assert "provides:" not in meta.lower()283        assert "requires:" not in meta.lower()284        assert "obsoletes:" not in meta.lower()285 286    def test_provides(self):287        attrs = {288            "name": "package",289            "version": "1.0",290            "provides": ["package", "package.sub"],291        }292        dist = Distribution(attrs)293        assert dist.metadata.get_provides() == ["package", "package.sub"]294        assert dist.get_provides() == ["package", "package.sub"]295        meta = self.format_metadata(dist)296        assert "Metadata-Version: 1.1" in meta297        assert "requires:" not in meta.lower()298        assert "obsoletes:" not in meta.lower()299 300    def test_provides_illegal(self):301        with pytest.raises(ValueError):302            Distribution(303                {"name": "package", "version": "1.0", "provides": ["my.pkg (splat)"]},304            )305 306    def test_requires(self):307        attrs = {308            "name": "package",309            "version": "1.0",310            "requires": ["other", "another (==1.0)"],311        }312        dist = Distribution(attrs)313        assert dist.metadata.get_requires() == ["other", "another (==1.0)"]314        assert dist.get_requires() == ["other", "another (==1.0)"]315        meta = self.format_metadata(dist)316        assert "Metadata-Version: 1.1" in meta317        assert "provides:" not in meta.lower()318        assert "Requires: other" in meta319        assert "Requires: another (==1.0)" in meta320        assert "obsoletes:" not in meta.lower()321 322    def test_requires_illegal(self):323        with pytest.raises(ValueError):324            Distribution(325                {"name": "package", "version": "1.0", "requires": ["my.pkg (splat)"]},326            )327 328    def test_requires_to_list(self):329        attrs = {"name": "package", "requires": iter(["other"])}330        dist = Distribution(attrs)331        assert isinstance(dist.metadata.requires, list)332 333    def test_obsoletes(self):334        attrs = {335            "name": "package",336            "version": "1.0",337            "obsoletes": ["other", "another (<1.0)"],338        }339        dist = Distribution(attrs)340        assert dist.metadata.get_obsoletes() == ["other", "another (<1.0)"]341        assert dist.get_obsoletes() == ["other", "another (<1.0)"]342        meta = self.format_metadata(dist)343        assert "Metadata-Version: 1.1" in meta344        assert "provides:" not in meta.lower()345        assert "requires:" not in meta.lower()346        assert "Obsoletes: other" in meta347        assert "Obsoletes: another (<1.0)" in meta348 349    def test_obsoletes_illegal(self):350        with pytest.raises(ValueError):351            Distribution(352                {"name": "package", "version": "1.0", "obsoletes": ["my.pkg (splat)"]},353            )354 355    def test_obsoletes_to_list(self):356        attrs = {"name": "package", "obsoletes": iter(["other"])}357        dist = Distribution(attrs)358        assert isinstance(dist.metadata.obsoletes, list)359 360    def test_classifier(self):361        attrs = {362            'name': 'Boa',363            'version': '3.0',364            'classifiers': ['Programming Language :: Python :: 3'],365        }366        dist = Distribution(attrs)367        assert dist.get_classifiers() == ['Programming Language :: Python :: 3']368        meta = self.format_metadata(dist)369        assert 'Metadata-Version: 1.1' in meta370 371    def test_classifier_invalid_type(self, caplog):372        attrs = {373            'name': 'Boa',374            'version': '3.0',375            'classifiers': ('Programming Language :: Python :: 3',),376        }377        d = Distribution(attrs)378        # should have warning about passing a non-list379        assert 'should be a list' in caplog.messages[0]380        # should be converted to a list381        assert isinstance(d.metadata.classifiers, list)382        assert d.metadata.classifiers == list(attrs['classifiers'])383 384    def test_keywords(self):385        attrs = {386            'name': 'Monty',387            'version': '1.0',388            'keywords': ['spam', 'eggs', 'life of brian'],389        }390        dist = Distribution(attrs)391        assert dist.get_keywords() == ['spam', 'eggs', 'life of brian']392 393    def test_keywords_invalid_type(self, caplog):394        attrs = {395            'name': 'Monty',396            'version': '1.0',397            'keywords': ('spam', 'eggs', 'life of brian'),398        }399        d = Distribution(attrs)400        # should have warning about passing a non-list401        assert 'should be a list' in caplog.messages[0]402        # should be converted to a list403        assert isinstance(d.metadata.keywords, list)404        assert d.metadata.keywords == list(attrs['keywords'])405 406    def test_platforms(self):407        attrs = {408            'name': 'Monty',409            'version': '1.0',410            'platforms': ['GNU/Linux', 'Some Evil Platform'],411        }412        dist = Distribution(attrs)413        assert dist.get_platforms() == ['GNU/Linux', 'Some Evil Platform']414 415    def test_platforms_invalid_types(self, caplog):416        attrs = {417            'name': 'Monty',418            'version': '1.0',419            'platforms': ('GNU/Linux', 'Some Evil Platform'),420        }421        d = Distribution(attrs)422        # should have warning about passing a non-list423        assert 'should be a list' in caplog.messages[0]424        # should be converted to a list425        assert isinstance(d.metadata.platforms, list)426        assert d.metadata.platforms == list(attrs['platforms'])427 428    def test_download_url(self):429        attrs = {430            'name': 'Boa',431            'version': '3.0',432            'download_url': 'http://example.org/boa',433        }434        dist = Distribution(attrs)435        meta = self.format_metadata(dist)436        assert 'Metadata-Version: 1.1' in meta437 438    def test_long_description(self):439        long_desc = textwrap.dedent(440            """\441        example::442              We start here443            and continue here444          and end here."""445        )446        attrs = {"name": "package", "version": "1.0", "long_description": long_desc}447 448        dist = Distribution(attrs)449        meta = self.format_metadata(dist)450        meta = meta.replace('\n' + 8 * ' ', '\n')451        assert long_desc in meta452 453    def test_custom_pydistutils(self, temp_home):454        """455        pydistutils.cfg is found456        """457        jaraco.path.build({pydistutils_cfg: ''}, temp_home)458        config_path = temp_home / pydistutils_cfg459 460        assert str(config_path) in Distribution().find_config_files()461 462    def test_extra_pydistutils(self, monkeypatch, tmp_path):463        jaraco.path.build({'overrides.cfg': ''}, tmp_path)464        filename = tmp_path / 'overrides.cfg'465        monkeypatch.setenv('DIST_EXTRA_CONFIG', str(filename))466        assert str(filename) in Distribution().find_config_files()467 468    def test_fix_help_options(self):469        help_tuples = [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]470        fancy_options = fix_help_options(help_tuples)471        assert fancy_options[0] == ('a', 'b', 'c')472        assert fancy_options[1] == (1, 2, 3)473 474    def test_show_help(self, request, capsys):475        # smoke test, just makes sure some help is displayed476        dist = Distribution()477        sys.argv = []478        dist.help = True479        dist.script_name = 'setup.py'480        dist.parse_command_line()481 482        output = [483            line for line in capsys.readouterr().out.split('\n') if line.strip() != ''484        ]485        assert output486 487    def test_read_metadata(self):488        attrs = {489            "name": "package",490            "version": "1.0",491            "long_description": "desc",492            "description": "xxx",493            "download_url": "http://example.com",494            "keywords": ['one', 'two'],495            "requires": ['foo'],496        }497 498        dist = Distribution(attrs)499        metadata = dist.metadata500 501        # write it then reloads it502        PKG_INFO = io.StringIO()503        metadata.write_pkg_file(PKG_INFO)504        PKG_INFO.seek(0)505        metadata.read_pkg_file(PKG_INFO)506 507        assert metadata.name == "package"508        assert metadata.version == "1.0"509        assert metadata.description == "xxx"510        assert metadata.download_url == 'http://example.com'511        assert metadata.keywords == ['one', 'two']512        assert metadata.platforms is None513        assert metadata.obsoletes is None514        assert metadata.requires == ['foo']515 516    def test_round_trip_through_email_generator(self):517        """518        In pypa/setuptools#4033, it was shown that once PKG-INFO is519        re-generated using ``email.generator.Generator``, some control520        characters might cause problems.521        """522        # Given a PKG-INFO file ...523        attrs = {524            "name": "package",525            "version": "1.0",526            "long_description": "hello\x0b\nworld\n",527        }528        dist = Distribution(attrs)529        metadata = dist.metadata530 531        with io.StringIO() as buffer:532            metadata.write_pkg_file(buffer)533            msg = buffer.getvalue()534 535        # ... when it is read and re-written using stdlib's email library,536        orig = email.message_from_string(msg)537        policy = email.policy.EmailPolicy(538            utf8=True,539            mangle_from_=False,540            max_line_length=0,541        )542        with io.StringIO() as buffer:543            email.generator.Generator(buffer, policy=policy).flatten(orig)544 545            buffer.seek(0)546            regen = email.message_from_file(buffer)547 548        # ... then it should be the same as the original549        # (except for the specific line break characters)550        orig_desc = set(orig["Description"].splitlines())551        regen_desc = set(regen["Description"].splitlines())552        assert regen_desc == orig_desc553 
Aluode/PerceptionLabPortable · CoolFace