Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_manifest.py623 linesDownload Raw Back to tests
1"""sdist tests"""2 3from __future__ import annotations4 5import contextlib6import io7import itertools8import logging9import os10import shutil11import sys12import tempfile13 14import pytest15 16from setuptools.command.egg_info import FileList, egg_info, translate_pattern17from setuptools.dist import Distribution18from setuptools.tests.textwrap import DALS19 20from distutils import log21from distutils.errors import DistutilsTemplateError22 23IS_PYPY = '__pypy__' in sys.builtin_module_names24 25 26def make_local_path(s):27    """Converts '/' in a string to os.sep"""28    return s.replace('/', os.sep)29 30 31SETUP_ATTRS = {32    'name': 'app',33    'version': '0.0',34    'packages': ['app'],35}36 37SETUP_PY = f"""\38from setuptools import setup39 40setup(**{SETUP_ATTRS!r})41"""42 43 44@contextlib.contextmanager45def quiet():46    old_stdout, old_stderr = sys.stdout, sys.stderr47    sys.stdout, sys.stderr = io.StringIO(), io.StringIO()48    try:49        yield50    finally:51        sys.stdout, sys.stderr = old_stdout, old_stderr52 53 54def touch(filename):55    open(filename, 'wb').close()56 57 58# The set of files always in the manifest, including all files in the59# .egg-info directory60default_files = frozenset(61    map(62        make_local_path,63        [64            'README.rst',65            'MANIFEST.in',66            'setup.py',67            'app.egg-info/PKG-INFO',68            'app.egg-info/SOURCES.txt',69            'app.egg-info/dependency_links.txt',70            'app.egg-info/top_level.txt',71            'app/__init__.py',72        ],73    )74)75 76 77translate_specs: list[tuple[str, list[str], list[str]]] = [78    ('foo', ['foo'], ['bar', 'foobar']),79    ('foo/bar', ['foo/bar'], ['foo/bar/baz', './foo/bar', 'foo']),80    # Glob matching81    ('*.txt', ['foo.txt', 'bar.txt'], ['foo/foo.txt']),82    ('dir/*.txt', ['dir/foo.txt', 'dir/bar.txt', 'dir/.txt'], ['notdir/foo.txt']),83    ('*/*.py', ['bin/start.py'], []),84    ('docs/page-?.txt', ['docs/page-9.txt'], ['docs/page-10.txt']),85    # Globstars change what they mean depending upon where they are86    (87        'foo/**/bar',88        ['foo/bing/bar', 'foo/bing/bang/bar', 'foo/bar'],89        ['foo/abar'],90    ),91    (92        'foo/**',93        ['foo/bar/bing.py', 'foo/x'],94        ['/foo/x'],95    ),96    (97        '**',98        ['x', 'abc/xyz', '@nything'],99        [],100    ),101    # Character classes102    (103        'pre[one]post',104        ['preopost', 'prenpost', 'preepost'],105        ['prepost', 'preonepost'],106    ),107    (108        'hello[!one]world',109        ['helloxworld', 'helloyworld'],110        ['hellooworld', 'helloworld', 'hellooneworld'],111    ),112    (113        '[]one].txt',114        ['o.txt', '].txt', 'e.txt'],115        ['one].txt'],116    ),117    (118        'foo[!]one]bar',119        ['fooybar'],120        ['foo]bar', 'fooobar', 'fooebar'],121    ),122]123"""124A spec of inputs for 'translate_pattern' and matches and mismatches125for that input.126"""127 128match_params = itertools.chain.from_iterable(129    zip(itertools.repeat(pattern), matches)130    for pattern, matches, mismatches in translate_specs131)132 133 134@pytest.fixture(params=match_params)135def pattern_match(request):136    return map(make_local_path, request.param)137 138 139mismatch_params = itertools.chain.from_iterable(140    zip(itertools.repeat(pattern), mismatches)141    for pattern, matches, mismatches in translate_specs142)143 144 145@pytest.fixture(params=mismatch_params)146def pattern_mismatch(request):147    return map(make_local_path, request.param)148 149 150def test_translated_pattern_match(pattern_match):151    pattern, target = pattern_match152    assert translate_pattern(pattern).match(target)153 154 155def test_translated_pattern_mismatch(pattern_mismatch):156    pattern, target = pattern_mismatch157    assert not translate_pattern(pattern).match(target)158 159 160class TempDirTestCase:161    def setup_method(self, method):162        self.temp_dir = tempfile.mkdtemp()163        self.old_cwd = os.getcwd()164        os.chdir(self.temp_dir)165 166    def teardown_method(self, method):167        os.chdir(self.old_cwd)168        shutil.rmtree(self.temp_dir)169 170 171class TestManifestTest(TempDirTestCase):172    def setup_method(self, method):173        super().setup_method(method)174 175        f = open(os.path.join(self.temp_dir, 'setup.py'), 'w', encoding="utf-8")176        f.write(SETUP_PY)177        f.close()178        """179        Create a file tree like:180        - LICENSE181        - README.rst182        - testing.rst183        - .hidden.rst184        - app/185            - __init__.py186            - a.txt187            - b.txt188            - c.rst189            - static/190                - app.js191                - app.js.map192                - app.css193                - app.css.map194        """195 196        for fname in ['README.rst', '.hidden.rst', 'testing.rst', 'LICENSE']:197            touch(os.path.join(self.temp_dir, fname))198 199        # Set up the rest of the test package200        test_pkg = os.path.join(self.temp_dir, 'app')201        os.mkdir(test_pkg)202        for fname in ['__init__.py', 'a.txt', 'b.txt', 'c.rst']:203            touch(os.path.join(test_pkg, fname))204 205        # Some compiled front-end assets to include206        static = os.path.join(test_pkg, 'static')207        os.mkdir(static)208        for fname in ['app.js', 'app.js.map', 'app.css', 'app.css.map']:209            touch(os.path.join(static, fname))210 211    def make_manifest(self, contents):212        """Write a MANIFEST.in."""213        manifest = os.path.join(self.temp_dir, 'MANIFEST.in')214        with open(manifest, 'w', encoding="utf-8") as f:215            f.write(DALS(contents))216 217    def get_files(self):218        """Run egg_info and get all the files to include, as a set"""219        dist = Distribution(SETUP_ATTRS)220        dist.script_name = 'setup.py'221        cmd = egg_info(dist)222        cmd.ensure_finalized()223 224        cmd.run()225 226        return set(cmd.filelist.files)227 228    def test_no_manifest(self):229        """Check a missing MANIFEST.in includes only the standard files."""230        assert (default_files - set(['MANIFEST.in'])) == self.get_files()231 232    def test_empty_files(self):233        """Check an empty MANIFEST.in includes only the standard files."""234        self.make_manifest("")235        assert default_files == self.get_files()236 237    def test_include(self):238        """Include extra rst files in the project root."""239        self.make_manifest("include *.rst")240        files = default_files | set(['testing.rst', '.hidden.rst'])241        assert files == self.get_files()242 243    def test_exclude(self):244        """Include everything in app/ except the text files"""245        ml = make_local_path246        self.make_manifest(247            """248            include app/*249            exclude app/*.txt250            """251        )252        files = default_files | set([ml('app/c.rst')])253        assert files == self.get_files()254 255    def test_include_multiple(self):256        """Include with multiple patterns."""257        ml = make_local_path258        self.make_manifest("include app/*.txt app/static/*")259        files = default_files | set([260            ml('app/a.txt'),261            ml('app/b.txt'),262            ml('app/static/app.js'),263            ml('app/static/app.js.map'),264            ml('app/static/app.css'),265            ml('app/static/app.css.map'),266        ])267        assert files == self.get_files()268 269    def test_graft(self):270        """Include the whole app/static/ directory."""271        ml = make_local_path272        self.make_manifest("graft app/static")273        files = default_files | set([274            ml('app/static/app.js'),275            ml('app/static/app.js.map'),276            ml('app/static/app.css'),277            ml('app/static/app.css.map'),278        ])279        assert files == self.get_files()280 281    def test_graft_glob_syntax(self):282        """Include the whole app/static/ directory."""283        ml = make_local_path284        self.make_manifest("graft */static")285        files = default_files | set([286            ml('app/static/app.js'),287            ml('app/static/app.js.map'),288            ml('app/static/app.css'),289            ml('app/static/app.css.map'),290        ])291        assert files == self.get_files()292 293    def test_graft_global_exclude(self):294        """Exclude all *.map files in the project."""295        ml = make_local_path296        self.make_manifest(297            """298            graft app/static299            global-exclude *.map300            """301        )302        files = default_files | set([ml('app/static/app.js'), ml('app/static/app.css')])303        assert files == self.get_files()304 305    def test_global_include(self):306        """Include all *.rst, *.js, and *.css files in the whole tree."""307        ml = make_local_path308        self.make_manifest(309            """310            global-include *.rst *.js *.css311            """312        )313        files = default_files | set([314            '.hidden.rst',315            'testing.rst',316            ml('app/c.rst'),317            ml('app/static/app.js'),318            ml('app/static/app.css'),319        ])320        assert files == self.get_files()321 322    def test_graft_prune(self):323        """Include all files in app/, except for the whole app/static/ dir."""324        ml = make_local_path325        self.make_manifest(326            """327            graft app328            prune app/static329            """330        )331        files = default_files | set([ml('app/a.txt'), ml('app/b.txt'), ml('app/c.rst')])332        assert files == self.get_files()333 334 335class TestFileListTest(TempDirTestCase):336    """337    A copy of the relevant bits of distutils/tests/test_filelist.py,338    to ensure setuptools' version of FileList keeps parity with distutils.339    """340 341    @pytest.fixture(autouse=os.getenv("SETUPTOOLS_USE_DISTUTILS") == "stdlib")342    def _compat_record_logs(self, monkeypatch, caplog):343        """Account for stdlib compatibility"""344 345        def _log(_logger, level, msg, args):346            exc = sys.exc_info()347            rec = logging.LogRecord("distutils", level, "", 0, msg, args, exc)348            caplog.records.append(rec)349 350        monkeypatch.setattr(log.Log, "_log", _log)351 352    def get_records(self, caplog, *levels):353        return [r for r in caplog.records if r.levelno in levels]354 355    def assertNoWarnings(self, caplog):356        assert self.get_records(caplog, log.WARN) == []357        caplog.clear()358 359    def assertWarnings(self, caplog):360        if IS_PYPY and not caplog.records:361            pytest.xfail("caplog checks may not work well in PyPy")362        else:363            assert len(self.get_records(caplog, log.WARN)) > 0364            caplog.clear()365 366    def make_files(self, files):367        for file in files:368            file = os.path.join(self.temp_dir, file)369            dirname, _basename = os.path.split(file)370            os.makedirs(dirname, exist_ok=True)371            touch(file)372 373    def test_process_template_line(self):374        # testing  all MANIFEST.in template patterns375        file_list = FileList()376        ml = make_local_path377 378        # simulated file list379        self.make_files([380            'foo.tmp',381            'ok',382            'xo',383            'four.txt',384            'buildout.cfg',385            # filelist does not filter out VCS directories,386            # it's sdist that does387            ml('.hg/last-message.txt'),388            ml('global/one.txt'),389            ml('global/two.txt'),390            ml('global/files.x'),391            ml('global/here.tmp'),392            ml('f/o/f.oo'),393            ml('dir/graft-one'),394            ml('dir/dir2/graft2'),395            ml('dir3/ok'),396            ml('dir3/sub/ok.txt'),397        ])398 399        MANIFEST_IN = DALS(400            """\401        include ok402        include xo403        exclude xo404        include foo.tmp405        include buildout.cfg406        global-include *.x407        global-include *.txt408        global-exclude *.tmp409        recursive-include f *.oo410        recursive-exclude global *.x411        graft dir412        prune dir3413        """414        )415 416        for line in MANIFEST_IN.split('\n'):417            if not line:418                continue419            file_list.process_template_line(line)420 421        wanted = [422            'buildout.cfg',423            'four.txt',424            'ok',425            ml('.hg/last-message.txt'),426            ml('dir/graft-one'),427            ml('dir/dir2/graft2'),428            ml('f/o/f.oo'),429            ml('global/one.txt'),430            ml('global/two.txt'),431        ]432 433        file_list.sort()434        assert file_list.files == wanted435 436    def test_exclude_pattern(self):437        # return False if no match438        file_list = FileList()439        assert not file_list.exclude_pattern('*.py')440 441        # return True if files match442        file_list = FileList()443        file_list.files = ['a.py', 'b.py']444        assert file_list.exclude_pattern('*.py')445 446        # test excludes447        file_list = FileList()448        file_list.files = ['a.py', 'a.txt']449        file_list.exclude_pattern('*.py')450        file_list.sort()451        assert file_list.files == ['a.txt']452 453    def test_include_pattern(self):454        # return False if no match455        file_list = FileList()456        self.make_files([])457        assert not file_list.include_pattern('*.py')458 459        # return True if files match460        file_list = FileList()461        self.make_files(['a.py', 'b.txt'])462        assert file_list.include_pattern('*.py')463 464        # test * matches all files465        file_list = FileList()466        self.make_files(['a.py', 'b.txt'])467        file_list.include_pattern('*')468        file_list.sort()469        assert file_list.files == ['a.py', 'b.txt']470 471    def test_process_template_line_invalid(self):472        # invalid lines473        file_list = FileList()474        for action in (475            'include',476            'exclude',477            'global-include',478            'global-exclude',479            'recursive-include',480            'recursive-exclude',481            'graft',482            'prune',483            'blarg',484        ):485            with pytest.raises(DistutilsTemplateError):486                file_list.process_template_line(action)487 488    def test_include(self, caplog):489        caplog.set_level(logging.DEBUG)490        ml = make_local_path491        # include492        file_list = FileList()493        self.make_files(['a.py', 'b.txt', ml('d/c.py')])494 495        file_list.process_template_line('include *.py')496        file_list.sort()497        assert file_list.files == ['a.py']498        self.assertNoWarnings(caplog)499 500        file_list.process_template_line('include *.rb')501        file_list.sort()502        assert file_list.files == ['a.py']503        self.assertWarnings(caplog)504 505    def test_exclude(self, caplog):506        caplog.set_level(logging.DEBUG)507        ml = make_local_path508        # exclude509        file_list = FileList()510        file_list.files = ['a.py', 'b.txt', ml('d/c.py')]511 512        file_list.process_template_line('exclude *.py')513        file_list.sort()514        assert file_list.files == ['b.txt', ml('d/c.py')]515        self.assertNoWarnings(caplog)516 517        file_list.process_template_line('exclude *.rb')518        file_list.sort()519        assert file_list.files == ['b.txt', ml('d/c.py')]520        self.assertWarnings(caplog)521 522    def test_global_include(self, caplog):523        caplog.set_level(logging.DEBUG)524        ml = make_local_path525        # global-include526        file_list = FileList()527        self.make_files(['a.py', 'b.txt', ml('d/c.py')])528 529        file_list.process_template_line('global-include *.py')530        file_list.sort()531        assert file_list.files == ['a.py', ml('d/c.py')]532        self.assertNoWarnings(caplog)533 534        file_list.process_template_line('global-include *.rb')535        file_list.sort()536        assert file_list.files == ['a.py', ml('d/c.py')]537        self.assertWarnings(caplog)538 539    def test_global_exclude(self, caplog):540        caplog.set_level(logging.DEBUG)541        ml = make_local_path542        # global-exclude543        file_list = FileList()544        file_list.files = ['a.py', 'b.txt', ml('d/c.py')]545 546        file_list.process_template_line('global-exclude *.py')547        file_list.sort()548        assert file_list.files == ['b.txt']549        self.assertNoWarnings(caplog)550 551        file_list.process_template_line('global-exclude *.rb')552        file_list.sort()553        assert file_list.files == ['b.txt']554        self.assertWarnings(caplog)555 556    def test_recursive_include(self, caplog):557        caplog.set_level(logging.DEBUG)558        ml = make_local_path559        # recursive-include560        file_list = FileList()561        self.make_files(['a.py', ml('d/b.py'), ml('d/c.txt'), ml('d/d/e.py')])562 563        file_list.process_template_line('recursive-include d *.py')564        file_list.sort()565        assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]566        self.assertNoWarnings(caplog)567 568        file_list.process_template_line('recursive-include e *.py')569        file_list.sort()570        assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]571        self.assertWarnings(caplog)572 573    def test_recursive_exclude(self, caplog):574        caplog.set_level(logging.DEBUG)575        ml = make_local_path576        # recursive-exclude577        file_list = FileList()578        file_list.files = ['a.py', ml('d/b.py'), ml('d/c.txt'), ml('d/d/e.py')]579 580        file_list.process_template_line('recursive-exclude d *.py')581        file_list.sort()582        assert file_list.files == ['a.py', ml('d/c.txt')]583        self.assertNoWarnings(caplog)584 585        file_list.process_template_line('recursive-exclude e *.py')586        file_list.sort()587        assert file_list.files == ['a.py', ml('d/c.txt')]588        self.assertWarnings(caplog)589 590    def test_graft(self, caplog):591        caplog.set_level(logging.DEBUG)592        ml = make_local_path593        # graft594        file_list = FileList()595        self.make_files(['a.py', ml('d/b.py'), ml('d/d/e.py'), ml('f/f.py')])596 597        file_list.process_template_line('graft d')598        file_list.sort()599        assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]600        self.assertNoWarnings(caplog)601 602        file_list.process_template_line('graft e')603        file_list.sort()604        assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]605        self.assertWarnings(caplog)606 607    def test_prune(self, caplog):608        caplog.set_level(logging.DEBUG)609        ml = make_local_path610        # prune611        file_list = FileList()612        file_list.files = ['a.py', ml('d/b.py'), ml('d/d/e.py'), ml('f/f.py')]613 614        file_list.process_template_line('prune d')615        file_list.sort()616        assert file_list.files == ['a.py', ml('f/f.py')]617        self.assertNoWarnings(caplog)618 619        file_list.process_template_line('prune e')620        file_list.sort()621        assert file_list.files == ['a.py', ml('f/f.py')]622        self.assertWarnings(caplog)623 
codekingpro/portable-devtools · Team Ai