123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601 |
- # -*- coding: utf-8 -*-
- """sdist tests"""
- import contextlib
- import os
- import shutil
- import sys
- import tempfile
- import itertools
- import io
- from distutils import log
- from distutils.errors import DistutilsTemplateError
- from setuptools.command.egg_info import FileList, egg_info, translate_pattern
- from setuptools.dist import Distribution
- from setuptools.tests.textwrap import DALS
- import pytest
- 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, 'w').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 = [
- ('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(TestManifestTest, self).setup_method(method)
- f = open(os.path.join(self.temp_dir, 'setup.py'), 'w')
- 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."""
- with open(os.path.join(self.temp_dir, 'MANIFEST.in'), 'w') 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.
- """
- def setup_method(self, method):
- super(TestFileListTest, self).setup_method(method)
- self.threshold = log.set_threshold(log.FATAL)
- self._old_log = log.Log._log
- log.Log._log = self._log
- self.logs = []
- def teardown_method(self, method):
- log.set_threshold(self.threshold)
- log.Log._log = self._old_log
- super(TestFileListTest, self).teardown_method(method)
- def _log(self, level, msg, args):
- if level not in (log.DEBUG, log.INFO, log.WARN, log.ERROR, log.FATAL):
- raise ValueError('%s wrong log level' % str(level))
- self.logs.append((level, msg, args))
- def get_logs(self, *levels):
- def _format(msg, args):
- if len(args) == 0:
- return msg
- return msg % args
- return [_format(msg, args) for level, msg, args
- in self.logs if level in levels]
- def clear_logs(self):
- self.logs = []
- def assertNoWarnings(self):
- assert self.get_logs(log.WARN) == []
- self.clear_logs()
- def assertWarnings(self):
- assert len(self.get_logs(log.WARN)) > 0
- self.clear_logs()
- 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)
- open(file, 'w').close()
- 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'):
- try:
- file_list.process_template_line(action)
- except DistutilsTemplateError:
- pass
- except Exception:
- assert False, "Incorrect error thrown"
- else:
- assert False, "Should have thrown an error"
- def test_include(self):
- 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()
- file_list.process_template_line('include *.rb')
- file_list.sort()
- assert file_list.files == ['a.py']
- self.assertWarnings()
- def test_exclude(self):
- 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()
- file_list.process_template_line('exclude *.rb')
- file_list.sort()
- assert file_list.files == ['b.txt', ml('d/c.py')]
- self.assertWarnings()
- def test_global_include(self):
- 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()
- file_list.process_template_line('global-include *.rb')
- file_list.sort()
- assert file_list.files == ['a.py', ml('d/c.py')]
- self.assertWarnings()
- def test_global_exclude(self):
- 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()
- file_list.process_template_line('global-exclude *.rb')
- file_list.sort()
- assert file_list.files == ['b.txt']
- self.assertWarnings()
- def test_recursive_include(self):
- 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()
- 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()
- def test_recursive_exclude(self):
- 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()
- file_list.process_template_line('recursive-exclude e *.py')
- file_list.sort()
- assert file_list.files == ['a.py', ml('d/c.txt')]
- self.assertWarnings()
- def test_graft(self):
- 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()
- 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()
- def test_prune(self):
- 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()
- file_list.process_template_line('prune e')
- file_list.sort()
- assert file_list.files == ['a.py', ml('f/f.py')]
- self.assertWarnings()
|