D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
cloudlinux
/
venv
/
lib64
/
python3.11
/
site-packages
/
setuptools
/
tests
/
Filename :
test_manifest.py
back
Copy
"""sdist tests""" from __future__ import annotations import contextlib import io import itertools import logging import os import shutil import sys import tempfile import pytest from setuptools.command.egg_info import FileList, egg_info, translate_pattern from setuptools.dist import Distribution from setuptools.tests.textwrap import DALS from distutils import log from distutils.errors import DistutilsTemplateError IS_PYPY = '__pypy__' in sys.builtin_module_names def make_local_path(s): """Converts '/' in a string to os.sep""" return s.replace('/', os.sep) SETUP_ATTRS = { 'name': 'app', 'version': '0.0', 'packages': ['app'], } SETUP_PY = ( """\ from setuptools import setup setup(**%r) """ % SETUP_ATTRS ) @contextlib.contextmanager def quiet(): old_stdout, old_stderr = sys.stdout, sys.stderr sys.stdout, sys.stderr = io.StringIO(), io.StringIO() try: yield finally: sys.stdout, sys.stderr = old_stdout, old_stderr def touch(filename): open(filename, 'wb').close() # The set of files always in the manifest, including all files in the # .egg-info directory default_files = frozenset( map( make_local_path, [ 'README.rst', 'MANIFEST.in', 'setup.py', 'app.egg-info/PKG-INFO', 'app.egg-info/SOURCES.txt', 'app.egg-info/dependency_links.txt', 'app.egg-info/top_level.txt', 'app/__init__.py', ], ) ) translate_specs: list[tuple[str, list[str], list[str]]] = [ ('foo', ['foo'], ['bar', 'foobar']), ('foo/bar', ['foo/bar'], ['foo/bar/baz', './foo/bar', 'foo']), # Glob matching ('*.txt', ['foo.txt', 'bar.txt'], ['foo/foo.txt']), ('dir/*.txt', ['dir/foo.txt', 'dir/bar.txt', 'dir/.txt'], ['notdir/foo.txt']), ('*/*.py', ['bin/start.py'], []), ('docs/page-?.txt', ['docs/page-9.txt'], ['docs/page-10.txt']), # Globstars change what they mean depending upon where they are ( 'foo/**/bar', ['foo/bing/bar', 'foo/bing/bang/bar', 'foo/bar'], ['foo/abar'], ), ( 'foo/**', ['foo/bar/bing.py', 'foo/x'], ['/foo/x'], ), ( '**', ['x', 'abc/xyz', '@nything'], [], ), # Character classes ( 'pre[one]post', ['preopost', 'prenpost', 'preepost'], ['prepost', 'preonepost'], ), ( 'hello[!one]world', ['helloxworld', 'helloyworld'], ['hellooworld', 'helloworld', 'hellooneworld'], ), ( '[]one].txt', ['o.txt', '].txt', 'e.txt'], ['one].txt'], ), ( 'foo[!]one]bar', ['fooybar'], ['foo]bar', 'fooobar', 'fooebar'], ), ] """ A spec of inputs for 'translate_pattern' and matches and mismatches for that input. """ match_params = itertools.chain.from_iterable( zip(itertools.repeat(pattern), matches) for pattern, matches, mismatches in translate_specs ) @pytest.fixture(params=match_params) def pattern_match(request): return map(make_local_path, request.param) mismatch_params = itertools.chain.from_iterable( zip(itertools.repeat(pattern), mismatches) for pattern, matches, mismatches in translate_specs ) @pytest.fixture(params=mismatch_params) def pattern_mismatch(request): return map(make_local_path, request.param) def test_translated_pattern_match(pattern_match): pattern, target = pattern_match assert translate_pattern(pattern).match(target) def test_translated_pattern_mismatch(pattern_mismatch): pattern, target = pattern_mismatch assert not translate_pattern(pattern).match(target) class TempDirTestCase: def setup_method(self, method): self.temp_dir = tempfile.mkdtemp() self.old_cwd = os.getcwd() os.chdir(self.temp_dir) def teardown_method(self, method): os.chdir(self.old_cwd) shutil.rmtree(self.temp_dir) class TestManifestTest(TempDirTestCase): def setup_method(self, method): super().setup_method(method) f = open(os.path.join(self.temp_dir, 'setup.py'), 'w', encoding="utf-8") f.write(SETUP_PY) f.close() """ Create a file tree like: - LICENSE - README.rst - testing.rst - .hidden.rst - app/ - __init__.py - a.txt - b.txt - c.rst - static/ - app.js - app.js.map - app.css - app.css.map """ for fname in ['README.rst', '.hidden.rst', 'testing.rst', 'LICENSE']: touch(os.path.join(self.temp_dir, fname)) # Set up the rest of the test package test_pkg = os.path.join(self.temp_dir, 'app') os.mkdir(test_pkg) for fname in ['__init__.py', 'a.txt', 'b.txt', 'c.rst']: touch(os.path.join(test_pkg, fname)) # Some compiled front-end assets to include static = os.path.join(test_pkg, 'static') os.mkdir(static) for fname in ['app.js', 'app.js.map', 'app.css', 'app.css.map']: touch(os.path.join(static, fname)) def make_manifest(self, contents): """Write a MANIFEST.in.""" manifest = os.path.join(self.temp_dir, 'MANIFEST.in') with open(manifest, 'w', encoding="utf-8") as f: f.write(DALS(contents)) def get_files(self): """Run egg_info and get all the files to include, as a set""" dist = Distribution(SETUP_ATTRS) dist.script_name = 'setup.py' cmd = egg_info(dist) cmd.ensure_finalized() cmd.run() return set(cmd.filelist.files) def test_no_manifest(self): """Check a missing MANIFEST.in includes only the standard files.""" assert (default_files - set(['MANIFEST.in'])) == self.get_files() def test_empty_files(self): """Check an empty MANIFEST.in includes only the standard files.""" self.make_manifest("") assert default_files == self.get_files() def test_include(self): """Include extra rst files in the project root.""" self.make_manifest("include *.rst") files = default_files | set(['testing.rst', '.hidden.rst']) assert files == self.get_files() def test_exclude(self): """Include everything in app/ except the text files""" ml = make_local_path self.make_manifest( """ include app/* exclude app/*.txt """ ) files = default_files | set([ml('app/c.rst')]) assert files == self.get_files() def test_include_multiple(self): """Include with multiple patterns.""" ml = make_local_path self.make_manifest("include app/*.txt app/static/*") files = default_files | set([ ml('app/a.txt'), ml('app/b.txt'), ml('app/static/app.js'), ml('app/static/app.js.map'), ml('app/static/app.css'), ml('app/static/app.css.map'), ]) assert files == self.get_files() def test_graft(self): """Include the whole app/static/ directory.""" ml = make_local_path self.make_manifest("graft app/static") files = default_files | set([ ml('app/static/app.js'), ml('app/static/app.js.map'), ml('app/static/app.css'), ml('app/static/app.css.map'), ]) assert files == self.get_files() def test_graft_glob_syntax(self): """Include the whole app/static/ directory.""" ml = make_local_path self.make_manifest("graft */static") files = default_files | set([ ml('app/static/app.js'), ml('app/static/app.js.map'), ml('app/static/app.css'), ml('app/static/app.css.map'), ]) assert files == self.get_files() def test_graft_global_exclude(self): """Exclude all *.map files in the project.""" ml = make_local_path self.make_manifest( """ graft app/static global-exclude *.map """ ) files = default_files | set([ml('app/static/app.js'), ml('app/static/app.css')]) assert files == self.get_files() def test_global_include(self): """Include all *.rst, *.js, and *.css files in the whole tree.""" ml = make_local_path self.make_manifest( """ global-include *.rst *.js *.css """ ) files = default_files | set([ '.hidden.rst', 'testing.rst', ml('app/c.rst'), ml('app/static/app.js'), ml('app/static/app.css'), ]) assert files == self.get_files() def test_graft_prune(self): """Include all files in app/, except for the whole app/static/ dir.""" ml = make_local_path self.make_manifest( """ graft app prune app/static """ ) files = default_files | set([ml('app/a.txt'), ml('app/b.txt'), ml('app/c.rst')]) assert files == self.get_files() class TestFileListTest(TempDirTestCase): """ A copy of the relevant bits of distutils/tests/test_filelist.py, to ensure setuptools' version of FileList keeps parity with distutils. """ @pytest.fixture(autouse=os.getenv("SETUPTOOLS_USE_DISTUTILS") == "stdlib") def _compat_record_logs(self, monkeypatch, caplog): """Account for stdlib compatibility""" def _log(_logger, level, msg, args): exc = sys.exc_info() rec = logging.LogRecord("distutils", level, "", 0, msg, args, exc) caplog.records.append(rec) monkeypatch.setattr(log.Log, "_log", _log) def get_records(self, caplog, *levels): return [r for r in caplog.records if r.levelno in levels] def assertNoWarnings(self, caplog): assert self.get_records(caplog, log.WARN) == [] caplog.clear() def assertWarnings(self, caplog): if IS_PYPY and not caplog.records: pytest.xfail("caplog checks may not work well in PyPy") else: assert len(self.get_records(caplog, log.WARN)) > 0 caplog.clear() def make_files(self, files): for file in files: file = os.path.join(self.temp_dir, file) dirname, _basename = os.path.split(file) os.makedirs(dirname, exist_ok=True) touch(file) def test_process_template_line(self): # testing all MANIFEST.in template patterns file_list = FileList() ml = make_local_path # simulated file list self.make_files([ 'foo.tmp', 'ok', 'xo', 'four.txt', 'buildout.cfg', # filelist does not filter out VCS directories, # it's sdist that does ml('.hg/last-message.txt'), ml('global/one.txt'), ml('global/two.txt'), ml('global/files.x'), ml('global/here.tmp'), ml('f/o/f.oo'), ml('dir/graft-one'), ml('dir/dir2/graft2'), ml('dir3/ok'), ml('dir3/sub/ok.txt'), ]) MANIFEST_IN = DALS( """\ include ok include xo exclude xo include foo.tmp include buildout.cfg global-include *.x global-include *.txt global-exclude *.tmp recursive-include f *.oo recursive-exclude global *.x graft dir prune dir3 """ ) for line in MANIFEST_IN.split('\n'): if not line: continue file_list.process_template_line(line) wanted = [ 'buildout.cfg', 'four.txt', 'ok', ml('.hg/last-message.txt'), ml('dir/graft-one'), ml('dir/dir2/graft2'), ml('f/o/f.oo'), ml('global/one.txt'), ml('global/two.txt'), ] file_list.sort() assert file_list.files == wanted def test_exclude_pattern(self): # return False if no match file_list = FileList() assert not file_list.exclude_pattern('*.py') # return True if files match file_list = FileList() file_list.files = ['a.py', 'b.py'] assert file_list.exclude_pattern('*.py') # test excludes file_list = FileList() file_list.files = ['a.py', 'a.txt'] file_list.exclude_pattern('*.py') file_list.sort() assert file_list.files == ['a.txt'] def test_include_pattern(self): # return False if no match file_list = FileList() self.make_files([]) assert not file_list.include_pattern('*.py') # return True if files match file_list = FileList() self.make_files(['a.py', 'b.txt']) assert file_list.include_pattern('*.py') # test * matches all files file_list = FileList() self.make_files(['a.py', 'b.txt']) file_list.include_pattern('*') file_list.sort() assert file_list.files == ['a.py', 'b.txt'] def test_process_template_line_invalid(self): # invalid lines file_list = FileList() for action in ( 'include', 'exclude', 'global-include', 'global-exclude', 'recursive-include', 'recursive-exclude', 'graft', 'prune', 'blarg', ): with pytest.raises(DistutilsTemplateError): file_list.process_template_line(action) def test_include(self, caplog): caplog.set_level(logging.DEBUG) ml = make_local_path # include file_list = FileList() self.make_files(['a.py', 'b.txt', ml('d/c.py')]) file_list.process_template_line('include *.py') file_list.sort() assert file_list.files == ['a.py'] self.assertNoWarnings(caplog) file_list.process_template_line('include *.rb') file_list.sort() assert file_list.files == ['a.py'] self.assertWarnings(caplog) def test_exclude(self, caplog): caplog.set_level(logging.DEBUG) ml = make_local_path # exclude file_list = FileList() file_list.files = ['a.py', 'b.txt', ml('d/c.py')] file_list.process_template_line('exclude *.py') file_list.sort() assert file_list.files == ['b.txt', ml('d/c.py')] self.assertNoWarnings(caplog) file_list.process_template_line('exclude *.rb') file_list.sort() assert file_list.files == ['b.txt', ml('d/c.py')] self.assertWarnings(caplog) def test_global_include(self, caplog): caplog.set_level(logging.DEBUG) ml = make_local_path # global-include file_list = FileList() self.make_files(['a.py', 'b.txt', ml('d/c.py')]) file_list.process_template_line('global-include *.py') file_list.sort() assert file_list.files == ['a.py', ml('d/c.py')] self.assertNoWarnings(caplog) file_list.process_template_line('global-include *.rb') file_list.sort() assert file_list.files == ['a.py', ml('d/c.py')] self.assertWarnings(caplog) def test_global_exclude(self, caplog): caplog.set_level(logging.DEBUG) ml = make_local_path # global-exclude file_list = FileList() file_list.files = ['a.py', 'b.txt', ml('d/c.py')] file_list.process_template_line('global-exclude *.py') file_list.sort() assert file_list.files == ['b.txt'] self.assertNoWarnings(caplog) file_list.process_template_line('global-exclude *.rb') file_list.sort() assert file_list.files == ['b.txt'] self.assertWarnings(caplog) def test_recursive_include(self, caplog): caplog.set_level(logging.DEBUG) ml = make_local_path # recursive-include file_list = FileList() self.make_files(['a.py', ml('d/b.py'), ml('d/c.txt'), ml('d/d/e.py')]) file_list.process_template_line('recursive-include d *.py') file_list.sort() assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')] self.assertNoWarnings(caplog) file_list.process_template_line('recursive-include e *.py') file_list.sort() assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')] self.assertWarnings(caplog) def test_recursive_exclude(self, caplog): caplog.set_level(logging.DEBUG) ml = make_local_path # recursive-exclude file_list = FileList() file_list.files = ['a.py', ml('d/b.py'), ml('d/c.txt'), ml('d/d/e.py')] file_list.process_template_line('recursive-exclude d *.py') file_list.sort() assert file_list.files == ['a.py', ml('d/c.txt')] self.assertNoWarnings(caplog) file_list.process_template_line('recursive-exclude e *.py') file_list.sort() assert file_list.files == ['a.py', ml('d/c.txt')] self.assertWarnings(caplog) def test_graft(self, caplog): caplog.set_level(logging.DEBUG) ml = make_local_path # graft file_list = FileList() self.make_files(['a.py', ml('d/b.py'), ml('d/d/e.py'), ml('f/f.py')]) file_list.process_template_line('graft d') file_list.sort() assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')] self.assertNoWarnings(caplog) file_list.process_template_line('graft e') file_list.sort() assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')] self.assertWarnings(caplog) def test_prune(self, caplog): caplog.set_level(logging.DEBUG) ml = make_local_path # prune file_list = FileList() file_list.files = ['a.py', ml('d/b.py'), ml('d/d/e.py'), ml('f/f.py')] file_list.process_template_line('prune d') file_list.sort() assert file_list.files == ['a.py', ml('f/f.py')] self.assertNoWarnings(caplog) file_list.process_template_line('prune e') file_list.sort() assert file_list.files == ['a.py', ml('f/f.py')] self.assertWarnings(caplog)