diff options
Diffstat (limited to 'setuptools')
69 files changed, 1741 insertions, 4178 deletions
diff --git a/setuptools/__init__.py b/setuptools/__init__.py index c885555d..57236a5b 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -3,7 +3,6 @@ __import__('setuptools.bootstrap').bootstrap.ensure_deps() import os -import sys import distutils.core import distutils.filelist from distutils.core import Command as _Command diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py index 67a67e23..b3c9fa56 100755 --- a/setuptools/archive_util.py +++ b/setuptools/archive_util.py @@ -64,20 +64,23 @@ def unpack_directory(filename, extract_dir, progress_filter=default_filter): Raises ``UnrecognizedFormat`` if `filename` is not a directory """ if not os.path.isdir(filename): - raise UnrecognizedFormat("%s is not a directory" % (filename,)) + raise UnrecognizedFormat("%s is not a directory" % filename) - paths = {filename:('',extract_dir)} + paths = { + filename: ('', extract_dir), + } for base, dirs, files in os.walk(filename): - src,dst = paths[base] + src, dst = paths[base] for d in dirs: - paths[os.path.join(base,d)] = src+d+'/', os.path.join(dst,d) + paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d) for f in files: - target = os.path.join(dst,f) - target = progress_filter(src+f, target) + target = os.path.join(dst, f) + target = progress_filter(src + f, target) if not target: - continue # skip non-files + # skip non-files + continue ensure_directory(target) - f = os.path.join(base,f) + f = os.path.join(base, f) shutil.copyfile(f, target) shutil.copystat(f, target) @@ -112,12 +115,8 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): # file ensure_directory(target) data = z.read(info.filename) - f = open(target,'wb') - try: + with open(target, 'wb') as f: f.write(data) - finally: - f.close() - del data unix_attributes = info.external_attr >> 16 if unix_attributes: os.chmod(target, unix_attributes) @@ -137,18 +136,21 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): "%s is not a compressed or uncompressed tar file" % (filename,) ) with contextlib.closing(tarobj): - tarobj.chown = lambda *args: None # don't do any chowning! + # don't do any chowning! + tarobj.chown = lambda *args: None for member in tarobj: name = member.name # don't extract absolute paths or ones with .. in them if not name.startswith('/') and '..' not in name.split('/'): prelim_dst = os.path.join(extract_dir, *name.split('/')) - # resolve any links and to extract the link targets as normal files + # resolve any links and to extract the link targets as normal + # files while member is not None and (member.islnk() or member.issym()): linkpath = member.linkname if member.issym(): - linkpath = posixpath.join(posixpath.dirname(member.name), linkpath) + base = posixpath.dirname(member.name) + linkpath = posixpath.join(base, linkpath) linkpath = posixpath.normpath(linkpath) member = tarobj._getmember(linkpath) @@ -158,9 +160,11 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): if final_dst.endswith(os.sep): final_dst = final_dst[:-1] try: - tarobj._extract_member(member, final_dst) # XXX Ugh + # XXX Ugh + tarobj._extract_member(member, final_dst) except tarfile.ExtractError: - pass # chown/chmod/mkfifo/mknode/makedev failed + # chown/chmod/mkfifo/mknode/makedev failed + pass return True extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py index 53bf9cd3..e4b2c593 100644 --- a/setuptools/command/build_ext.py +++ b/setuptools/command/build_ext.py @@ -6,6 +6,7 @@ from distutils.errors import DistutilsError from distutils import log import os import sys +import itertools from setuptools.extension import Library @@ -33,18 +34,13 @@ if sys.platform == "darwin": use_stubs = True elif os.name != 'nt': try: - from dl import RTLD_NOW - - have_rtld = True - use_stubs = True + import dl + use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW') except ImportError: pass -def if_dl(s): - if have_rtld: - return s - return '' +if_dl = lambda s: s if have_rtld else '' class build_ext(_build_ext): @@ -123,10 +119,10 @@ class build_ext(_build_ext): # XXX what to do with conflicts? self.ext_map[fullname.split('.')[-1]] = ext - ltd = ext._links_to_dynamic = \ - self.shlibs and self.links_to_dynamic(ext) or False - ext._needs_stub = ltd and use_stubs and not isinstance(ext, - Library) + ltd = self.shlibs and self.links_to_dynamic(ext) or False + ns = ltd and use_stubs and not isinstance(ext, Library) + ext._links_to_dynamic = ltd + ext._needs_stub = ns filename = ext._file_name = self.get_ext_filename(fullname) libdir = os.path.dirname(os.path.join(self.build_lib, filename)) if ltd and libdir not in ext.library_dirs: @@ -186,9 +182,8 @@ class build_ext(_build_ext): self.compiler = self.shlib_compiler _build_ext.build_extension(self, ext) if ext._needs_stub: - self.write_stub( - self.get_finalized_command('build_py').build_lib, ext - ) + cmd = self.get_finalized_command('build_py').build_lib + self.write_stub(cmd, ext) finally: self.compiler = _compiler @@ -199,22 +194,27 @@ class build_ext(_build_ext): # XXX static-compiled version libnames = dict.fromkeys([lib._full_name for lib in self.shlibs]) pkg = '.'.join(ext._full_name.split('.')[:-1] + ['']) - for libname in ext.libraries: - if pkg + libname in libnames: - return True - return False + return any(pkg + libname in libnames for libname in ext.libraries) def get_outputs(self): - outputs = _build_ext.get_outputs(self) - optimize = self.get_finalized_command('build_py').optimize - for ext in self.extensions: - if ext._needs_stub: - base = os.path.join(self.build_lib, *ext._full_name.split('.')) - outputs.append(base + '.py') - outputs.append(base + '.pyc') - if optimize: - outputs.append(base + '.pyo') - return outputs + return _build_ext.get_outputs(self) + self.__get_stubs_outputs() + + def __get_stubs_outputs(self): + # assemble the base name for each extension that needs a stub + ns_ext_bases = ( + os.path.join(self.build_lib, *ext._full_name.split('.')) + for ext in self.extensions + if ext._needs_stub + ) + # pair each base with the extension + pairs = itertools.product(ns_ext_bases, self.__get_output_extensions()) + return list(base + fnext for base, fnext in pairs) + + def __get_output_extensions(self): + yield '.py' + yield '.pyc' + if self.get_finalized_command('build_py').optimize: + yield '.pyo' def write_stub(self, output_dir, ext, compile=False): log.info("writing stub loader for %s to %s", ext._full_name, diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 5444ba53..a24e3b59 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -34,6 +34,7 @@ import textwrap import warnings import site import struct +import contextlib import six from six.moves import configparser @@ -55,9 +56,14 @@ from pkg_resources import ( import pkg_resources +# Turn on PEP440Warnings +warnings.filterwarnings("default", category=pkg_resources.PEP440Warning) + + sys_executable = os.environ.get('__PYVENV_LAUNCHER__', os.path.normpath(sys.executable)) + __all__ = [ 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', 'main', 'get_exe_prefixes', @@ -1541,10 +1547,14 @@ class PthDistributions(Environment): def add(self, dist): """Add `dist` to the distribution map""" - if (dist.location not in self.paths and ( - dist.location not in self.sitedirs or - dist.location == os.getcwd() # account for '.' being in PYTHONPATH - )): + new_path = ( + dist.location not in self.paths and ( + dist.location not in self.sitedirs or + # account for '.' being in PYTHONPATH + dist.location == os.getcwd() + ) + ) + if new_path: self.paths.append(dist.location) self.dirty = True Environment.add(self, dist) @@ -2112,39 +2122,42 @@ def bootstrap(): def main(argv=None, **kw): from setuptools import setup from setuptools.dist import Distribution - import distutils.core - - USAGE = """\ -usage: %(script)s [options] requirement_or_url ... - or: %(script)s --help -""" - - def gen_usage(script_name): - return USAGE % dict( - script=os.path.basename(script_name), - ) - - def with_ei_usage(f): - old_gen_usage = distutils.core.gen_usage - try: - distutils.core.gen_usage = gen_usage - return f() - finally: - distutils.core.gen_usage = old_gen_usage class DistributionWithoutHelpCommands(Distribution): common_usage = "" def _show_help(self, *args, **kw): - with_ei_usage(lambda: Distribution._show_help(self, *args, **kw)) + with _patch_usage(): + Distribution._show_help(self, *args, **kw) if argv is None: argv = sys.argv[1:] - with_ei_usage( - lambda: setup( + with _patch_usage(): + setup( script_args=['-q', 'easy_install', '-v'] + argv, script_name=sys.argv[0] or 'easy_install', distclass=DistributionWithoutHelpCommands, **kw ) - ) + + +@contextlib.contextmanager +def _patch_usage(): + import distutils.core + USAGE = textwrap.dedent(""" + usage: %(script)s [options] requirement_or_url ... + or: %(script)s --help + """).lstrip() + + def gen_usage(script_name): + return USAGE % dict( + script=os.path.basename(script_name), + ) + + saved = distutils.core.gen_usage + distutils.core.gen_usage = gen_usage + try: + yield + finally: + distutils.core.gen_usage = saved + diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 14ff0763..3f1db996 100755 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -6,21 +6,27 @@ from distutils.filelist import FileList as _FileList from distutils.util import convert_path from distutils import log import distutils.errors +import distutils.filelist import os import re import sys import six +try: + from setuptools_svn import svn_utils +except ImportError: + pass + from setuptools import Command from setuptools.command.sdist import sdist -from setuptools import svn_utils from setuptools.command.sdist import walk_revctrl from pkg_resources import ( parse_requirements, safe_name, parse_version, safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename) import setuptools.unicode_utils as unicode_utils +from pkg_resources import packaging class egg_info(Command): description = "create a distribution's .egg-info directory" @@ -69,10 +75,15 @@ class egg_info(Command): self.vtags = self.tags() self.egg_version = self.tagged_version() + parsed_version = parse_version(self.egg_version) + try: + is_version = isinstance(parsed_version, packaging.version.Version) + spec = ( + "%s==%s" if is_version else "%s===%s" + ) list( - parse_requirements('%s==%s' % (self.egg_name, - self.egg_version)) + parse_requirements(spec % (self.egg_name, self.egg_version)) ) except ValueError: raise distutils.errors.DistutilsOptionError( @@ -184,6 +195,8 @@ class egg_info(Command): @staticmethod def get_svn_revision(): + if 'svn_utils' not in globals(): + return "0" return str(svn_utils.SvnInfo.load(os.curdir).get_revision()) def find_sources(self): @@ -313,8 +326,33 @@ class manifest_maker(sdist): elif os.path.exists(self.manifest): self.read_manifest() ei_cmd = self.get_finalized_command('egg_info') + self._add_egg_info(cmd=ei_cmd) self.filelist.include_pattern("*", prefix=ei_cmd.egg_info) + def _add_egg_info(self, cmd): + """ + Add paths for egg-info files for an external egg-base. + + The egg-info files are written to egg-base. If egg-base is + outside the current working directory, this method + searchs the egg-base directory for files to include + in the manifest. Uses distutils.filelist.findall (which is + really the version monkeypatched in by setuptools/__init__.py) + to perform the search. + + Since findall records relative paths, prefix the returned + paths with cmd.egg_base, so add_default's include_pattern call + (which is looking for the absolute cmd.egg_info) will match + them. + """ + if cmd.egg_base == os.curdir: + # egg-info files were already added by something else + return + + discovered = distutils.filelist.findall(cmd.egg_base) + resolved = (os.path.join(cmd.egg_base, path) for path in discovered) + self.filelist.allfiles.extend(resolved) + def prune_file_list(self): build = self.get_finalized_command('build') base_dir = self.distribution.get_fullname() @@ -383,6 +421,12 @@ def write_requirements(cmd, basename, filename): cmd.write_or_delete_file("requirements", filename, data.getvalue()) +def write_setup_requirements(cmd, basename, filename): + data = StringIO() + _write_requirements(data, cmd.distribution.setup_requires) + cmd.write_or_delete_file("setup-requirements", filename, data.getvalue()) + + def write_toplevel_names(cmd, basename, filename): pkgs = dict.fromkeys( [ diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index a15582c3..4ec7ec91 100755 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -1,20 +1,18 @@ from glob import glob -from distutils.util import convert_path from distutils import log import distutils.command.sdist as orig import os -import re import sys import six -from setuptools import svn_utils from setuptools.utils import cs_path_exists import pkg_resources -READMES = ('README', 'README.rst', 'README.txt') +READMES = 'README', 'README.rst', 'README.txt' +_default_revctrl = list def walk_revctrl(dirname=''): """Find all files under revision control""" @@ -23,60 +21,6 @@ def walk_revctrl(dirname=''): yield item -# TODO will need test case -class re_finder(object): - """ - Finder that locates files based on entries in a file matched by a - regular expression. - """ - - def __init__(self, path, pattern, postproc=lambda x: x): - self.pattern = pattern - self.postproc = postproc - self.entries_path = convert_path(path) - - def _finder(self, dirname, filename): - f = open(filename, 'rU') - try: - data = f.read() - finally: - f.close() - for match in self.pattern.finditer(data): - path = match.group(1) - # postproc was formerly used when the svn finder - # was an re_finder for calling unescape - path = self.postproc(path) - yield svn_utils.joinpath(dirname, path) - - def find(self, dirname=''): - path = svn_utils.joinpath(dirname, self.entries_path) - - if not os.path.isfile(path): - # entries file doesn't exist - return - for path in self._finder(dirname, path): - if os.path.isfile(path): - yield path - elif os.path.isdir(path): - for item in self.find(path): - yield item - - __call__ = find - - -def _default_revctrl(dirname=''): - 'Primary svn_cvs entry point' - for finder in finders: - for item in finder(dirname): - yield item - - -finders = [ - re_finder('CVS/Entries', re.compile(r"^\w?/([^/]+)/", re.M)), - svn_utils.svn_finder, -] - - class sdist(orig.sdist): """Smart sdist that finds anything supported by revision control""" diff --git a/setuptools/command/test.py b/setuptools/command/test.py index 14dd2600..c5644530 100644 --- a/setuptools/command/test.py +++ b/setuptools/command/test.py @@ -173,4 +173,4 @@ class test(Command): if val is None: return parsed = EntryPoint.parse("x=" + val) - return parsed.load(require=False)() + return parsed._load()() diff --git a/setuptools/dist.py b/setuptools/dist.py index 99939f45..cdc15e46 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -19,6 +19,9 @@ from setuptools.depends import Require from setuptools import windows_support import pkg_resources +packaging = pkg_resources.packaging + + def _get_unpatched(cls): """Protect against re-patching the distutils if reloaded @@ -270,6 +273,27 @@ class Distribution(_Distribution): # Some people apparently take "version number" too literally :) self.metadata.version = str(self.metadata.version) + if self.metadata.version is not None: + try: + ver = packaging.version.Version(self.metadata.version) + normalized_version = str(ver) + if self.metadata.version != normalized_version: + warnings.warn( + "The version specified requires normalization, " + "consider using '%s' instead of '%s'." % ( + normalized_version, + self.metadata.version, + ) + ) + self.metadata.version = normalized_version + except (packaging.version.InvalidVersion, TypeError): + warnings.warn( + "The version specified (%r) is an invalid version, this " + "may not work as expected with newer versions of " + "setuptools, pip, and PyPI. Please see PEP 440 for more " + "details." % self.metadata.version + ) + def parse_command_line(self): """Process features after parsing command line options""" result = _Distribution.parse_command_line(self) @@ -411,7 +435,8 @@ class Distribution(_Distribution): def print_commands(self): for ep in pkg_resources.iter_entry_points('distutils.commands'): if ep.name not in self.cmdclass: - cmdclass = ep.load(False) # don't require extras, we're not running + # don't require extras as the commands won't be invoked + cmdclass = ep._load() self.cmdclass[ep.name] = cmdclass return _Distribution.print_commands(self) diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py index 1d23ba98..f99532f6 100755 --- a/setuptools/sandbox.py +++ b/setuptools/sandbox.py @@ -5,7 +5,10 @@ import operator import functools import itertools import re +import contextlib +import pickle +import six from six.moves import builtins import pkg_resources @@ -42,20 +45,150 @@ def _execfile(filename, globals, locals=None): code = compile(script, filename, 'exec') exec(code, globals, locals) + +@contextlib.contextmanager +def save_argv(): + saved = sys.argv[:] + try: + yield saved + finally: + sys.argv[:] = saved + + +@contextlib.contextmanager +def save_path(): + saved = sys.path[:] + try: + yield saved + finally: + sys.path[:] = saved + + +@contextlib.contextmanager +def override_temp(replacement): + """ + Monkey-patch tempfile.tempdir with replacement, ensuring it exists + """ + if not os.path.isdir(replacement): + os.makedirs(replacement) + + saved = tempfile.tempdir + + tempfile.tempdir = replacement + + try: + yield + finally: + tempfile.tempdir = saved + + +@contextlib.contextmanager +def pushd(target): + saved = os.getcwd() + os.chdir(target) + try: + yield saved + finally: + os.chdir(saved) + + +@contextlib.contextmanager +def save_modules(): + """ + Context in which imported modules are saved. + + Translates exceptions internal to the context into the equivalent exception + outside the context. + """ + saved = sys.modules.copy() + try: + try: + yield saved + except: + # dump any exception + class_, exc, tb = sys.exc_info() + saved_cls = pickle.dumps(class_) + saved_exc = pickle.dumps(exc) + raise + finally: + sys.modules.update(saved) + # remove any modules imported since + del_modules = ( + mod_name for mod_name in sys.modules + if mod_name not in saved + # exclude any encodings modules. See #285 + and not mod_name.startswith('encodings.') + ) + _clear_modules(del_modules) + except: + # reload and re-raise any exception, using restored modules + class_, exc, tb = sys.exc_info() + new_cls = pickle.loads(saved_cls) + new_exc = pickle.loads(saved_exc) + six.reraise(new_cls, new_exc, tb) + + +def _clear_modules(module_names): + for mod_name in list(module_names): + del sys.modules[mod_name] + + +@contextlib.contextmanager +def save_pkg_resources_state(): + saved = pkg_resources.__getstate__() + try: + yield saved + finally: + pkg_resources.__setstate__(saved) + + +@contextlib.contextmanager +def setup_context(setup_dir): + temp_dir = os.path.join(setup_dir, 'temp') + with save_pkg_resources_state(): + with save_modules(): + hide_setuptools() + with save_path(): + with save_argv(): + with override_temp(temp_dir): + with pushd(setup_dir): + # ensure setuptools commands are available + __import__('setuptools') + yield + + +def _needs_hiding(mod_name): + """ + >>> _needs_hiding('setuptools') + True + >>> _needs_hiding('pkg_resources') + True + >>> _needs_hiding('setuptools_plugin') + False + >>> _needs_hiding('setuptools.__init__') + True + >>> _needs_hiding('distutils') + True + """ + pattern = re.compile('(setuptools|pkg_resources|distutils)(\.|$)') + return bool(pattern.match(mod_name)) + + +def hide_setuptools(): + """ + Remove references to setuptools' modules from sys.modules to allow the + invocation to import the most appropriate setuptools. This technique is + necessary to avoid issues such as #315 where setuptools upgrading itself + would fail to find a function declared in the metadata. + """ + modules = filter(_needs_hiding, sys.modules) + _clear_modules(modules) + + def run_setup(setup_script, args): """Run a distutils setup script, sandboxed in its directory""" - old_dir = os.getcwd() - save_argv = sys.argv[:] - save_path = sys.path[:] setup_dir = os.path.abspath(os.path.dirname(setup_script)) - temp_dir = os.path.join(setup_dir,'temp') - if not os.path.isdir(temp_dir): os.makedirs(temp_dir) - save_tmp = tempfile.tempdir - save_modules = sys.modules.copy() - pr_state = pkg_resources.__getstate__() - try: - tempfile.tempdir = temp_dir - os.chdir(setup_dir) + with setup_context(setup_dir): try: sys.argv[:] = [setup_script]+list(args) sys.path.insert(0, setup_dir) @@ -71,21 +204,6 @@ def run_setup(setup_script, args): if v.args and v.args[0]: raise # Normal exit, just return - finally: - pkg_resources.__setstate__(pr_state) - sys.modules.update(save_modules) - # remove any modules imported within the sandbox - del_modules = [ - mod_name for mod_name in sys.modules - if mod_name not in save_modules - # exclude any encodings modules. See #285 - and not mod_name.startswith('encodings.') - ] - list(map(sys.modules.__delitem__, del_modules)) - os.chdir(old_dir) - sys.path[:] = save_path - sys.argv[:] = save_argv - tempfile.tempdir = save_tmp class AbstractSandbox: diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py deleted file mode 100644 index f80fd9f3..00000000 --- a/setuptools/svn_utils.py +++ /dev/null @@ -1,582 +0,0 @@ -from __future__ import absolute_import
-
-import os
-import re
-import sys
-from distutils import log
-import xml.dom.pulldom
-import shlex
-import locale
-import codecs
-import unicodedata
-import warnings
-from setuptools.py31compat import TemporaryDirectory
-from xml.sax.saxutils import unescape
-
-import six
-from six.moves import urllib
-
-from subprocess import Popen as _Popen, PIPE as _PIPE
-
-#NOTE: Use of the command line options require SVN 1.3 or newer (December 2005)
-# and SVN 1.3 hasn't been supported by the developers since mid 2008.
-
-#subprocess is called several times with shell=(sys.platform=='win32')
-#see the follow for more information:
-# http://bugs.python.org/issue8557
-# http://stackoverflow.com/questions/5658622/
-# python-subprocess-popen-environment-path
-
-def _run_command(args, stdout=_PIPE, stderr=_PIPE, encoding=None, stream=0):
- #regarding the shell argument, see: http://bugs.python.org/issue8557
- try:
- proc = _Popen(args, stdout=stdout, stderr=stderr,
- shell=(sys.platform == 'win32'))
-
- data = proc.communicate()[stream]
- except OSError:
- return 1, ''
-
- #doubled checked and
- data = decode_as_string(data, encoding)
-
- #communciate calls wait()
- return proc.returncode, data
-
-
-def _get_entry_schedule(entry):
- schedule = entry.getElementsByTagName('schedule')[0]
- return "".join([t.nodeValue
- for t in schedule.childNodes
- if t.nodeType == t.TEXT_NODE])
-
-
-def _get_target_property(target):
- property_text = target.getElementsByTagName('property')[0]
- return "".join([t.nodeValue
- for t in property_text.childNodes
- if t.nodeType == t.TEXT_NODE])
-
-
-def _get_xml_data(decoded_str):
- if six.PY2:
- #old versions want an encoded string
- data = decoded_str.encode('utf-8')
- else:
- data = decoded_str
- return data
-
-
-def joinpath(prefix, *suffix):
- if not prefix or prefix == '.':
- return os.path.join(*suffix)
- return os.path.join(prefix, *suffix)
-
-def determine_console_encoding():
- try:
- #try for the preferred encoding
- encoding = locale.getpreferredencoding()
-
- #see if the locale.getdefaultlocale returns null
- #some versions of python\platforms return US-ASCII
- #when it cannot determine an encoding
- if not encoding or encoding == "US-ASCII":
- encoding = locale.getdefaultlocale()[1]
-
- if encoding:
- codecs.lookup(encoding) # make sure a lookup error is not made
-
- except (locale.Error, LookupError):
- encoding = None
-
- is_osx = sys.platform == "darwin"
- if not encoding:
- return ["US-ASCII", "utf-8"][is_osx]
- elif encoding.startswith("mac-") and is_osx:
- #certain versions of python would return mac-roman as default
- #OSX as a left over of earlier mac versions.
- return "utf-8"
- else:
- return encoding
-
-_console_encoding = determine_console_encoding()
-
-def decode_as_string(text, encoding=None):
- """
- Decode the console or file output explicitly using getpreferredencoding.
- The text paraemeter should be a encoded string, if not no decode occurs
- If no encoding is given, getpreferredencoding is used. If encoding is
- specified, that is used instead. This would be needed for SVN --xml
- output. Unicode is explicitly put in composed NFC form.
-
- --xml should be UTF-8 (SVN Issue 2938) the discussion on the Subversion
- DEV List from 2007 seems to indicate the same.
- """
- #text should be a byte string
-
- if encoding is None:
- encoding = _console_encoding
-
- if not isinstance(text, six.text_type):
- text = text.decode(encoding)
-
- text = unicodedata.normalize('NFC', text)
-
- return text
-
-
-def parse_dir_entries(decoded_str):
- '''Parse the entries from a recursive info xml'''
- doc = xml.dom.pulldom.parseString(_get_xml_data(decoded_str))
- entries = list()
-
- for event, node in doc:
- if event == 'START_ELEMENT' and node.nodeName == 'entry':
- doc.expandNode(node)
- if not _get_entry_schedule(node).startswith('delete'):
- entries.append((node.getAttribute('path'),
- node.getAttribute('kind')))
-
- return entries[1:] # do not want the root directory
-
-
-def parse_externals_xml(decoded_str, prefix=''):
- '''Parse a propget svn:externals xml'''
- prefix = os.path.normpath(prefix)
- prefix = os.path.normcase(prefix)
-
- doc = xml.dom.pulldom.parseString(_get_xml_data(decoded_str))
- externals = list()
-
- for event, node in doc:
- if event == 'START_ELEMENT' and node.nodeName == 'target':
- doc.expandNode(node)
- path = os.path.normpath(node.getAttribute('path'))
-
- if os.path.normcase(path).startswith(prefix):
- path = path[len(prefix)+1:]
-
- data = _get_target_property(node)
- #data should be decoded already
- for external in parse_external_prop(data):
- externals.append(joinpath(path, external))
-
- return externals # do not want the root directory
-
-
-def parse_external_prop(lines):
- """
- Parse the value of a retrieved svn:externals entry.
-
- possible token setups (with quotng and backscaping in laters versions)
- URL[@#] EXT_FOLDERNAME
- [-r#] URL EXT_FOLDERNAME
- EXT_FOLDERNAME [-r#] URL
- """
- externals = []
- for line in lines.splitlines():
- line = line.lstrip() # there might be a "\ "
- if not line:
- continue
-
- if six.PY2:
- #shlex handles NULLs just fine and shlex in 2.7 tries to encode
- #as ascii automatiically
- line = line.encode('utf-8')
- line = shlex.split(line)
- if six.PY2:
- line = [x.decode('utf-8') for x in line]
-
- #EXT_FOLDERNAME is either the first or last depending on where
- #the URL falls
- if urllib.parse.urlsplit(line[-1])[0]:
- external = line[0]
- else:
- external = line[-1]
-
- external = decode_as_string(external, encoding="utf-8")
- externals.append(os.path.normpath(external))
-
- return externals
-
-
-def parse_prop_file(filename, key):
- found = False
- f = open(filename, 'rt')
- data = ''
- try:
- for line in iter(f.readline, ''): # can't use direct iter!
- parts = line.split()
- if len(parts) == 2:
- kind, length = parts
- data = f.read(int(length))
- if kind == 'K' and data == key:
- found = True
- elif kind == 'V' and found:
- break
- finally:
- f.close()
-
- return data
-
-
-class SvnInfo(object):
- '''
- Generic svn_info object. No has little knowledge of how to extract
- information. Use cls.load to instatiate according svn version.
-
- Paths are not filesystem encoded.
- '''
-
- @staticmethod
- def get_svn_version():
- # Temp config directory should be enough to check for repository
- # This is needed because .svn always creates .subversion and
- # some operating systems do not handle dot directory correctly.
- # Real queries in real svn repos with be concerned with it creation
- with TemporaryDirectory() as tempdir:
- code, data = _run_command(['svn',
- '--config-dir', tempdir,
- '--version',
- '--quiet'])
-
- if code == 0 and data:
- return data.strip()
- else:
- return ''
-
- #svnversion return values (previous implementations return max revision)
- # 4123:4168 mixed revision working copy
- # 4168M modified working copy
- # 4123S switched working copy
- # 4123:4168MS mixed revision, modified, switched working copy
- revision_re = re.compile(r'(?:([\-0-9]+):)?(\d+)([a-z]*)\s*$', re.I)
-
- @classmethod
- def load(cls, dirname=''):
- normdir = os.path.normpath(dirname)
-
- # Temp config directory should be enough to check for repository
- # This is needed because .svn always creates .subversion and
- # some operating systems do not handle dot directory correctly.
- # Real queries in real svn repos with be concerned with it creation
- with TemporaryDirectory() as tempdir:
- code, data = _run_command(['svn',
- '--config-dir', tempdir,
- 'info', normdir])
-
- # Must check for some contents, as some use empty directories
- # in testcases, however only enteries is needed also the info
- # command above MUST have worked
- svn_dir = os.path.join(normdir, '.svn')
- is_svn_wd = (not code or
- os.path.isfile(os.path.join(svn_dir, 'entries')))
-
- svn_version = tuple(cls.get_svn_version().split('.'))
-
- try:
- base_svn_version = tuple(int(x) for x in svn_version[:2])
- except ValueError:
- base_svn_version = tuple()
-
- if not is_svn_wd:
- #return an instance of this NO-OP class
- return SvnInfo(dirname)
-
- if code or not base_svn_version or base_svn_version < (1, 3):
- warnings.warn(("No SVN 1.3+ command found: falling back "
- "on pre 1.7 .svn parsing"), DeprecationWarning)
- return SvnFileInfo(dirname)
-
- if base_svn_version < (1, 5):
- return Svn13Info(dirname)
-
- return Svn15Info(dirname)
-
- def __init__(self, path=''):
- self.path = path
- self._entries = None
- self._externals = None
-
- def get_revision(self):
- 'Retrieve the directory revision information using svnversion'
- code, data = _run_command(['svnversion', '-c', self.path])
- if code:
- log.warn("svnversion failed")
- return 0
-
- parsed = self.revision_re.match(data)
- if parsed:
- return int(parsed.group(2))
- else:
- return 0
-
- @property
- def entries(self):
- if self._entries is None:
- self._entries = self.get_entries()
- return self._entries
-
- @property
- def externals(self):
- if self._externals is None:
- self._externals = self.get_externals()
- return self._externals
-
- def iter_externals(self):
- '''
- Iterate over the svn:external references in the repository path.
- '''
- for item in self.externals:
- yield item
-
- def iter_files(self):
- '''
- Iterate over the non-deleted file entries in the repository path
- '''
- for item, kind in self.entries:
- if kind.lower() == 'file':
- yield item
-
- def iter_dirs(self, include_root=True):
- '''
- Iterate over the non-deleted file entries in the repository path
- '''
- if include_root:
- yield self.path
- for item, kind in self.entries:
- if kind.lower() == 'dir':
- yield item
-
- def get_entries(self):
- return []
-
- def get_externals(self):
- return []
-
-
-class Svn13Info(SvnInfo):
- def get_entries(self):
- code, data = _run_command(['svn', 'info', '-R', '--xml', self.path],
- encoding="utf-8")
-
- if code:
- log.debug("svn info failed")
- return []
-
- return parse_dir_entries(data)
-
- def get_externals(self):
- #Previous to 1.5 --xml was not supported for svn propget and the -R
- #output format breaks the shlex compatible semantics.
- cmd = ['svn', 'propget', 'svn:externals']
- result = []
- for folder in self.iter_dirs():
- code, lines = _run_command(cmd + [folder], encoding="utf-8")
- if code != 0:
- log.warn("svn propget failed")
- return []
- #lines should a str
- for external in parse_external_prop(lines):
- if folder:
- external = os.path.join(folder, external)
- result.append(os.path.normpath(external))
-
- return result
-
-
-class Svn15Info(Svn13Info):
- def get_externals(self):
- cmd = ['svn', 'propget', 'svn:externals', self.path, '-R', '--xml']
- code, lines = _run_command(cmd, encoding="utf-8")
- if code:
- log.debug("svn propget failed")
- return []
- return parse_externals_xml(lines, prefix=os.path.abspath(self.path))
-
-
-class SvnFileInfo(SvnInfo):
-
- def __init__(self, path=''):
- super(SvnFileInfo, self).__init__(path)
- self._directories = None
- self._revision = None
-
- def _walk_svn(self, base):
- entry_file = joinpath(base, '.svn', 'entries')
- if os.path.isfile(entry_file):
- entries = SVNEntriesFile.load(base)
- yield (base, False, entries.parse_revision())
- for path in entries.get_undeleted_records():
- path = decode_as_string(path)
- path = joinpath(base, path)
- if os.path.isfile(path):
- yield (path, True, None)
- elif os.path.isdir(path):
- for item in self._walk_svn(path):
- yield item
-
- def _build_entries(self):
- entries = list()
-
- rev = 0
- for path, isfile, dir_rev in self._walk_svn(self.path):
- if isfile:
- entries.append((path, 'file'))
- else:
- entries.append((path, 'dir'))
- rev = max(rev, dir_rev)
-
- self._entries = entries
- self._revision = rev
-
- def get_entries(self):
- if self._entries is None:
- self._build_entries()
- return self._entries
-
- def get_revision(self):
- if self._revision is None:
- self._build_entries()
- return self._revision
-
- def get_externals(self):
- prop_files = [['.svn', 'dir-prop-base'],
- ['.svn', 'dir-props']]
- externals = []
-
- for dirname in self.iter_dirs():
- prop_file = None
- for rel_parts in prop_files:
- filename = joinpath(dirname, *rel_parts)
- if os.path.isfile(filename):
- prop_file = filename
-
- if prop_file is not None:
- ext_prop = parse_prop_file(prop_file, 'svn:externals')
- #ext_prop should be utf-8 coming from svn:externals
- ext_prop = decode_as_string(ext_prop, encoding="utf-8")
- externals.extend(parse_external_prop(ext_prop))
-
- return externals
-
-
-def svn_finder(dirname=''):
- #combined externals due to common interface
- #combined externals and entries due to lack of dir_props in 1.7
- info = SvnInfo.load(dirname)
- for path in info.iter_files():
- yield path
-
- for path in info.iter_externals():
- sub_info = SvnInfo.load(path)
- for sub_path in sub_info.iter_files():
- yield sub_path
-
-
-class SVNEntriesFile(object):
- def __init__(self, data):
- self.data = data
-
- @classmethod
- def load(class_, base):
- filename = os.path.join(base, '.svn', 'entries')
- f = open(filename)
- try:
- result = SVNEntriesFile.read(f)
- finally:
- f.close()
- return result
-
- @classmethod
- def read(class_, fileobj):
- data = fileobj.read()
- is_xml = data.startswith('<?xml')
- class_ = [SVNEntriesFileText, SVNEntriesFileXML][is_xml]
- return class_(data)
-
- def parse_revision(self):
- all_revs = self.parse_revision_numbers() + [0]
- return max(all_revs)
-
-
-class SVNEntriesFileText(SVNEntriesFile):
- known_svn_versions = {
- '1.4.x': 8,
- '1.5.x': 9,
- '1.6.x': 10,
- }
-
- def __get_cached_sections(self):
- return self.sections
-
- def get_sections(self):
- SECTION_DIVIDER = '\f\n'
- sections = self.data.split(SECTION_DIVIDER)
- sections = [x for x in map(str.splitlines, sections)]
- try:
- # remove the SVN version number from the first line
- svn_version = int(sections[0].pop(0))
- if not svn_version in self.known_svn_versions.values():
- log.warn("Unknown subversion verson %d", svn_version)
- except ValueError:
- return
- self.sections = sections
- self.get_sections = self.__get_cached_sections
- return self.sections
-
- def is_valid(self):
- return bool(self.get_sections())
-
- def get_url(self):
- return self.get_sections()[0][4]
-
- def parse_revision_numbers(self):
- revision_line_number = 9
- rev_numbers = [
- int(section[revision_line_number])
- for section in self.get_sections()
- if (len(section) > revision_line_number
- and section[revision_line_number])
- ]
- return rev_numbers
-
- def get_undeleted_records(self):
- undeleted = lambda s: s and s[0] and (len(s) < 6 or s[5] != 'delete')
- result = [
- section[0]
- for section in self.get_sections()
- if undeleted(section)
- ]
- return result
-
-
-class SVNEntriesFileXML(SVNEntriesFile):
- def is_valid(self):
- return True
-
- def get_url(self):
- "Get repository URL"
- urlre = re.compile('url="([^"]+)"')
- return urlre.search(self.data).group(1)
-
- def parse_revision_numbers(self):
- revre = re.compile(r'committed-rev="(\d+)"')
- return [
- int(m.group(1))
- for m in revre.finditer(self.data)
- ]
-
- def get_undeleted_records(self):
- entries_pattern = \
- re.compile(r'name="([^"]+)"(?![^>]+deleted="true")', re.I)
- results = [
- unescape(match.group(1))
- for match in entries_pattern.finditer(self.data)
- ]
- return results
-
-
-if __name__ == '__main__':
- for name in svn_finder(sys.argv[1]):
- print(name)
diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py index 823cf937..8cde6f60 100644 --- a/setuptools/tests/__init__.py +++ b/setuptools/tests/__init__.py @@ -1,8 +1,6 @@ """Tests for the 'setuptools' package""" import sys import os -import unittest -import doctest import distutils.core import distutils.cmd from distutils.errors import DistutilsOptionError, DistutilsPlatformError @@ -11,23 +9,13 @@ from distutils.core import Extension from distutils.version import LooseVersion import six +import pytest import setuptools.dist import setuptools.depends as dep from setuptools import Feature from setuptools.depends import Require -def additional_tests(): - suite = unittest.TestSuite(( - doctest.DocFileSuite( - os.path.join('tests', 'api_tests.txt'), - optionflags=doctest.ELLIPSIS, package='pkg_resources', - ), - )) - if sys.platform == 'win32': - suite.addTest(doctest.DocFileSuite('win_script_wrapper.txt')) - return suite - def makeSetup(**args): """Return distribution from 'setup(**args)', without executing commands""" @@ -42,7 +30,12 @@ def makeSetup(**args): distutils.core._setup_stop_after = None -class DependsTests(unittest.TestCase): +needs_bytecode = pytest.mark.skipif( + not hasattr(dep, 'get_module_constant'), + reason="bytecode support not available", +) + +class TestDepends: def testExtractConst(self): if not hasattr(dep, 'extract_constant'): @@ -55,86 +48,77 @@ class DependsTests(unittest.TestCase): y = z fc = six.get_function_code(f1) + # unrecognized name - self.assertEqual(dep.extract_constant(fc,'q', -1), None) + assert dep.extract_constant(fc,'q', -1) is None # constant assigned - self.assertEqual(dep.extract_constant(fc,'x', -1), "test") + dep.extract_constant(fc,'x', -1) == "test" # expression assigned - self.assertEqual(dep.extract_constant(fc,'y', -1), -1) + dep.extract_constant(fc,'y', -1) == -1 # recognized name, not assigned - self.assertEqual(dep.extract_constant(fc,'z', -1), None) + dep.extract_constant(fc,'z', -1) is None def testFindModule(self): - self.assertRaises(ImportError, dep.find_module, 'no-such.-thing') - self.assertRaises(ImportError, dep.find_module, 'setuptools.non-existent') + with pytest.raises(ImportError): + dep.find_module('no-such.-thing') + with pytest.raises(ImportError): + dep.find_module('setuptools.non-existent') f,p,i = dep.find_module('setuptools.tests') f.close() + @needs_bytecode def testModuleExtract(self): - if not hasattr(dep, 'get_module_constant'): - # skip on non-bytecode platforms - return - from email import __version__ - self.assertEqual( - dep.get_module_constant('email','__version__'), __version__ - ) - self.assertEqual( - dep.get_module_constant('sys','version'), sys.version - ) - self.assertEqual( - dep.get_module_constant('setuptools.tests','__doc__'),__doc__ - ) + assert dep.get_module_constant('email','__version__') == __version__ + assert dep.get_module_constant('sys','version') == sys.version + assert dep.get_module_constant('setuptools.tests','__doc__') == __doc__ + @needs_bytecode def testRequire(self): - if not hasattr(dep, 'extract_constant'): - # skip on non-bytecode platformsh - return - req = Require('Email','1.0.3','email') - self.assertEqual(req.name, 'Email') - self.assertEqual(req.module, 'email') - self.assertEqual(req.requested_version, '1.0.3') - self.assertEqual(req.attribute, '__version__') - self.assertEqual(req.full_name(), 'Email-1.0.3') + assert req.name == 'Email' + assert req.module == 'email' + assert req.requested_version == '1.0.3' + assert req.attribute == '__version__' + assert req.full_name() == 'Email-1.0.3' from email import __version__ - self.assertEqual(req.get_version(), __version__) - self.assertTrue(req.version_ok('1.0.9')) - self.assertTrue(not req.version_ok('0.9.1')) - self.assertTrue(not req.version_ok('unknown')) + assert req.get_version() == __version__ + assert req.version_ok('1.0.9') + assert not req.version_ok('0.9.1') + assert not req.version_ok('unknown') - self.assertTrue(req.is_present()) - self.assertTrue(req.is_current()) + assert req.is_present() + assert req.is_current() req = Require('Email 3000','03000','email',format=LooseVersion) - self.assertTrue(req.is_present()) - self.assertTrue(not req.is_current()) - self.assertTrue(not req.version_ok('unknown')) + assert req.is_present() + assert not req.is_current() + assert not req.version_ok('unknown') req = Require('Do-what-I-mean','1.0','d-w-i-m') - self.assertTrue(not req.is_present()) - self.assertTrue(not req.is_current()) + assert not req.is_present() + assert not req.is_current() req = Require('Tests', None, 'tests', homepage="http://example.com") - self.assertEqual(req.format, None) - self.assertEqual(req.attribute, None) - self.assertEqual(req.requested_version, None) - self.assertEqual(req.full_name(), 'Tests') - self.assertEqual(req.homepage, 'http://example.com') + assert req.format is None + assert req.attribute is None + assert req.requested_version is None + assert req.full_name() == 'Tests' + assert req.homepage == 'http://example.com' paths = [os.path.dirname(p) for p in __path__] - self.assertTrue(req.is_present(paths)) - self.assertTrue(req.is_current(paths)) + assert req.is_present(paths) + assert req.is_current(paths) -class DistroTests(unittest.TestCase): +class TestDistro: - def setUp(self): + def setup_method(self, method): self.e1 = Extension('bar.ext',['bar.c']) self.e2 = Extension('c.y', ['y.c']) @@ -146,21 +130,21 @@ class DistroTests(unittest.TestCase): ) def testDistroType(self): - self.assertTrue(isinstance(self.dist,setuptools.dist.Distribution)) + assert isinstance(self.dist,setuptools.dist.Distribution) def testExcludePackage(self): self.dist.exclude_package('a') - self.assertEqual(self.dist.packages, ['b','c']) + assert self.dist.packages == ['b','c'] self.dist.exclude_package('b') - self.assertEqual(self.dist.packages, ['c']) - self.assertEqual(self.dist.py_modules, ['x']) - self.assertEqual(self.dist.ext_modules, [self.e1, self.e2]) + assert self.dist.packages == ['c'] + assert self.dist.py_modules == ['x'] + assert self.dist.ext_modules == [self.e1, self.e2] self.dist.exclude_package('c') - self.assertEqual(self.dist.packages, []) - self.assertEqual(self.dist.py_modules, ['x']) - self.assertEqual(self.dist.ext_modules, [self.e1]) + assert self.dist.packages == [] + assert self.dist.py_modules == ['x'] + assert self.dist.ext_modules == [self.e1] # test removals from unspecified options makeSetup().exclude_package('x') @@ -168,21 +152,21 @@ class DistroTests(unittest.TestCase): def testIncludeExclude(self): # remove an extension self.dist.exclude(ext_modules=[self.e1]) - self.assertEqual(self.dist.ext_modules, [self.e2]) + assert self.dist.ext_modules == [self.e2] # add it back in self.dist.include(ext_modules=[self.e1]) - self.assertEqual(self.dist.ext_modules, [self.e2, self.e1]) + assert self.dist.ext_modules == [self.e2, self.e1] # should not add duplicate self.dist.include(ext_modules=[self.e1]) - self.assertEqual(self.dist.ext_modules, [self.e2, self.e1]) + assert self.dist.ext_modules == [self.e2, self.e1] def testExcludePackages(self): self.dist.exclude(packages=['c','b','a']) - self.assertEqual(self.dist.packages, []) - self.assertEqual(self.dist.py_modules, ['x']) - self.assertEqual(self.dist.ext_modules, [self.e1]) + assert self.dist.packages == [] + assert self.dist.py_modules == ['x'] + assert self.dist.ext_modules == [self.e1] def testEmpty(self): dist = makeSetup() @@ -191,49 +175,41 @@ class DistroTests(unittest.TestCase): dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2]) def testContents(self): - self.assertTrue(self.dist.has_contents_for('a')) + assert self.dist.has_contents_for('a') self.dist.exclude_package('a') - self.assertTrue(not self.dist.has_contents_for('a')) + assert not self.dist.has_contents_for('a') - self.assertTrue(self.dist.has_contents_for('b')) + assert self.dist.has_contents_for('b') self.dist.exclude_package('b') - self.assertTrue(not self.dist.has_contents_for('b')) + assert not self.dist.has_contents_for('b') - self.assertTrue(self.dist.has_contents_for('c')) + assert self.dist.has_contents_for('c') self.dist.exclude_package('c') - self.assertTrue(not self.dist.has_contents_for('c')) + assert not self.dist.has_contents_for('c') def testInvalidIncludeExclude(self): - self.assertRaises(DistutilsSetupError, - self.dist.include, nonexistent_option='x' - ) - self.assertRaises(DistutilsSetupError, - self.dist.exclude, nonexistent_option='x' - ) - self.assertRaises(DistutilsSetupError, - self.dist.include, packages={'x':'y'} - ) - self.assertRaises(DistutilsSetupError, - self.dist.exclude, packages={'x':'y'} - ) - self.assertRaises(DistutilsSetupError, - self.dist.include, ext_modules={'x':'y'} - ) - self.assertRaises(DistutilsSetupError, - self.dist.exclude, ext_modules={'x':'y'} - ) - - self.assertRaises(DistutilsSetupError, - self.dist.include, package_dir=['q'] - ) - self.assertRaises(DistutilsSetupError, - self.dist.exclude, package_dir=['q'] - ) - - -class FeatureTests(unittest.TestCase): - - def setUp(self): + with pytest.raises(DistutilsSetupError): + self.dist.include(nonexistent_option='x') + with pytest.raises(DistutilsSetupError): + self.dist.exclude(nonexistent_option='x') + with pytest.raises(DistutilsSetupError): + self.dist.include(packages={'x':'y'}) + with pytest.raises(DistutilsSetupError): + self.dist.exclude(packages={'x':'y'}) + with pytest.raises(DistutilsSetupError): + self.dist.include(ext_modules={'x':'y'}) + with pytest.raises(DistutilsSetupError): + self.dist.exclude(ext_modules={'x':'y'}) + + with pytest.raises(DistutilsSetupError): + self.dist.include(package_dir=['q']) + with pytest.raises(DistutilsSetupError): + self.dist.exclude(package_dir=['q']) + + +class TestFeatures: + + def setup_method(self, method): self.req = Require('Distutils','1.0.3','distutils') self.dist = makeSetup( features={ @@ -255,80 +231,75 @@ class FeatureTests(unittest.TestCase): ) def testDefaults(self): - self.assertTrue(not - Feature( - "test",standard=True,remove='x',available=False - ).include_by_default() - ) - self.assertTrue( - Feature("test",standard=True,remove='x').include_by_default() - ) + assert not Feature( + "test",standard=True,remove='x',available=False + ).include_by_default() + assert Feature("test",standard=True,remove='x').include_by_default() # Feature must have either kwargs, removes, or require_features - self.assertRaises(DistutilsSetupError, Feature, "test") + with pytest.raises(DistutilsSetupError): + Feature("test") def testAvailability(self): - self.assertRaises( - DistutilsPlatformError, - self.dist.features['dwim'].include_in, self.dist - ) + with pytest.raises(DistutilsPlatformError): + self.dist.features['dwim'].include_in(self.dist) def testFeatureOptions(self): dist = self.dist - self.assertTrue( + assert ( ('with-dwim',None,'include DWIM') in dist.feature_options ) - self.assertTrue( + assert ( ('without-dwim',None,'exclude DWIM (default)') in dist.feature_options ) - self.assertTrue( + assert ( ('with-bar',None,'include bar (default)') in dist.feature_options ) - self.assertTrue( + assert ( ('without-bar',None,'exclude bar') in dist.feature_options ) - self.assertEqual(dist.feature_negopt['without-foo'],'with-foo') - self.assertEqual(dist.feature_negopt['without-bar'],'with-bar') - self.assertEqual(dist.feature_negopt['without-dwim'],'with-dwim') - self.assertTrue(not 'without-baz' in dist.feature_negopt) + assert dist.feature_negopt['without-foo'] == 'with-foo' + assert dist.feature_negopt['without-bar'] == 'with-bar' + assert dist.feature_negopt['without-dwim'] == 'with-dwim' + assert (not 'without-baz' in dist.feature_negopt) def testUseFeatures(self): dist = self.dist - self.assertEqual(dist.with_foo,1) - self.assertEqual(dist.with_bar,0) - self.assertEqual(dist.with_baz,1) - self.assertTrue(not 'bar_et' in dist.py_modules) - self.assertTrue(not 'pkg.bar' in dist.packages) - self.assertTrue('pkg.baz' in dist.packages) - self.assertTrue('scripts/baz_it' in dist.scripts) - self.assertTrue(('libfoo','foo/foofoo.c') in dist.libraries) - self.assertEqual(dist.ext_modules,[]) - self.assertEqual(dist.require_features, [self.req]) + assert dist.with_foo == 1 + assert dist.with_bar == 0 + assert dist.with_baz == 1 + assert (not 'bar_et' in dist.py_modules) + assert (not 'pkg.bar' in dist.packages) + assert ('pkg.baz' in dist.packages) + assert ('scripts/baz_it' in dist.scripts) + assert (('libfoo','foo/foofoo.c') in dist.libraries) + assert dist.ext_modules == [] + assert dist.require_features == [self.req] # If we ask for bar, it should fail because we explicitly disabled # it on the command line - self.assertRaises(DistutilsOptionError, dist.include_feature, 'bar') + with pytest.raises(DistutilsOptionError): + dist.include_feature('bar') def testFeatureWithInvalidRemove(self): - self.assertRaises( - SystemExit, makeSetup, features = {'x':Feature('x', remove='y')} - ) + with pytest.raises(SystemExit): + makeSetup(features={'x':Feature('x', remove='y')}) -class TestCommandTests(unittest.TestCase): +class TestCommandTests: def testTestIsCommand(self): test_cmd = makeSetup().get_command_obj('test') - self.assertTrue(isinstance(test_cmd, distutils.cmd.Command)) + assert (isinstance(test_cmd, distutils.cmd.Command)) def testLongOptSuiteWNoDefault(self): ts1 = makeSetup(script_args=['test','--test-suite=foo.tests.suite']) ts1 = ts1.get_command_obj('test') ts1.ensure_finalized() - self.assertEqual(ts1.test_suite, 'foo.tests.suite') + assert ts1.test_suite == 'foo.tests.suite' def testDefaultSuite(self): ts2 = makeSetup(test_suite='bar.tests.suite').get_command_obj('test') ts2.ensure_finalized() - self.assertEqual(ts2.test_suite, 'bar.tests.suite') + assert ts2.test_suite == 'bar.tests.suite' def testDefaultWModuleOnCmdLine(self): ts3 = makeSetup( @@ -336,16 +307,17 @@ class TestCommandTests(unittest.TestCase): script_args=['test','-m','foo.tests'] ).get_command_obj('test') ts3.ensure_finalized() - self.assertEqual(ts3.test_module, 'foo.tests') - self.assertEqual(ts3.test_suite, 'foo.tests.test_suite') + assert ts3.test_module == 'foo.tests' + assert ts3.test_suite == 'foo.tests.test_suite' def testConflictingOptions(self): ts4 = makeSetup( script_args=['test','-m','bar.tests', '-s','foo.tests.suite'] ).get_command_obj('test') - self.assertRaises(DistutilsOptionError, ts4.ensure_finalized) + with pytest.raises(DistutilsOptionError): + ts4.ensure_finalized() def testNoSuite(self): ts5 = makeSetup().get_command_obj('test') ts5.ensure_finalized() - self.assertEqual(ts5.test_suite, None) + assert ts5.test_suite == None diff --git a/setuptools/tests/contexts.py b/setuptools/tests/contexts.py new file mode 100644 index 00000000..fabab071 --- /dev/null +++ b/setuptools/tests/contexts.py @@ -0,0 +1,93 @@ +import tempfile +import os +import shutil +import sys +import contextlib +import site + +import six + + +@contextlib.contextmanager +def tempdir(cd=lambda dir:None, **kwargs): + temp_dir = tempfile.mkdtemp(**kwargs) + orig_dir = os.getcwd() + try: + cd(temp_dir) + yield temp_dir + finally: + cd(orig_dir) + shutil.rmtree(temp_dir) + + +@contextlib.contextmanager +def environment(**replacements): + """ + In a context, patch the environment with replacements. Pass None values + to clear the values. + """ + saved = dict( + (key, os.environ['key']) + for key in replacements + if key in os.environ + ) + + # remove values that are null + remove = (key for (key, value) in replacements.items() if value is None) + for key in list(remove): + os.environ.pop(key, None) + replacements.pop(key) + + os.environ.update(replacements) + + try: + yield saved + finally: + for key in replacements: + os.environ.pop(key, None) + os.environ.update(saved) + + +@contextlib.contextmanager +def argv(repl): + old_argv = sys.argv[:] + sys.argv[:] = repl + yield + sys.argv[:] = old_argv + + +@contextlib.contextmanager +def quiet(): + """ + Redirect stdout/stderr to StringIO objects to prevent console output from + distutils commands. + """ + + old_stdout = sys.stdout + old_stderr = sys.stderr + new_stdout = sys.stdout = six.StringIO() + new_stderr = sys.stderr = six.StringIO() + try: + yield new_stdout, new_stderr + finally: + new_stdout.seek(0) + new_stderr.seek(0) + sys.stdout = old_stdout + sys.stderr = old_stderr + + +@contextlib.contextmanager +def save_user_site_setting(): + saved = site.ENABLE_USER_SITE + try: + yield saved + finally: + site.ENABLE_USER_SITE = saved + + +@contextlib.contextmanager +def suppress_exceptions(*excs): + try: + yield + except excs: + pass diff --git a/setuptools/tests/entries-v10 b/setuptools/tests/entries-v10 deleted file mode 100644 index 4446c501..00000000 --- a/setuptools/tests/entries-v10 +++ /dev/null @@ -1,615 +0,0 @@ -10 - -dir -89001 -http://svn.python.org/projects/sandbox/branches/setuptools-0.6 -http://svn.python.org/projects - - - -2013-06-03T17:26:03.052972Z -89000 -phillip.eby - - - - - - - - - - - - - - -6015fed2-1504-0410-9fe1-9d1591cc4771 - -api_tests.txt -file - - - - -2013-06-19T13:20:47.948712Z -dec366372ca14fbeaeb26f492bcf5725 -2013-05-15T22:04:59.389374Z -88997 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -12312 - -setuptools.egg-info -dir - -README.txt -file - - - - -2013-06-19T13:20:47.948712Z -26f0dd5d095522ba3ad999b6b6777b92 -2011-05-31T20:10:56.416725Z -88846 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -7615 - -easy_install.py -file - - - - -2013-06-19T13:20:47.948712Z -97b52fe7253bf4683f9f626f015eb72e -2006-09-20T20:48:18.716070Z -51935 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -126 - -setuptools -dir - -launcher.c -file - - - - -2013-06-19T13:20:47.924700Z -e5a8e77de9022688b80f77fc6d742fee -2009-10-19T21:03:29.785400Z -75544 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -7476 - -ez_setup.py -file - - - - -2013-06-19T13:20:47.924700Z -17e8ec5e08faccfcb08b5f8d5167ca14 -2011-01-20T18:50:00.815420Z -88124 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -8350 - -version -file - - - - -2013-06-19T13:20:47.924700Z -e456da09e0c9e224a56302f8316b6dbf -2007-01-09T19:21:05.921317Z -53317 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -1143 - -setup.py -file - - - - -2013-06-19T13:20:47.924700Z -d4e5b3c16bd61bfef6c0bb9377a3a3ea -2013-05-15T22:04:59.389374Z -88997 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -5228 - -release.sh -file - - - - -2013-06-19T13:20:47.932704Z -b1fd4054a1c107ff0f27baacd97be94c -2009-10-28T17:12:45.227140Z -75925 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -1044 - -pkg_resources.txt -file - - - - -2013-06-19T13:20:47.928702Z -f497e7c92a4de207cbd9ab1943f93388 -2009-10-12T20:00:02.336146Z -75385 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -94518 - -site.py -file - - - - -2013-06-19T13:20:47.932704Z -ebaac6fb6525f77ca950d22e6f8315df -2006-03-11T00:39:09.666740Z -42965 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -2362 - -version.dat -file - - - - -2013-06-19T13:20:47.932704Z -8e14ecea32b9874cd7d29277494554c0 -2009-10-28T17:12:45.227140Z -75925 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -80 - -virtual-python.py -file - - - - -2013-06-19T13:20:47.932704Z -aa857add3b5563238f0a904187f5ded9 -2005-10-17T02:26:39.000000Z -41262 -pje -has-props - - - - - - - - - - - - - - - - - - - - -3898 - -setup.cfg -file - - - - -2013-06-19T13:20:47.932704Z -eda883e744fce83f8107ad8dc8303536 -2006-09-21T22:26:48.050256Z -51965 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -296 - -setuptools.txt -file - - - - -2013-06-19T13:20:47.940708Z -11926256f06046b196eaf814772504e7 -2013-05-15T22:04:59.389374Z -88997 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -149832 - -pkg_resources.py -file - - - - -2013-06-19T13:20:47.940708Z -b63a30f5f0f0225a788c2c0e3430b3cf -2013-05-15T22:04:59.389374Z -88997 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -90397 - -tests -dir - -wikiup.cfg -file - - - - -2013-06-19T13:20:47.944710Z -34ad845a5e0a0b46458557fa910bf429 -2008-08-21T17:23:50.797633Z -65935 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -136 - -EasyInstall.txt -file - - - - -2013-06-19T13:20:47.944710Z -e97387c517f70fc18a377e42d19d64d4 -2013-05-15T22:04:59.389374Z -88997 -phillip.eby -has-props - - - - - - - - - - - - - - - - - - - - -82495 - diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py index c8d0e669..a23c0504 100644 --- a/setuptools/tests/environment.py +++ b/setuptools/tests/environment.py @@ -1,68 +1,10 @@ import os -import zipfile import sys -import tempfile -import unittest -import shutil -import stat import unicodedata from subprocess import Popen as _Popen, PIPE as _PIPE -def _remove_dir(target): - - #on windows this seems to a problem - for dir_path, dirs, files in os.walk(target): - os.chmod(dir_path, stat.S_IWRITE) - for filename in files: - os.chmod(os.path.join(dir_path, filename), stat.S_IWRITE) - shutil.rmtree(target) - - -class ZippedEnvironment(unittest.TestCase): - - datafile = None - dataname = None - old_cwd = None - - def setUp(self): - if self.datafile is None or self.dataname is None: - return - - if not os.path.isfile(self.datafile): - self.old_cwd = None - return - - self.old_cwd = os.getcwd() - - self.temp_dir = tempfile.mkdtemp() - zip_file, source, target = [None, None, None] - try: - zip_file = zipfile.ZipFile(self.datafile) - for files in zip_file.namelist(): - zip_file.extract(files, self.temp_dir) - finally: - if zip_file: - zip_file.close() - del zip_file - - os.chdir(os.path.join(self.temp_dir, self.dataname)) - - def tearDown(self): - #Assume setUp was never completed - if self.dataname is None or self.datafile is None: - return - - try: - if self.old_cwd: - os.chdir(self.old_cwd) - _remove_dir(self.temp_dir) - except OSError: - #sigh? - pass - - def _which_dirs(cmd): result = set() for path in os.environ.get('PATH', '').split(os.pathsep): diff --git a/setuptools/tests/fixtures.py b/setuptools/tests/fixtures.py new file mode 100644 index 00000000..0b1eaf5f --- /dev/null +++ b/setuptools/tests/fixtures.py @@ -0,0 +1,24 @@ +import mock +import pytest + +from . import contexts + + +@pytest.yield_fixture +def user_override(): + """ + Override site.USER_BASE and site.USER_SITE with temporary directories in + a context. + """ + with contexts.tempdir() as user_base: + with mock.patch('site.USER_BASE', user_base): + with contexts.tempdir() as user_site: + with mock.patch('site.USER_SITE', user_site): + with contexts.save_user_site_setting(): + yield + + +@pytest.yield_fixture +def tmpdir_cwd(tmpdir): + with tmpdir.as_cwd() as orig: + yield orig diff --git a/setuptools/tests/py26compat.py b/setuptools/tests/py26compat.py index d4fb891a..c53b4809 100644 --- a/setuptools/tests/py26compat.py +++ b/setuptools/tests/py26compat.py @@ -1,14 +1,11 @@ -import unittest +import sys +import tarfile +import contextlib -try: - # provide skipIf for Python 2.4-2.6 - skipIf = unittest.skipIf -except AttributeError: - def skipIf(condition, reason): - def skipper(func): - def skip(*args, **kwargs): - return - if condition: - return skip - return func - return skipper +def _tarfile_open_ex(*args, **kwargs): + """ + Extend result as a context manager. + """ + return contextlib.closing(tarfile.open(*args, **kwargs)) + +tarfile_open = _tarfile_open_ex if sys.version_info < (2,7) else tarfile.open diff --git a/setuptools/tests/server.py b/setuptools/tests/server.py index 099e8b19..1fee0563 100644 --- a/setuptools/tests/server.py +++ b/setuptools/tests/server.py @@ -1,10 +1,10 @@ """Basic http server for tests to simulate PyPI or custom indexes """ -import sys + import time import threading -from six.moves import BaseHTTPServer, SimpleHTTPServer, urllib +from six.moves import BaseHTTPServer, SimpleHTTPServer class IndexServer(BaseHTTPServer.HTTPServer): """Basic single-threaded http server simulating a package index @@ -23,12 +23,8 @@ class IndexServer(BaseHTTPServer.HTTPServer): RequestHandlerClass) self._run = True - def serve(self): - while self._run: - self.handle_request() - def start(self): - self.thread = threading.Thread(target=self.serve) + self.thread = threading.Thread(target=self.serve_forever) self.thread.start() def stop(self): @@ -37,19 +33,7 @@ class IndexServer(BaseHTTPServer.HTTPServer): # Let the server finish the last request and wait for a new one. time.sleep(0.1) - # self.shutdown is not supported on python < 2.6, so just - # set _run to false, and make a request, causing it to - # terminate. - self._run = False - url = 'http://127.0.0.1:%(server_port)s/' % vars(self) - try: - if sys.version_info >= (2, 6): - urllib.request.urlopen(url, timeout=5) - else: - urllib.request.urlopen(url) - except urllib.error.URLError: - # ignore any errors; all that's important is the request - pass + self.shutdown() self.thread.join() self.socket.close() @@ -78,6 +62,6 @@ class MockServer(BaseHTTPServer.HTTPServer, threading.Thread): def run(self): self.serve_forever() + @property def url(self): return 'http://localhost:%(server_port)s/' % vars(self) - url = property(url) diff --git a/setuptools/tests/svn_data/dummy.zip b/setuptools/tests/svn_data/dummy.zip Binary files differdeleted file mode 100644 index 1347be53..00000000 --- a/setuptools/tests/svn_data/dummy.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/dummy13.zip b/setuptools/tests/svn_data/dummy13.zip Binary files differdeleted file mode 100644 index 47764342..00000000 --- a/setuptools/tests/svn_data/dummy13.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/dummy14.zip b/setuptools/tests/svn_data/dummy14.zip Binary files differdeleted file mode 100644 index 02ed8cf0..00000000 --- a/setuptools/tests/svn_data/dummy14.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/dummy15.zip b/setuptools/tests/svn_data/dummy15.zip Binary files differdeleted file mode 100644 index ed8daeeb..00000000 --- a/setuptools/tests/svn_data/dummy15.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/dummy16.zip b/setuptools/tests/svn_data/dummy16.zip Binary files differdeleted file mode 100644 index b6e98d6c..00000000 --- a/setuptools/tests/svn_data/dummy16.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/dummy17.zip b/setuptools/tests/svn_data/dummy17.zip Binary files differdeleted file mode 100644 index d96e1513..00000000 --- a/setuptools/tests/svn_data/dummy17.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/dummy18.zip b/setuptools/tests/svn_data/dummy18.zip Binary files differdeleted file mode 100644 index a7267838..00000000 --- a/setuptools/tests/svn_data/dummy18.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/svn13_example.zip b/setuptools/tests/svn_data/svn13_example.zip Binary files differdeleted file mode 100644 index d85fb84f..00000000 --- a/setuptools/tests/svn_data/svn13_example.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/svn13_ext_list.txt b/setuptools/tests/svn_data/svn13_ext_list.txt deleted file mode 100644 index 0bb0f438..00000000 --- a/setuptools/tests/svn_data/svn13_ext_list.txt +++ /dev/null @@ -1,3 +0,0 @@ -third_party3 file:///C:/development/svn_example/repos/svn13/extra1
-third_party2 -r3 file:///C:/development/svn_example/repos/svn13/extra1
-third_party -r1 file:///C:/development/svn_example/repos/svn13/extra1
diff --git a/setuptools/tests/svn_data/svn13_ext_list.xml b/setuptools/tests/svn_data/svn13_ext_list.xml deleted file mode 100644 index e69de29b..00000000 --- a/setuptools/tests/svn_data/svn13_ext_list.xml +++ /dev/null diff --git a/setuptools/tests/svn_data/svn13_info.xml b/setuptools/tests/svn_data/svn13_info.xml deleted file mode 100644 index 5c96520a..00000000 --- a/setuptools/tests/svn_data/svn13_info.xml +++ /dev/null @@ -1,121 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?>
-<info>
-<entry
- kind="dir"
- path="svn13_example"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn13/main</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn13/main</root>
-<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<prop-updated>2013-07-13T15:33:23.187500Z</prop-updated>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:33:28.359375Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn13_example\a file"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn13/main/a%20file</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn13/main</root>
-<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<text-updated>2013-07-13T15:33:21.109375Z</text-updated>
-<checksum>a6166e5e98a5a503089cde9bc8031293</checksum>
-</wc-info>
-<commit
- revision="3">
-<author>ptt</author>
-<date>2013-07-13T15:33:21.312500Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn13_example\to_delete"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn13/main/to_delete</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn13/main</root>
-<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
-</repository>
-<wc-info>
-<schedule>delete</schedule>
-<text-updated>2013-07-13T15:33:28.140625Z</text-updated>
-<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:33:28.359375Z</date>
-</commit>
-</entry>
-<entry
- kind="dir"
- path="svn13_example\folder"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn13/main/folder</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn13/main</root>
-<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<prop-updated>2013-07-13T15:33:26.187500Z</prop-updated>
-</wc-info>
-<commit
- revision="5">
-<author>ptt</author>
-<date>2013-07-13T15:33:26.312500Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn13_example\folder\quest.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn13/main/folder/quest.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn13/main</root>
-<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<text-updated>2013-07-13T15:33:20.109375Z</text-updated>
-<checksum>795240c6a830c14f83961e57e07dad12</checksum>
-</wc-info>
-<commit
- revision="2">
-<author>ptt</author>
-<date>2013-07-13T15:33:20.312500Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn13_example\folder\lalala.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn13/main/folder/lalala.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn13/main</root>
-<uuid>d2996769-47b0-9946-b618-da1aa3eceda3</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<text-updated>2013-07-13T15:33:19.375000Z</text-updated>
-<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
-</wc-info>
-<commit
- revision="1">
-<author>ptt</author>
-<date>2013-07-13T15:33:19.609375Z</date>
-</commit>
-</entry>
-</info>
diff --git a/setuptools/tests/svn_data/svn14_example.zip b/setuptools/tests/svn_data/svn14_example.zip Binary files differdeleted file mode 100644 index 57093c0b..00000000 --- a/setuptools/tests/svn_data/svn14_example.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/svn14_ext_list.txt b/setuptools/tests/svn_data/svn14_ext_list.txt deleted file mode 100644 index 800a0965..00000000 --- a/setuptools/tests/svn_data/svn14_ext_list.txt +++ /dev/null @@ -1,4 +0,0 @@ -third_party3 file:///C:/development/svn_example/repos/svn13/extra1
-third_party2 -r3 file:///C:/development/svn_example/repos/svn13/extra1
-third_party -r1 file:///C:/development/svn_example/repos/svn13/extra1
-
diff --git a/setuptools/tests/svn_data/svn14_ext_list.xml b/setuptools/tests/svn_data/svn14_ext_list.xml deleted file mode 100644 index e69de29b..00000000 --- a/setuptools/tests/svn_data/svn14_ext_list.xml +++ /dev/null diff --git a/setuptools/tests/svn_data/svn14_info.xml b/setuptools/tests/svn_data/svn14_info.xml deleted file mode 100644 index a896a77f..00000000 --- a/setuptools/tests/svn_data/svn14_info.xml +++ /dev/null @@ -1,119 +0,0 @@ -<?xml version="1.0"?>
-<info>
-<entry
- kind="dir"
- path="svn14_example"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn14/main</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn14/main</root>
-<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:34:14.406250Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn14_example\a file"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn14/main/a%20file</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn14/main</root>
-<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<text-updated>2013-07-13T15:34:08.109375Z</text-updated>
-<checksum>a6166e5e98a5a503089cde9bc8031293</checksum>
-</wc-info>
-<commit
- revision="3">
-<author>ptt</author>
-<date>2013-07-13T15:34:08.390625Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn14_example\to_delete"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn14/main/to_delete</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn14/main</root>
-<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
-</repository>
-<wc-info>
-<schedule>delete</schedule>
-<text-updated>2013-07-13T15:34:14.125000Z</text-updated>
-<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:34:14.406250Z</date>
-</commit>
-</entry>
-<entry
- kind="dir"
- path="svn14_example\folder"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn14/main/folder</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn14/main</root>
-<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-</wc-info>
-<commit
- revision="5">
-<author>ptt</author>
-<date>2013-07-13T15:34:12.390625Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn14_example\folder\quest.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn14/main/folder/quest.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn14/main</root>
-<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<text-updated>2013-07-13T15:34:07.109375Z</text-updated>
-<checksum>795240c6a830c14f83961e57e07dad12</checksum>
-</wc-info>
-<commit
- revision="2">
-<author>ptt</author>
-<date>2013-07-13T15:34:07.390625Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn14_example\folder\lalala.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn14/main/folder/lalala.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn14/main</root>
-<uuid>c75942e5-8b7a-354d-b1cf-73dee23fa94f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<text-updated>2013-07-13T15:34:06.250000Z</text-updated>
-<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
-</wc-info>
-<commit
- revision="1">
-<author>ptt</author>
-<date>2013-07-13T15:34:06.531250Z</date>
-</commit>
-</entry>
-</info>
diff --git a/setuptools/tests/svn_data/svn15_example.zip b/setuptools/tests/svn_data/svn15_example.zip Binary files differdeleted file mode 100644 index 52a1d45b..00000000 --- a/setuptools/tests/svn_data/svn15_example.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/svn15_ext_list.txt b/setuptools/tests/svn_data/svn15_ext_list.txt deleted file mode 100644 index 75fde4e6..00000000 --- a/setuptools/tests/svn_data/svn15_ext_list.txt +++ /dev/null @@ -1,4 +0,0 @@ -third_party3 file:///C:/development/svn_example/repos/svn15/extra1
--r3 file:///C:/development/svn_example/repos/svn15/extra1 third_party2
-file:///C:/development/svn_example/repos/svn15/extra1@r1 third_party
-
diff --git a/setuptools/tests/svn_data/svn15_ext_list.xml b/setuptools/tests/svn_data/svn15_ext_list.xml deleted file mode 100644 index 6950b3c5..00000000 --- a/setuptools/tests/svn_data/svn15_ext_list.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0"?>
-<properties>
-<target
- path="C:/development/svn_example/svn15_example/folder">
-<property
- name="svn:externals">third_party3 file:///C:/development/svn_example/repos/svn15/extra2
--r3 file:///C:/development/svn_example/repos/svn15/extra2 third_party2
-file:///C:/development/svn_example/repos/svn15/extra2@r1 third_party大介
-</property>
-</target>
-<target
- path="C:/development/svn_example/svn15_example">
-<property
- name="svn:externals">third_party3 file:///C:/development/svn_example/repos/svn15/extra1
--r3 file:///C:/development/svn_example/repos/svn15/extra1 third_party2
-file:///C:/development/svn_example/repos/svn15/extra1@r1 third_party大介
-</property>
-</target>
-</properties>
diff --git a/setuptools/tests/svn_data/svn15_info.xml b/setuptools/tests/svn_data/svn15_info.xml deleted file mode 100644 index 0b3550af..00000000 --- a/setuptools/tests/svn_data/svn15_info.xml +++ /dev/null @@ -1,125 +0,0 @@ -<?xml version="1.0"?>
-<info>
-<entry
- kind="dir"
- path="svn15_example"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn15/main</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn15/main</root>
-<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:34:49.562500Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn15_example\a file"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn15/main/a%20file</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn15/main</root>
-<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:34:43.109375Z</text-updated>
-<checksum>a6166e5e98a5a503089cde9bc8031293</checksum>
-</wc-info>
-<commit
- revision="3">
-<author>ptt</author>
-<date>2013-07-13T15:34:43.484375Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn15_example\to_delete"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn15/main/to_delete</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn15/main</root>
-<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
-</repository>
-<wc-info>
-<schedule>delete</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:34:49.125000Z</text-updated>
-<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:34:49.562500Z</date>
-</commit>
-</entry>
-<entry
- kind="dir"
- path="svn15_example\folder"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn15/main/folder</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn15/main</root>
-<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-</wc-info>
-<commit
- revision="5">
-<author>ptt</author>
-<date>2013-07-13T15:34:47.515625Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn15_example\folder\quest.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn15/main/folder/quest.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn15/main</root>
-<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:34:42.109375Z</text-updated>
-<checksum>795240c6a830c14f83961e57e07dad12</checksum>
-</wc-info>
-<commit
- revision="2">
-<author>ptt</author>
-<date>2013-07-13T15:34:42.484375Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn15_example\folder\lalala.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn15/main/folder/lalala.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn15/main</root>
-<uuid>4eab6983-54fe-384b-a282-9306f52d948f</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:34:41.375000Z</text-updated>
-<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
-</wc-info>
-<commit
- revision="1">
-<author>ptt</author>
-<date>2013-07-13T15:34:41.734375Z</date>
-</commit>
-</entry>
-</info>
diff --git a/setuptools/tests/svn_data/svn16_example.zip b/setuptools/tests/svn_data/svn16_example.zip Binary files differdeleted file mode 100644 index e886b2af..00000000 --- a/setuptools/tests/svn_data/svn16_example.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/svn16_ext_list.txt b/setuptools/tests/svn_data/svn16_ext_list.txt deleted file mode 100644 index 3ca54893..00000000 --- a/setuptools/tests/svn_data/svn16_ext_list.txt +++ /dev/null @@ -1,4 +0,0 @@ -"third party3" file:///C:/development/svn_example/repos/svn16/extra1
-'third party3b' file:///C:/development/svn_example/repos/svn16/extra1
--r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party
diff --git a/setuptools/tests/svn_data/svn16_ext_list.xml b/setuptools/tests/svn_data/svn16_ext_list.xml deleted file mode 100644 index 8ddaed0a..00000000 --- a/setuptools/tests/svn_data/svn16_ext_list.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0"?>
-<properties>
-<target
- path="C:/development/svn_example/svn16_example/folder">
-<property
- name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn16/extra2
--r3 file:///C:/development/svn_example/repos/svn16/extra2 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra2@r1 third_party大介
-</property>
-</target>
-<target
- path="C:/development/svn_example/svn16_example">
-<property
- name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn16/extra1
--r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
-</property>
-</target>
-</properties>
diff --git a/setuptools/tests/svn_data/svn16_info.xml b/setuptools/tests/svn_data/svn16_info.xml deleted file mode 100644 index 745469c9..00000000 --- a/setuptools/tests/svn_data/svn16_info.xml +++ /dev/null @@ -1,125 +0,0 @@ -<?xml version="1.0"?>
-<info>
-<entry
- kind="dir"
- path="svn16_example"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn16/main</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn16/main</root>
-<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:35:17.390625Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn16_example\a file"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn16/main/a%20file</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn16/main</root>
-<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:14.578125Z</text-updated>
-<checksum>a6166e5e98a5a503089cde9bc8031293</checksum>
-</wc-info>
-<commit
- revision="3">
-<author>ptt</author>
-<date>2013-07-13T15:35:14.906250Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn16_example\to_delete"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn16/main/to_delete</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn16/main</root>
-<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
-</repository>
-<wc-info>
-<schedule>delete</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:17.046875Z</text-updated>
-<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:35:17.390625Z</date>
-</commit>
-</entry>
-<entry
- kind="dir"
- path="svn16_example\folder"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn16/main/folder</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn16/main</root>
-<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-</wc-info>
-<commit
- revision="5">
-<author>ptt</author>
-<date>2013-07-13T15:35:16.406250Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn16_example\folder\quest.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn16/main/folder/quest.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn16/main</root>
-<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:14.078125Z</text-updated>
-<checksum>795240c6a830c14f83961e57e07dad12</checksum>
-</wc-info>
-<commit
- revision="2">
-<author>ptt</author>
-<date>2013-07-13T15:35:14.421875Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn16_example\folder\lalala.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn16/main/folder/lalala.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn16/main</root>
-<uuid>bd8d2cfc-1a74-de45-b166-262010c17c0a</uuid>
-</repository>
-<wc-info>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:12.171875Z</text-updated>
-<checksum>d41d8cd98f00b204e9800998ecf8427e</checksum>
-</wc-info>
-<commit
- revision="1">
-<author>ptt</author>
-<date>2013-07-13T15:35:13.906250Z</date>
-</commit>
-</entry>
-</info>
diff --git a/setuptools/tests/svn_data/svn17_example.zip b/setuptools/tests/svn_data/svn17_example.zip Binary files differdeleted file mode 100644 index ba0e8823..00000000 --- a/setuptools/tests/svn_data/svn17_example.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/svn17_ext_list.txt b/setuptools/tests/svn_data/svn17_ext_list.txt deleted file mode 100644 index a8b832a8..00000000 --- a/setuptools/tests/svn_data/svn17_ext_list.txt +++ /dev/null @@ -1,4 +0,0 @@ -"third party3" file:///C:/development/svn_example/repos/svn17/extra1
-'third party3b' file:///C:/development/svn_example/repos/svn17/extra1
--r3 file:///C:/development/svn_example/repos/svn17/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn17/extra1@r1 third_party
diff --git a/setuptools/tests/svn_data/svn17_ext_list.xml b/setuptools/tests/svn_data/svn17_ext_list.xml deleted file mode 100644 index 2879bb65..00000000 --- a/setuptools/tests/svn_data/svn17_ext_list.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<properties>
-<target
- path="C:/development/svn_example/svn17_example">
-<property
- name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn16/extra1
--r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
-</property>
-</target>
-<target
- path="C:/development/svn_example/svn17_example/folder">
-<property
- name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn17/extra2
--r3 file:///C:/development/svn_example/repos/svn17/extra2 third\ party2
-file:///C:/development/svn_example/repos/svn17/extra2@r1 third_party大介
-</property>
-</target>
-</properties>
diff --git a/setuptools/tests/svn_data/svn17_info.xml b/setuptools/tests/svn_data/svn17_info.xml deleted file mode 100644 index 6cffeffd..00000000 --- a/setuptools/tests/svn_data/svn17_info.xml +++ /dev/null @@ -1,130 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<info>
-<entry
- kind="dir"
- path="svn17_example"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn17/main</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn17/main</root>
-<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:35:36.171875Z</date>
-</commit>
-</entry>
-<entry
- path="svn17_example\folder"
- revision="6"
- kind="dir">
-<url>file:///C:/development/svn_example/repos/svn17/main/folder</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn17/main</root>
-<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-</wc-info>
-<commit
- revision="5">
-<author>ptt</author>
-<date>2013-07-13T15:35:34.859375Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn17_example\folder\quest.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn17/main/folder/quest.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn17/main</root>
-<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:32.812500Z</text-updated>
-<checksum>bc80eba9e7a10c0a571a4678c520bc9683f3bac2</checksum>
-</wc-info>
-<commit
- revision="2">
-<author>ptt</author>
-<date>2013-07-13T15:35:33.109375Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn17_example\folder\lalala.txt"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn17/main/folder/lalala.txt</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn17/main</root>
-<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:32.343750Z</text-updated>
-<checksum>da39a3ee5e6b4b0d3255bfef95601890afd80709</checksum>
-</wc-info>
-<commit
- revision="1">
-<author>ptt</author>
-<date>2013-07-13T15:35:32.687500Z</date>
-</commit>
-</entry>
-<entry
- path="svn17_example\a file"
- revision="6"
- kind="file">
-<url>file:///C:/development/svn_example/repos/svn17/main/a%20file</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn17/main</root>
-<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:33.187500Z</text-updated>
-<checksum>43785ab4b1816b49f242990883292813cd4f486c</checksum>
-</wc-info>
-<commit
- revision="3">
-<author>ptt</author>
-<date>2013-07-13T15:35:33.515625Z</date>
-</commit>
-</entry>
-<entry
- path="svn17_example\to_delete"
- revision="6"
- kind="file">
-<url>file:///C:/development/svn_example/repos/svn17/main/to_delete</url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn17/main</root>
-<uuid>5ba45434-5197-164e-afab-81923f4744f5</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn17_example</wcroot-abspath>
-<schedule>delete</schedule>
-<depth>infinity</depth>
-<checksum>da39a3ee5e6b4b0d3255bfef95601890afd80709</checksum>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:35:36.171875Z</date>
-</commit>
-</entry>
-</info>
diff --git a/setuptools/tests/svn_data/svn18_example.zip b/setuptools/tests/svn_data/svn18_example.zip Binary files differdeleted file mode 100644 index 4362f8e9..00000000 --- a/setuptools/tests/svn_data/svn18_example.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/svn18_ext_list.txt b/setuptools/tests/svn_data/svn18_ext_list.txt deleted file mode 100644 index c90a5f11..00000000 --- a/setuptools/tests/svn_data/svn18_ext_list.txt +++ /dev/null @@ -1,4 +0,0 @@ -"third party3" file:///C:/development/svn_example/repos/svn18/extra1
-'third party3b' file:///C:/development/svn_example/repos/svn18/extra1
--r3 file:///C:/development/svn_example/repos/svn18/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn18/extra1@r1 third_party
diff --git a/setuptools/tests/svn_data/svn18_ext_list.xml b/setuptools/tests/svn_data/svn18_ext_list.xml deleted file mode 100644 index 9b5e9e96..00000000 --- a/setuptools/tests/svn_data/svn18_ext_list.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<properties>
-<target
- path="C:/development/svn_example/svn18_example">
-<property
- name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn16/extra1
--r3 file:///C:/development/svn_example/repos/svn16/extra1 third\ party2
-file:///C:/development/svn_example/repos/svn16/extra1@r1 third_party大介
-</property>
-</target>
-<target
- path="C:/development/svn_example/svn18_example/folder">
-<property
- name="svn:externals">"third party3" file:///C:/development/svn_example/repos/svn18/extra2
--r3 file:///C:/development/svn_example/repos/svn18/extra2 third\ party2
-file:///C:/development/svn_example/repos/svn18/extra2@r1 third_party大介
-</property>
-</target>
-</properties>
diff --git a/setuptools/tests/svn_data/svn18_info.xml b/setuptools/tests/svn_data/svn18_info.xml deleted file mode 100644 index 7ca55995..00000000 --- a/setuptools/tests/svn_data/svn18_info.xml +++ /dev/null @@ -1,136 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?>
-<info>
-<entry
- path="svn18_example"
- revision="6"
- kind="dir">
-<url>file:///C:/development/svn_example/repos/svn18/main</url>
-<relative-url>^/</relative-url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn18/main</root>
-<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:35:57.796875Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn18_example\a file"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn18/main/a%20file</url>
-<relative-url>^/a%20file</relative-url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn18/main</root>
-<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:54.906250Z</text-updated>
-<checksum>43785ab4b1816b49f242990883292813cd4f486c</checksum>
-</wc-info>
-<commit
- revision="3">
-<author>ptt</author>
-<date>2013-07-13T15:35:55.265625Z</date>
-</commit>
-</entry>
-<entry
- kind="file"
- path="svn18_example\to_delete"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn18/main/to_delete</url>
-<relative-url>^/to_delete</relative-url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn18/main</root>
-<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
-<schedule>delete</schedule>
-<depth>infinity</depth>
-<checksum>da39a3ee5e6b4b0d3255bfef95601890afd80709</checksum>
-</wc-info>
-<commit
- revision="6">
-<author>ptt</author>
-<date>2013-07-13T15:35:57.796875Z</date>
-</commit>
-</entry>
-<entry
- kind="dir"
- path="svn18_example\folder"
- revision="6">
-<url>file:///C:/development/svn_example/repos/svn18/main/folder</url>
-<relative-url>^/folder</relative-url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn18/main</root>
-<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-</wc-info>
-<commit
- revision="5">
-<author>ptt</author>
-<date>2013-07-13T15:35:56.750000Z</date>
-</commit>
-</entry>
-<entry
- path="svn18_example\folder\quest.txt"
- revision="6"
- kind="file">
-<url>file:///C:/development/svn_example/repos/svn18/main/folder/quest.txt</url>
-<relative-url>^/folder/quest.txt</relative-url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn18/main</root>
-<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:54.484375Z</text-updated>
-<checksum>bc80eba9e7a10c0a571a4678c520bc9683f3bac2</checksum>
-</wc-info>
-<commit
- revision="2">
-<author>ptt</author>
-<date>2013-07-13T15:35:54.843750Z</date>
-</commit>
-</entry>
-<entry
- path="svn18_example\folder\lalala.txt"
- revision="6"
- kind="file">
-<url>file:///C:/development/svn_example/repos/svn18/main/folder/lalala.txt</url>
-<relative-url>^/folder/lalala.txt</relative-url>
-<repository>
-<root>file:///C:/development/svn_example/repos/svn18/main</root>
-<uuid>3c5e3929-c92b-7045-9ba9-5e65d3dd1ee9</uuid>
-</repository>
-<wc-info>
-<wcroot-abspath>C:/development/svn_example/svn18_example</wcroot-abspath>
-<schedule>normal</schedule>
-<depth>infinity</depth>
-<text-updated>2013-07-13T15:35:54.015625Z</text-updated>
-<checksum>da39a3ee5e6b4b0d3255bfef95601890afd80709</checksum>
-</wc-info>
-<commit
- revision="1">
-<author>ptt</author>
-<date>2013-07-13T15:35:54.375000Z</date>
-</commit>
-</entry>
-</info>
diff --git a/setuptools/tests/test_bdist_egg.py b/setuptools/tests/test_bdist_egg.py index 937e0ed0..f8a68378 100644 --- a/setuptools/tests/test_bdist_egg.py +++ b/setuptools/tests/test_bdist_egg.py @@ -2,53 +2,32 @@ """ import os import re -import shutil -import site -import sys -import tempfile -import unittest import six +import pytest -from distutils.errors import DistutilsError -from setuptools.command.bdist_egg import bdist_egg -from setuptools.command import easy_install as easy_install_pkg from setuptools.dist import Distribution +from . import contexts + SETUP_PY = """\ from setuptools import setup setup(name='foo', py_modules=['hi']) """ -class TestDevelopTest(unittest.TestCase): - - def setUp(self): - self.dir = tempfile.mkdtemp() - self.old_cwd = os.getcwd() - os.chdir(self.dir) - f = open('setup.py', 'w') +@pytest.yield_fixture +def setup_context(tmpdir): + with (tmpdir/'setup.py').open('w') as f: f.write(SETUP_PY) - f.close() - f = open('hi.py', 'w') + with (tmpdir/'hi.py').open('w') as f: f.write('1\n') - f.close() - if sys.version >= "2.6": - self.old_base = site.USER_BASE - site.USER_BASE = tempfile.mkdtemp() - self.old_site = site.USER_SITE - site.USER_SITE = tempfile.mkdtemp() + with tmpdir.as_cwd(): + yield tmpdir - def tearDown(self): - os.chdir(self.old_cwd) - shutil.rmtree(self.dir) - if sys.version >= "2.6": - shutil.rmtree(site.USER_BASE) - shutil.rmtree(site.USER_SITE) - site.USER_BASE = self.old_base - site.USER_SITE = self.old_site - def test_bdist_egg(self): +class Test: + def test_bdist_egg(self, setup_context, user_override): dist = Distribution(dict( script_name='setup.py', script_args=['bdist_egg'], @@ -56,17 +35,10 @@ class TestDevelopTest(unittest.TestCase): py_modules=['hi'] )) os.makedirs(os.path.join('build', 'src')) - old_stdout = sys.stdout - sys.stdout = o = six.StringIO() - try: + with contexts.quiet(): dist.parse_command_line() dist.run_commands() - finally: - sys.stdout = old_stdout # let's see if we got our egg link at the right place [content] = os.listdir('dist') - self.assertTrue(re.match('foo-0.0.0-py[23].\d.egg$', content)) - -def test_suite(): - return unittest.makeSuite(TestDevelopTest) + assert re.match('foo-0.0.0-py[23].\d.egg$', content) diff --git a/setuptools/tests/test_build_ext.py b/setuptools/tests/test_build_ext.py index a92e53ae..0719ba44 100644 --- a/setuptools/tests/test_build_ext.py +++ b/setuptools/tests/test_build_ext.py @@ -1,19 +1,18 @@ -"""build_ext tests -""" -import unittest -from distutils.command.build_ext import build_ext as distutils_build_ext +import distutils.command.build_ext as orig + from setuptools.command.build_ext import build_ext from setuptools.dist import Distribution -class TestBuildExtTest(unittest.TestCase): - +class TestBuildExt: def test_get_ext_filename(self): - # setuptools needs to give back the same - # result than distutils, even if the fullname - # is not in ext_map + """ + Setuptools needs to give back the same + result as distutils, even if the fullname + is not in ext_map. + """ dist = Distribution() cmd = build_ext(dist) cmd.ext_map['foo/bar'] = '' res = cmd.get_ext_filename('foo') - wanted = distutils_build_ext.get_ext_filename(cmd, 'foo') + wanted = orig.build_ext.get_ext_filename(cmd, 'foo') assert res == wanted diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py index 66d182eb..ed1b194a 100644 --- a/setuptools/tests/test_develop.py +++ b/setuptools/tests/test_develop.py @@ -5,9 +5,7 @@ import shutil import site import sys import tempfile -import unittest -from distutils.errors import DistutilsError from setuptools.command.develop import develop from setuptools.dist import Distribution @@ -23,10 +21,10 @@ setup(name='foo', INIT_PY = """print "foo" """ -class TestDevelopTest(unittest.TestCase): +class TestDevelopTest: - def setUp(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix'): + def setup_method(self, method): + if hasattr(sys, 'real_prefix'): return # Directory structure @@ -50,8 +48,8 @@ class TestDevelopTest(unittest.TestCase): self.old_site = site.USER_SITE site.USER_SITE = tempfile.mkdtemp() - def tearDown(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix): + def teardown_method(self, method): + if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix): return os.chdir(self.old_cwd) @@ -62,7 +60,7 @@ class TestDevelopTest(unittest.TestCase): site.USER_SITE = self.old_site def test_develop(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix'): + if hasattr(sys, 'real_prefix'): return dist = Distribution( dict(name='foo', @@ -86,7 +84,7 @@ class TestDevelopTest(unittest.TestCase): # let's see if we got our egg link at the right place content = os.listdir(site.USER_SITE) content.sort() - self.assertEqual(content, ['easy-install.pth', 'foo.egg-link']) + assert content == ['easy-install.pth', 'foo.egg-link'] # Check that we are using the right code. egg_link_file = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt') @@ -100,23 +98,6 @@ class TestDevelopTest(unittest.TestCase): finally: init_file.close() if sys.version < "3": - self.assertEqual(init, 'print "foo"') + assert init == 'print "foo"' else: - self.assertEqual(init, 'print("foo")') - - def notest_develop_with_setup_requires(self): - - wanted = ("Could not find suitable distribution for " - "Requirement.parse('I-DONT-EXIST')") - old_dir = os.getcwd() - os.chdir(self.dir) - try: - try: - Distribution({'setup_requires': ['I_DONT_EXIST']}) - except DistutilsError: - e = sys.exc_info()[1] - error = str(e) - if error == wanted: - pass - finally: - os.chdir(old_dir) + assert init == 'print("foo")' diff --git a/setuptools/tests/test_dist_info.py b/setuptools/tests/test_dist_info.py index a8adb68c..6d0ab587 100644 --- a/setuptools/tests/test_dist_info.py +++ b/setuptools/tests/test_dist_info.py @@ -3,28 +3,20 @@ import os import shutil import tempfile -import unittest -import textwrap -try: - import ast -except: - pass +import pytest import pkg_resources +from .textwrap import DALS -from setuptools.tests.py26compat import skipIf -def DALS(s): - "dedent and left-strip" - return textwrap.dedent(s).lstrip() - -class TestDistInfo(unittest.TestCase): +class TestDistInfo: def test_distinfo(self): - dists = {} - for d in pkg_resources.find_distributions(self.tmpdir): - dists[d.project_name] = d + dists = dict( + (d.project_name, d) + for d in pkg_resources.find_distributions(self.tmpdir) + ) assert len(dists) == 2, dists @@ -34,50 +26,45 @@ class TestDistInfo(unittest.TestCase): assert versioned.version == '2.718' # from filename assert unversioned.version == '0.3' # from METADATA - @skipIf('ast' not in globals(), - "ast is used to test conditional dependencies (Python >= 2.6)") + @pytest.mark.importorskip('ast') def test_conditional_dependencies(self): - requires = [pkg_resources.Requirement.parse('splort==4'), - pkg_resources.Requirement.parse('quux>=1.1')] + specs = 'splort==4', 'quux>=1.1' + requires = list(map(pkg_resources.Requirement.parse, specs)) for d in pkg_resources.find_distributions(self.tmpdir): - self.assertEqual(d.requires(), requires[:1]) - self.assertEqual(d.requires(extras=('baz',)), requires) - self.assertEqual(d.extras, ['baz']) + assert d.requires() == requires[:1] + assert d.requires(extras=('baz',)) == requires + assert d.extras == ['baz'] + + metadata_template = DALS(""" + Metadata-Version: 1.2 + Name: {name} + {version} + Requires-Dist: splort (==4) + Provides-Extra: baz + Requires-Dist: quux (>=1.1); extra == 'baz' + """) - def setUp(self): + def setup_method(self, method): self.tmpdir = tempfile.mkdtemp() - versioned = os.path.join(self.tmpdir, - 'VersionedDistribution-2.718.dist-info') + dist_info_name = 'VersionedDistribution-2.718.dist-info' + versioned = os.path.join(self.tmpdir, dist_info_name) os.mkdir(versioned) - metadata_file = open(os.path.join(versioned, 'METADATA'), 'w+') - try: - metadata_file.write(DALS( - """ - Metadata-Version: 1.2 - Name: VersionedDistribution - Requires-Dist: splort (4) - Provides-Extra: baz - Requires-Dist: quux (>=1.1); extra == 'baz' - """)) - finally: - metadata_file.close() - unversioned = os.path.join(self.tmpdir, - 'UnversionedDistribution.dist-info') + with open(os.path.join(versioned, 'METADATA'), 'w+') as metadata_file: + metadata = self.metadata_template.format( + name='VersionedDistribution', + version='', + ).replace('\n\n', '\n') + metadata_file.write(metadata) + dist_info_name = 'UnversionedDistribution.dist-info' + unversioned = os.path.join(self.tmpdir, dist_info_name) os.mkdir(unversioned) - metadata_file = open(os.path.join(unversioned, 'METADATA'), 'w+') - try: - metadata_file.write(DALS( - """ - Metadata-Version: 1.2 - Name: UnversionedDistribution - Version: 0.3 - Requires-Dist: splort (==4) - Provides-Extra: baz - Requires-Dist: quux (>=1.1); extra == 'baz' - """)) - finally: - metadata_file.close() + with open(os.path.join(unversioned, 'METADATA'), 'w+') as metadata_file: + metadata = self.metadata_template.format( + name='UnversionedDistribution', + version='Version: 0.3', + ) + metadata_file.write(metadata) - def tearDown(self): + def teardown_method(self, method): shutil.rmtree(self.tmpdir) diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py index 8dfe234e..5e83831d 100644 --- a/setuptools/tests/test_easy_install.py +++ b/setuptools/tests/test_easy_install.py @@ -1,21 +1,23 @@ """Easy install Tests """ +from __future__ import absolute_import + import sys import os import shutil import tempfile -import unittest import site import contextlib -import textwrap import tarfile import logging -import distutils.core +import itertools import io -import six from six.moves import urllib +import pytest +import mock +from setuptools import sandbox from setuptools.sandbox import run_setup, SandboxViolation from setuptools.command.easy_install import ( easy_install, fix_jython_executable, get_script_args, nt_quote_arg) @@ -26,7 +28,11 @@ from pkg_resources import working_set, VersionConflict from pkg_resources import Distribution as PRDistribution import setuptools.tests.server import pkg_resources -from .py26compat import skipIf + +from .py26compat import tarfile_open +from . import contexts +from .textwrap import DALS + class FakeDist(object): def get_entry_map(self, group): @@ -37,26 +43,26 @@ class FakeDist(object): def as_requirement(self): return 'spec' -WANTED = """\ -#!%s -# EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name' -__requires__ = 'spec' -import sys -from pkg_resources import load_entry_point +WANTED = DALS(""" + #!%s + # EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name' + __requires__ = 'spec' + import sys + from pkg_resources import load_entry_point -if __name__ == '__main__': - sys.exit( - load_entry_point('spec', 'console_scripts', 'name')() - ) -""" % nt_quote_arg(fix_jython_executable(sys.executable, "")) + if __name__ == '__main__': + sys.exit( + load_entry_point('spec', 'console_scripts', 'name')() + ) + """) % nt_quote_arg(fix_jython_executable(sys.executable, "")) -SETUP_PY = """\ -from setuptools import setup +SETUP_PY = DALS(""" + from setuptools import setup -setup(name='foo') -""" + setup(name='foo') + """) -class TestEasyInstallTest(unittest.TestCase): +class TestEasyInstallTest: def test_install_site_py(self): dist = Distribution() @@ -66,20 +72,17 @@ class TestEasyInstallTest(unittest.TestCase): try: cmd.install_site_py() sitepy = os.path.join(cmd.install_dir, 'site.py') - self.assertTrue(os.path.exists(sitepy)) + assert os.path.exists(sitepy) finally: shutil.rmtree(cmd.install_dir) def test_get_script_args(self): dist = FakeDist() - old_platform = sys.platform - try: - name, script = [i for i in next(get_script_args(dist))][0:2] - finally: - sys.platform = old_platform + args = next(get_script_args(dist)) + name, script = itertools.islice(args, 2) - self.assertEqual(script, WANTED) + assert script == WANTED def test_no_find_links(self): # new option '--no-find-links', that blocks find-links added at @@ -92,7 +95,7 @@ class TestEasyInstallTest(unittest.TestCase): cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok') cmd.args = ['ok'] cmd.ensure_finalized() - self.assertEqual(cmd.package_index.scanned_urls, {}) + assert cmd.package_index.scanned_urls == {} # let's try without it (default behavior) cmd = easy_install(dist) @@ -102,61 +105,44 @@ class TestEasyInstallTest(unittest.TestCase): cmd.args = ['ok'] cmd.ensure_finalized() keys = sorted(cmd.package_index.scanned_urls.keys()) - self.assertEqual(keys, ['link1', 'link2']) + assert keys == ['link1', 'link2'] -class TestPTHFileWriter(unittest.TestCase): +class TestPTHFileWriter: def test_add_from_cwd_site_sets_dirty(self): '''a pth file manager should set dirty if a distribution is in site but also the cwd ''' pth = PthDistributions('does-not_exist', [os.getcwd()]) - self.assertTrue(not pth.dirty) + assert not pth.dirty pth.add(PRDistribution(os.getcwd())) - self.assertTrue(pth.dirty) + assert pth.dirty def test_add_from_site_is_ignored(self): - if os.name != 'nt': - location = '/test/location/does-not-have-to-exist' - else: - location = 'c:\\does_not_exist' + location = '/test/location/does-not-have-to-exist' + # PthDistributions expects all locations to be normalized + location = pkg_resources.normalize_path(location) pth = PthDistributions('does-not_exist', [location, ]) - self.assertTrue(not pth.dirty) + assert not pth.dirty pth.add(PRDistribution(location)) - self.assertTrue(not pth.dirty) - + assert not pth.dirty -class TestUserInstallTest(unittest.TestCase): - def setUp(self): - self.dir = tempfile.mkdtemp() - setup = os.path.join(self.dir, 'setup.py') - f = open(setup, 'w') +@pytest.yield_fixture +def setup_context(tmpdir): + with (tmpdir/'setup.py').open('w') as f: f.write(SETUP_PY) - f.close() - self.old_cwd = os.getcwd() - os.chdir(self.dir) - - self.old_enable_site = site.ENABLE_USER_SITE - self.old_file = easy_install_pkg.__file__ - self.old_base = site.USER_BASE - site.USER_BASE = tempfile.mkdtemp() - self.old_site = site.USER_SITE - site.USER_SITE = tempfile.mkdtemp() - easy_install_pkg.__file__ = site.USER_SITE + with tmpdir.as_cwd(): + yield tmpdir - def tearDown(self): - os.chdir(self.old_cwd) - shutil.rmtree(self.dir) - shutil.rmtree(site.USER_BASE) - shutil.rmtree(site.USER_SITE) - site.USER_BASE = self.old_base - site.USER_SITE = self.old_site - site.ENABLE_USER_SITE = self.old_enable_site - easy_install_pkg.__file__ = self.old_file +@pytest.mark.usefixtures("user_override") +@pytest.mark.usefixtures("setup_context") +class TestUserInstallTest: + @mock.patch('setuptools.command.easy_install.__file__', None) def test_user_install_implied(self): + easy_install_pkg.__file__ = site.USER_SITE site.ENABLE_USER_SITE = True # disabled sometimes #XXX: replace with something meaningfull dist = Distribution() @@ -164,7 +150,7 @@ class TestUserInstallTest(unittest.TestCase): cmd = easy_install(dist) cmd.args = ['py'] cmd.ensure_finalized() - self.assertTrue(cmd.user, 'user should be implied') + assert cmd.user, 'user should be implied' def test_multiproc_atexit(self): try: @@ -185,7 +171,7 @@ class TestUserInstallTest(unittest.TestCase): cmd = easy_install(dist) cmd.args = ['py'] cmd.initialize_options() - self.assertFalse(cmd.user, 'NOT user should be implied') + assert not cmd.user, 'NOT user should be implied' def test_local_index(self): # make sure the local index is used @@ -194,11 +180,8 @@ class TestUserInstallTest(unittest.TestCase): new_location = tempfile.mkdtemp() target = tempfile.mkdtemp() egg_file = os.path.join(new_location, 'foo-1.0.egg-info') - f = open(egg_file, 'w') - try: + with open(egg_file, 'w') as f: f.write('Name: foo\n') - finally: - f.close() sys.path.append(target) old_ppath = os.environ.get('PYTHONPATH') @@ -214,7 +197,7 @@ class TestUserInstallTest(unittest.TestCase): res = cmd.easy_install('foo') actual = os.path.normcase(os.path.realpath(res.location)) expected = os.path.normcase(os.path.realpath(new_location)) - self.assertEqual(actual, expected) + assert actual == expected finally: sys.path.remove(target) for basedir in [new_location, target, ]: @@ -229,6 +212,25 @@ class TestUserInstallTest(unittest.TestCase): else: del os.environ['PYTHONPATH'] + @contextlib.contextmanager + def user_install_setup_context(self, *args, **kwargs): + """ + Wrap sandbox.setup_context to patch easy_install in that context to + appear as user-installed. + """ + with self.orig_context(*args, **kwargs): + import setuptools.command.easy_install as ei + ei.__file__ = site.USER_SITE + yield + + def patched_setup_context(self): + self.orig_context = sandbox.setup_context + + return mock.patch( + 'setuptools.sandbox.setup_context', + self.user_install_setup_context, + ) + def test_setup_requires(self): """Regression test for Distribute issue #318 @@ -237,12 +239,12 @@ class TestUserInstallTest(unittest.TestCase): SandboxViolation. """ - test_pkg = create_setup_requires_package(self.dir) + test_pkg = create_setup_requires_package(os.getcwd()) test_setup_py = os.path.join(test_pkg, 'setup.py') try: - with quiet_context(): - with reset_setup_stop_context(): + with contexts.quiet(): + with self.patched_setup_context(): run_setup(test_setup_py, ['install']) except SandboxViolation: self.fail('Installation caused SandboxViolation') @@ -252,7 +254,24 @@ class TestUserInstallTest(unittest.TestCase): pass -class TestSetupRequires(unittest.TestCase): +@pytest.yield_fixture +def distutils_package(): + distutils_setup_py = SETUP_PY.replace( + 'from setuptools import setup', + 'from distutils.core import setup', + ) + with contexts.tempdir(cd=os.chdir): + with open('setup.py', 'w') as f: + f.write(distutils_setup_py) + yield + + +class TestDistutilsPackage: + def test_bdist_egg_available_on_distutils_pkg(self, distutils_package): + run_setup('setup.py', ['bdist_egg']) + + +class TestSetupRequires: def test_setup_requires_honors_fetch_params(self): """ @@ -269,25 +288,27 @@ class TestSetupRequires(unittest.TestCase): # Some platforms (Jython) don't find a port to which to bind, # so skip this test for them. return - with quiet_context(): + with contexts.quiet(): # create an sdist that has a build-time dependency. with TestSetupRequires.create_sdist() as dist_file: - with tempdir_context() as temp_install_dir: - with environment_context(PYTHONPATH=temp_install_dir): - ei_params = ['--index-url', p_index.url, + with contexts.tempdir() as temp_install_dir: + with contexts.environment(PYTHONPATH=temp_install_dir): + ei_params = [ + '--index-url', p_index.url, '--allow-hosts', p_index_loc, - '--exclude-scripts', '--install-dir', temp_install_dir, - dist_file] - with reset_setup_stop_context(): - with argv_context(['easy_install']): - # attempt to install the dist. It should fail because - # it doesn't exist. - self.assertRaises(SystemExit, - easy_install_pkg.main, ei_params) + '--exclude-scripts', + '--install-dir', temp_install_dir, + dist_file, + ] + with contexts.argv(['easy_install']): + # attempt to install the dist. It should fail because + # it doesn't exist. + with pytest.raises(SystemExit): + easy_install_pkg.main(ei_params) # there should have been two or three requests to the server # (three happens on Python 3.3a) - self.assertTrue(2 <= len(p_index.requests) <= 3) - self.assertEqual(p_index.requests[0].path, '/does-not-exist/') + assert 2 <= len(p_index.requests) <= 3 + assert p_index.requests[0].path == '/does-not-exist/' @staticmethod @contextlib.contextmanager @@ -296,18 +317,17 @@ class TestSetupRequires(unittest.TestCase): Return an sdist with a setup_requires dependency (of something that doesn't exist) """ - with tempdir_context() as dir: + with contexts.tempdir() as dir: dist_path = os.path.join(dir, 'setuptools-test-fetcher-1.0.tar.gz') - make_trivial_sdist( - dist_path, - textwrap.dedent(""" - import setuptools - setuptools.setup( - name="setuptools-test-fetcher", - version="1.0", - setup_requires = ['does-not-exist'], - ) - """).lstrip()) + script = DALS(""" + import setuptools + setuptools.setup( + name="setuptools-test-fetcher", + version="1.0", + setup_requires = ['does-not-exist'], + ) + """) + make_trivial_sdist(dist_path, script) yield dist_path def test_setup_requires_overrides_version_conflict(self): @@ -325,22 +345,21 @@ class TestSetupRequires(unittest.TestCase): working_set.add(fake_dist) try: - with tempdir_context() as temp_dir: + with contexts.tempdir() as temp_dir: test_pkg = create_setup_requires_package(temp_dir) test_setup_py = os.path.join(test_pkg, 'setup.py') - with quiet_context() as (stdout, stderr): - with reset_setup_stop_context(): - try: - # Don't even need to install the package, just - # running the setup.py at all is sufficient - run_setup(test_setup_py, ['--name']) - except VersionConflict: - self.fail('Installing setup.py requirements ' - 'caused a VersionConflict') + with contexts.quiet() as (stdout, stderr): + try: + # Don't even need to install the package, just + # running the setup.py at all is sufficient + run_setup(test_setup_py, ['--name']) + except VersionConflict: + self.fail('Installing setup.py requirements ' + 'caused a VersionConflict') lines = stdout.readlines() - self.assertTrue(len(lines) > 0) - self.assertTrue(lines[-1].strip(), 'test_pkg') + assert len(lines) > 0 + assert lines[-1].strip(), 'test_pkg' finally: pkg_resources.__setstate__(pr_state) @@ -361,17 +380,16 @@ def create_setup_requires_package(path): test_setup_py = os.path.join(test_pkg, 'setup.py') os.mkdir(test_pkg) - f = open(test_setup_py, 'w') - f.write(textwrap.dedent("""\ - import setuptools - setuptools.setup(**%r) - """ % test_setup_attrs)) - f.close() + with open(test_setup_py, 'w') as f: + f.write(DALS(""" + import setuptools + setuptools.setup(**%r) + """ % test_setup_attrs)) foobar_path = os.path.join(path, 'foobar-0.1.tar.gz') make_trivial_sdist( foobar_path, - textwrap.dedent("""\ + DALS(""" import setuptools setuptools.setup( name='foobar', @@ -390,71 +408,5 @@ def make_trivial_sdist(dist_path, setup_py): setup_py_file = tarfile.TarInfo(name='setup.py') setup_py_bytes = io.BytesIO(setup_py.encode('utf-8')) setup_py_file.size = len(setup_py_bytes.getvalue()) - dist = tarfile.open(dist_path, 'w:gz') - try: + with tarfile_open(dist_path, 'w:gz') as dist: dist.addfile(setup_py_file, fileobj=setup_py_bytes) - finally: - dist.close() - - -@contextlib.contextmanager -def tempdir_context(cd=lambda dir:None): - temp_dir = tempfile.mkdtemp() - orig_dir = os.getcwd() - try: - cd(temp_dir) - yield temp_dir - finally: - cd(orig_dir) - shutil.rmtree(temp_dir) - -@contextlib.contextmanager -def environment_context(**updates): - old_env = os.environ.copy() - os.environ.update(updates) - try: - yield - finally: - for key in updates: - del os.environ[key] - os.environ.update(old_env) - -@contextlib.contextmanager -def argv_context(repl): - old_argv = sys.argv[:] - sys.argv[:] = repl - yield - sys.argv[:] = old_argv - -@contextlib.contextmanager -def reset_setup_stop_context(): - """ - When the setuptools tests are run using setup.py test, and then - one wants to invoke another setup() command (such as easy_install) - within those tests, it's necessary to reset the global variable - in distutils.core so that the setup() command will run naturally. - """ - setup_stop_after = distutils.core._setup_stop_after - distutils.core._setup_stop_after = None - yield - distutils.core._setup_stop_after = setup_stop_after - - -@contextlib.contextmanager -def quiet_context(): - """ - Redirect stdout/stderr to StringIO objects to prevent console output from - distutils commands. - """ - - old_stdout = sys.stdout - old_stderr = sys.stderr - new_stdout = sys.stdout = six.StringIO() - new_stderr = sys.stderr = six.StringIO() - try: - yield new_stdout, new_stderr - finally: - new_stdout.seek(0) - new_stderr.seek(0) - sys.stdout = old_stdout - sys.stderr = old_stderr diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index e803a41e..a1caf9fd 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -1,210 +1,98 @@ - import os -import sys -import tempfile -import shutil -import unittest - -import pkg_resources -import warnings -from setuptools.command import egg_info -from setuptools import svn_utils -from setuptools.tests import environment, test_svn -from setuptools.tests.py26compat import skipIf - -ENTRIES_V10 = pkg_resources.resource_string(__name__, 'entries-v10') -"An entries file generated with svn 1.6.17 against the legacy Setuptools repo" - - -class TestEggInfo(unittest.TestCase): - - def setUp(self): - self.test_dir = tempfile.mkdtemp() - os.mkdir(os.path.join(self.test_dir, '.svn')) - - self.old_cwd = os.getcwd() - os.chdir(self.test_dir) - - def tearDown(self): - os.chdir(self.old_cwd) - shutil.rmtree(self.test_dir) - - def _write_entries(self, entries): - fn = os.path.join(self.test_dir, '.svn', 'entries') - entries_f = open(fn, 'wb') - entries_f.write(entries) - entries_f.close() - - @skipIf(not test_svn._svn_check, "No SVN to text, in the first place") - def test_version_10_format(self): - """ - """ - #keeping this set for 1.6 is a good check on the get_svn_revision - #to ensure I return using svnversion what would had been returned - version_str = svn_utils.SvnInfo.get_svn_version() - version = [int(x) for x in version_str.split('.')[:2]] - if version != [1, 6]: - if hasattr(self, 'skipTest'): - self.skipTest('') - else: - sys.stderr.write('\n Skipping due to SVN Version\n') - return - - self._write_entries(ENTRIES_V10) - rev = egg_info.egg_info.get_svn_revision() - self.assertEqual(rev, '89000') - - def test_version_10_format_legacy_parser(self): - """ - """ - path_variable = None - for env in os.environ: - if env.lower() == 'path': - path_variable = env - - if path_variable: - old_path = os.environ[path_variable] - os.environ[path_variable] = '' - #catch_warnings not available until py26 - warning_filters = warnings.filters - warnings.filters = warning_filters[:] - try: - warnings.simplefilter("ignore", DeprecationWarning) - self._write_entries(ENTRIES_V10) - rev = egg_info.egg_info.get_svn_revision() - finally: - #restore the warning filters - warnings.filters = warning_filters - #restore the os path - if path_variable: - os.environ[path_variable] = old_path - - self.assertEqual(rev, '89000') - -DUMMY_SOURCE_TXT = """CHANGES.txt -CONTRIBUTORS.txt -HISTORY.txt -LICENSE -MANIFEST.in -README.txt -setup.py -dummy/__init__.py -dummy/test.txt -dummy.egg-info/PKG-INFO -dummy.egg-info/SOURCES.txt -dummy.egg-info/dependency_links.txt -dummy.egg-info/top_level.txt""" - - -class TestSvnDummy(environment.ZippedEnvironment): - - def setUp(self): - version = svn_utils.SvnInfo.get_svn_version() - if not version: # None or Empty - return None - - self.base_version = tuple([int(x) for x in version.split('.')][:2]) - - if not self.base_version: - raise ValueError('No SVN tools installed') - elif self.base_version < (1, 3): - raise ValueError('Insufficient SVN Version %s' % version) - elif self.base_version >= (1, 9): - #trying the latest version - self.base_version = (1, 8) - - self.dataname = "dummy%i%i" % self.base_version - self.datafile = os.path.join('setuptools', 'tests', - 'svn_data', self.dataname + ".zip") - super(TestSvnDummy, self).setUp() - - @skipIf(not test_svn._svn_check, "No SVN to text, in the first place") - def test_sources(self): - code, data = environment.run_setup_py(["sdist"], - pypath=self.old_cwd, - data_stream=1) +import stat + +import pytest + +from . import environment +from .textwrap import DALS +from . import contexts + + +class TestEggInfo: + + setup_script = DALS(""" + from setuptools import setup + + setup( + name='foo', + py_modules=['hello'], + entry_points={'console_scripts': ['hi = hello.run']}, + zip_safe=False, + ) + """) + + def _create_project(self): + with open('setup.py', 'w') as f: + f.write(self.setup_script) + + with open('hello.py', 'w') as f: + f.write(DALS(""" + def run(): + print('hello') + """)) + + @pytest.yield_fixture + def env(self): + class Environment(str): pass + + with contexts.tempdir(prefix='setuptools-test.') as env_dir: + env = Environment(env_dir) + os.chmod(env_dir, stat.S_IRWXU) + subs = 'home', 'lib', 'scripts', 'data', 'egg-base' + env.paths = dict( + (dirname, os.path.join(env_dir, dirname)) + for dirname in subs + ) + list(map(os.mkdir, env.paths.values())) + config = os.path.join(env.paths['home'], '.pydistutils.cfg') + with open(config, 'w') as f: + f.write(DALS(""" + [egg_info] + egg-base = %(egg-base)s + """ % env.paths + )) + yield env + + def test_egg_base_installed_egg_info(self, tmpdir_cwd, env): + self._create_project() + + environ = os.environ.copy().update( + HOME=env.paths['home'], + ) + cmd = [ + 'install', + '--home', env.paths['home'], + '--install-lib', env.paths['lib'], + '--install-scripts', env.paths['scripts'], + '--install-data', env.paths['data'], + ] + code, data = environment.run_setup_py( + cmd=cmd, + pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]), + data_stream=1, + env=environ, + ) if code: raise AssertionError(data) - sources = os.path.join('dummy.egg-info', 'SOURCES.txt') - infile = open(sources, 'r') - try: - read_contents = infile.read() - finally: - infile.close() - del infile - - self.assertEqual(DUMMY_SOURCE_TXT, read_contents) - - return data - - @skipIf(not test_svn._svn_check, "No SVN to text, in the first place") - def test_svn_tags(self): - code, data = environment.run_setup_py(["egg_info", - "--tag-svn-revision"], - pypath=self.old_cwd, - data_stream=1) - if code: - raise AssertionError(data) - - pkginfo = os.path.join('dummy.egg-info', 'PKG-INFO') - infile = open(pkginfo, 'r') - try: - read_contents = infile.readlines() - finally: - infile.close() - del infile - - self.assertTrue("Version: 0.1.1-r1\n" in read_contents) - - @skipIf(not test_svn._svn_check, "No SVN to text, in the first place") - def test_no_tags(self): - code, data = environment.run_setup_py(["egg_info"], - pypath=self.old_cwd, - data_stream=1) - if code: - raise AssertionError(data) - - pkginfo = os.path.join('dummy.egg-info', 'PKG-INFO') - infile = open(pkginfo, 'r') - try: - read_contents = infile.readlines() - finally: - infile.close() - del infile - - self.assertTrue("Version: 0.1.1\n" in read_contents) - - -class TestSvnDummyLegacy(environment.ZippedEnvironment): - - def setUp(self): - self.base_version = (1, 6) - self.dataname = "dummy%i%i" % self.base_version - self.datafile = os.path.join('setuptools', 'tests', - 'svn_data', self.dataname + ".zip") - super(TestSvnDummyLegacy, self).setUp() - - def test_sources(self): - code, data = environment.run_setup_py(["sdist"], - pypath=self.old_cwd, - path="", - data_stream=1) - if code: - raise AssertionError(data) - - sources = os.path.join('dummy.egg-info', 'SOURCES.txt') - infile = open(sources, 'r') - try: - read_contents = infile.read() - finally: - infile.close() - del infile - - self.assertEqual(DUMMY_SOURCE_TXT, read_contents) - - return data - - -def test_suite(): - return unittest.defaultTestLoader.loadTestsFromName(__name__) + actual = self._find_egg_info_files(env.paths['lib']) + + expected = [ + 'PKG-INFO', + 'SOURCES.txt', + 'dependency_links.txt', + 'entry_points.txt', + 'not-zip-safe', + 'top_level.txt', + ] + assert sorted(actual) == expected + + def _find_egg_info_files(self, root): + results = ( + filenames + for dirpath, dirnames, filenames in os.walk(root) + if os.path.basename(dirpath) == 'EGG-INFO' + ) + # expect exactly one result + result, = results + return result diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py index fe390728..06a7c02e 100644 --- a/setuptools/tests/test_find_packages.py +++ b/setuptools/tests/test_find_packages.py @@ -3,12 +3,12 @@ import os import sys import shutil import tempfile -import unittest import platform +import pytest + import setuptools from setuptools import find_packages -from setuptools.tests.py26compat import skipIf find_420_packages = setuptools.PEP420PackageFinder.find @@ -33,13 +33,13 @@ def has_symlink(): ) return can_symlink() and not bad_symlink -class TestFindPackages(unittest.TestCase): +class TestFindPackages: - def setUp(self): + def setup_method(self, method): self.dist_dir = tempfile.mkdtemp() self._make_pkg_structure() - def tearDown(self): + def teardown_method(self, method): shutil.rmtree(self.dist_dir) def _make_pkg_structure(self): @@ -87,7 +87,7 @@ class TestFindPackages(unittest.TestCase): def test_regular_package(self): self._touch('__init__.py', self.pkg_dir) packages = find_packages(self.dist_dir) - self.assertEqual(packages, ['pkg', 'pkg.subpkg']) + assert packages == ['pkg', 'pkg.subpkg'] def test_exclude(self): self._touch('__init__.py', self.pkg_dir) @@ -102,7 +102,7 @@ class TestFindPackages(unittest.TestCase): alt_dir = self._mkdir('other_pkg', self.dist_dir) self._touch('__init__.py', alt_dir) packages = find_packages(self.dist_dir, include=['other_pkg']) - self.assertEqual(packages, ['other_pkg']) + assert packages == ['other_pkg'] def test_dir_with_dot_is_skipped(self): shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets')) @@ -110,7 +110,7 @@ class TestFindPackages(unittest.TestCase): self._touch('__init__.py', data_dir) self._touch('file.dat', data_dir) packages = find_packages(self.dist_dir) - self.assertTrue('pkg.some.data' not in packages) + assert 'pkg.some.data' not in packages def test_dir_with_packages_in_subdir_is_excluded(self): """ @@ -121,9 +121,9 @@ class TestFindPackages(unittest.TestCase): build_pkg_dir = self._mkdir('pkg', build_dir) self._touch('__init__.py', build_pkg_dir) packages = find_packages(self.dist_dir) - self.assertTrue('build.pkg' not in packages) + assert 'build.pkg' not in packages - @skipIf(not has_symlink(), 'Symlink support required') + @pytest.mark.skipif(not has_symlink(), reason='Symlink support required') def test_symlinked_packages_are_included(self): """ A symbolically-linked directory should be treated like any other @@ -136,10 +136,10 @@ class TestFindPackages(unittest.TestCase): os.symlink('pkg', linked_pkg) assert os.path.isdir(linked_pkg) packages = find_packages(self.dist_dir) - self.assertTrue('lpkg' in packages) + assert 'lpkg' in packages def _assert_packages(self, actual, expected): - self.assertEqual(set(actual), set(expected)) + assert set(actual) == set(expected) def test_pep420_ns_package(self): packages = find_420_packages( diff --git a/setuptools/tests/test_integration.py b/setuptools/tests/test_integration.py index 8d6c1e55..3a6abeaa 100644 --- a/setuptools/tests/test_integration.py +++ b/setuptools/tests/test_integration.py @@ -27,7 +27,7 @@ def install_context(request, tmpdir, monkeypatch): def fin(): # undo the monkeypatch, particularly needed under # windows because of kept handle on cwd - monkeypatch.undo() + monkeypatch.undo() new_cwd.remove() user_base.remove() user_site.remove() @@ -71,7 +71,6 @@ def test_virtualenvwrapper(install_context): 'virtualenvwrapper', 'hook_loader.py') -@pytest.mark.xfail def test_pbr(install_context): _install_one('pbr', install_context, 'pbr', 'core.py') diff --git a/setuptools/tests/test_markerlib.py b/setuptools/tests/test_markerlib.py index dae71cba..8197b49d 100644 --- a/setuptools/tests/test_markerlib.py +++ b/setuptools/tests/test_markerlib.py @@ -1,48 +1,43 @@ import os -import unittest -from setuptools.tests.py26compat import skipIf -try: - import ast -except ImportError: - pass +import pytest -class TestMarkerlib(unittest.TestCase): - @skipIf('ast' not in globals(), - "ast not available (Python < 2.6?)") +class TestMarkerlib: + + @pytest.mark.importorskip('ast') def test_markers(self): from _markerlib import interpret, default_environment, compile - + os_name = os.name - - self.assertTrue(interpret("")) - - self.assertTrue(interpret("os.name != 'buuuu'")) - self.assertTrue(interpret("os_name != 'buuuu'")) - self.assertTrue(interpret("python_version > '1.0'")) - self.assertTrue(interpret("python_version < '5.0'")) - self.assertTrue(interpret("python_version <= '5.0'")) - self.assertTrue(interpret("python_version >= '1.0'")) - self.assertTrue(interpret("'%s' in os.name" % os_name)) - self.assertTrue(interpret("'%s' in os_name" % os_name)) - self.assertTrue(interpret("'buuuu' not in os.name")) - - self.assertFalse(interpret("os.name == 'buuuu'")) - self.assertFalse(interpret("os_name == 'buuuu'")) - self.assertFalse(interpret("python_version < '1.0'")) - self.assertFalse(interpret("python_version > '5.0'")) - self.assertFalse(interpret("python_version >= '5.0'")) - self.assertFalse(interpret("python_version <= '1.0'")) - self.assertFalse(interpret("'%s' not in os.name" % os_name)) - self.assertFalse(interpret("'buuuu' in os.name and python_version >= '5.0'")) - self.assertFalse(interpret("'buuuu' in os_name and python_version >= '5.0'")) - + + assert interpret("") + + assert interpret("os.name != 'buuuu'") + assert interpret("os_name != 'buuuu'") + assert interpret("python_version > '1.0'") + assert interpret("python_version < '5.0'") + assert interpret("python_version <= '5.0'") + assert interpret("python_version >= '1.0'") + assert interpret("'%s' in os.name" % os_name) + assert interpret("'%s' in os_name" % os_name) + assert interpret("'buuuu' not in os.name") + + assert not interpret("os.name == 'buuuu'") + assert not interpret("os_name == 'buuuu'") + assert not interpret("python_version < '1.0'") + assert not interpret("python_version > '5.0'") + assert not interpret("python_version >= '5.0'") + assert not interpret("python_version <= '1.0'") + assert not interpret("'%s' not in os.name" % os_name) + assert not interpret("'buuuu' in os.name and python_version >= '5.0'") + assert not interpret("'buuuu' in os_name and python_version >= '5.0'") + environment = default_environment() environment['extra'] = 'test' - self.assertTrue(interpret("extra == 'test'", environment)) - self.assertFalse(interpret("extra == 'doc'", environment)) - + assert interpret("extra == 'test'", environment) + assert not interpret("extra == 'doc'", environment) + def raises_nameError(): try: interpret("python.version == '42'") @@ -50,9 +45,9 @@ class TestMarkerlib(unittest.TestCase): pass else: raise Exception("Expected NameError") - + raises_nameError() - + def raises_syntaxError(): try: interpret("(x for x in (4,))") @@ -60,9 +55,9 @@ class TestMarkerlib(unittest.TestCase): pass else: raise Exception("Expected SyntaxError") - + raises_syntaxError() - + statement = "python_version == '5'" - self.assertEqual(compile(statement).__doc__, statement) - + assert compile(statement).__doc__ == statement + diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py index 970f7679..a0820fff 100644 --- a/setuptools/tests/test_msvc9compiler.py +++ b/setuptools/tests/test_msvc9compiler.py @@ -1,157 +1,173 @@ -"""msvc9compiler monkey patch test - -This test ensures that importing setuptools is sufficient to replace -the standard find_vcvarsall function with our patched version that -finds the Visual C++ for Python package. +""" +Tests for msvc9compiler. """ import os -import shutil -import sys -import tempfile -import unittest -import distutils.errors import contextlib +import distutils.errors -# importing only setuptools should apply the patch -__import__('setuptools') - -class MockReg: - """Mock for distutils.msvc9compiler.Reg. We patch it - with an instance of this class that mocks out the - functions that access the registry. - """ - - def __init__(self, hkey_local_machine={}, hkey_current_user={}): - self.hklm = hkey_local_machine - self.hkcu = hkey_current_user +import pytest +import mock - def __enter__(self): - self.original_read_keys = distutils.msvc9compiler.Reg.read_keys - self.original_read_values = distutils.msvc9compiler.Reg.read_values +from . import contexts - _winreg = getattr(distutils.msvc9compiler, '_winreg', None) - winreg = getattr(distutils.msvc9compiler, 'winreg', _winreg) +# importing only setuptools should apply the patch +__import__('setuptools') - hives = { - winreg.HKEY_CURRENT_USER: self.hkcu, - winreg.HKEY_LOCAL_MACHINE: self.hklm, - } +pytest.importorskip("distutils.msvc9compiler") - def read_keys(cls, base, key): - """Return list of registry keys.""" - hive = hives.get(base, {}) - return [k.rpartition('\\')[2] - for k in hive if k.startswith(key.lower())] - def read_values(cls, base, key): - """Return dict of registry keys and values.""" - hive = hives.get(base, {}) - return dict((k.rpartition('\\')[2], hive[k]) - for k in hive if k.startswith(key.lower())) +def mock_reg(hkcu=None, hklm=None): + """ + Return a mock for distutils.msvc9compiler.Reg, patched + to mock out the functions that access the registry. + """ - distutils.msvc9compiler.Reg.read_keys = classmethod(read_keys) - distutils.msvc9compiler.Reg.read_values = classmethod(read_values) + _winreg = getattr(distutils.msvc9compiler, '_winreg', None) + winreg = getattr(distutils.msvc9compiler, 'winreg', _winreg) + + hives = { + winreg.HKEY_CURRENT_USER: hkcu or {}, + winreg.HKEY_LOCAL_MACHINE: hklm or {}, + } + + @classmethod + def read_keys(cls, base, key): + """Return list of registry keys.""" + hive = hives.get(base, {}) + return [ + k.rpartition('\\')[2] + for k in hive if k.startswith(key.lower()) + ] + + @classmethod + def read_values(cls, base, key): + """Return dict of registry keys and values.""" + hive = hives.get(base, {}) + return dict( + (k.rpartition('\\')[2], hive[k]) + for k in hive if k.startswith(key.lower()) + ) - return self + return mock.patch.multiple(distutils.msvc9compiler.Reg, + read_keys=read_keys, read_values=read_values) - def __exit__(self, exc_type, exc_value, exc_tb): - distutils.msvc9compiler.Reg.read_keys = self.original_read_keys - distutils.msvc9compiler.Reg.read_values = self.original_read_values -@contextlib.contextmanager -def patch_env(**replacements): +class TestModulePatch: """ - In a context, patch the environment with replacements. Pass None values - to clear the values. + Ensure that importing setuptools is sufficient to replace + the standard find_vcvarsall function with a version that + recognizes the "Visual C++ for Python" package. """ - saved = dict( - (key, os.environ['key']) - for key in replacements - if key in os.environ - ) - - # remove values that are null - remove = (key for (key, value) in replacements.items() if value is None) - for key in list(remove): - os.environ.pop(key, None) - replacements.pop(key) - - os.environ.update(replacements) - - try: - yield saved - finally: - for key in replacements: - os.environ.pop(key, None) - os.environ.update(saved) - -class TestMSVC9Compiler(unittest.TestCase): - - def test_find_vcvarsall_patch(self): - if not hasattr(distutils, 'msvc9compiler'): - # skip - return - - self.assertEqual( - "setuptools.msvc9_support", - distutils.msvc9compiler.find_vcvarsall.__module__, - "find_vcvarsall was not patched" - ) + key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir' + key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir' + + def test_patched(self): + "Test the module is actually patched" + mod_name = distutils.msvc9compiler.find_vcvarsall.__module__ + assert mod_name == "setuptools.msvc9_support", "find_vcvarsall unpatched" + + def test_no_registry_entryies_means_nothing_found(self): + """ + No registry entries or environment variable should lead to an error + directing the user to download vcpython27. + """ find_vcvarsall = distutils.msvc9compiler.find_vcvarsall query_vcvarsall = distutils.msvc9compiler.query_vcvarsall - # No registry entries or environment variable means we should - # not find anything - with patch_env(VS90COMNTOOLS=None): - with MockReg(): - self.assertIsNone(find_vcvarsall(9.0)) + with contexts.environment(VS90COMNTOOLS=None): + with mock_reg(): + assert find_vcvarsall(9.0) is None - try: + expected = distutils.errors.DistutilsPlatformError + with pytest.raises(expected) as exc: query_vcvarsall(9.0) - self.fail('Expected DistutilsPlatformError from query_vcvarsall()') - except distutils.errors.DistutilsPlatformError: - exc_message = str(sys.exc_info()[1]) - self.assertIn('aka.ms/vcpython27', exc_message) - - key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir' - key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir' - - # Make two mock files so we can tell whether HCKU entries are - # preferred to HKLM entries. - mock_installdir_1 = tempfile.mkdtemp() - mock_vcvarsall_bat_1 = os.path.join(mock_installdir_1, 'vcvarsall.bat') - open(mock_vcvarsall_bat_1, 'w').close() - mock_installdir_2 = tempfile.mkdtemp() - mock_vcvarsall_bat_2 = os.path.join(mock_installdir_2, 'vcvarsall.bat') - open(mock_vcvarsall_bat_2, 'w').close() - try: - # Ensure we get the current user's setting first - with MockReg( - hkey_current_user={key_32: mock_installdir_1}, - hkey_local_machine={ - key_32: mock_installdir_2, - key_64: mock_installdir_2, - } - ): - self.assertEqual(mock_vcvarsall_bat_1, find_vcvarsall(9.0)) - - # Ensure we get the local machine value if it's there - with MockReg(hkey_local_machine={key_32: mock_installdir_2}): - self.assertEqual(mock_vcvarsall_bat_2, find_vcvarsall(9.0)) - - # Ensure we prefer the 64-bit local machine key - # (*not* the Wow6432Node key) - with MockReg( - hkey_local_machine={ - # This *should* only exist on 32-bit machines - key_32: mock_installdir_1, - # This *should* only exist on 64-bit machines - key_64: mock_installdir_2, - } - ): - self.assertEqual(mock_vcvarsall_bat_1, find_vcvarsall(9.0)) - finally: - shutil.rmtree(mock_installdir_1) - shutil.rmtree(mock_installdir_2) + assert 'aka.ms/vcpython27' in str(exc) + + @pytest.yield_fixture + def user_preferred_setting(self): + """ + Set up environment with different install dirs for user vs. system + and yield the user_install_dir for the expected result. + """ + with self.mock_install_dir() as user_install_dir: + with self.mock_install_dir() as system_install_dir: + reg = mock_reg( + hkcu={ + self.key_32: user_install_dir, + }, + hklm={ + self.key_32: system_install_dir, + self.key_64: system_install_dir, + }, + ) + with reg: + yield user_install_dir + + def test_prefer_current_user(self, user_preferred_setting): + """ + Ensure user's settings are preferred. + """ + result = distutils.msvc9compiler.find_vcvarsall(9.0) + assert user_preferred_setting == result + + @pytest.yield_fixture + def local_machine_setting(self): + """ + Set up environment with only the system environment configured. + """ + with self.mock_install_dir() as system_install_dir: + reg = mock_reg( + hklm={ + self.key_32: system_install_dir, + }, + ) + with reg: + yield system_install_dir + + def test_local_machine_recognized(self, local_machine_setting): + """ + Ensure machine setting is honored if user settings are not present. + """ + result = distutils.msvc9compiler.find_vcvarsall(9.0) + assert local_machine_setting == result + + @pytest.yield_fixture + def x64_preferred_setting(self): + """ + Set up environment with 64-bit and 32-bit system settings configured + and yield the 64-bit location. + """ + with self.mock_install_dir() as x32_dir: + with self.mock_install_dir() as x64_dir: + reg = mock_reg( + hklm={ + # This *should* only exist on 32-bit machines + self.key_32: x32_dir, + # This *should* only exist on 64-bit machines + self.key_64: x64_dir, + }, + ) + with reg: + yield x64_dir + + def test_ensure_64_bit_preferred(self, x64_preferred_setting): + """ + Ensure 64-bit system key is preferred. + """ + result = distutils.msvc9compiler.find_vcvarsall(9.0) + assert x64_preferred_setting == result + + @staticmethod + @contextlib.contextmanager + def mock_install_dir(): + """ + Make a mock install dir in a unique location so that tests can + distinguish which dir was detected in a given scenario. + """ + with contexts.tempdir() as result: + vcvarsall = os.path.join(result, 'vcvarsall.bat') + with open(vcvarsall, 'w'): + pass + yield diff --git a/setuptools/tests/test_packageindex.py b/setuptools/tests/test_packageindex.py index 40ae0af3..4eb98bb1 100644 --- a/setuptools/tests/test_packageindex.py +++ b/setuptools/tests/test_packageindex.py @@ -1,8 +1,4 @@ -"""Package Index Tests -""" import sys -import os -import unittest import distutils.errors import six @@ -12,7 +8,8 @@ import pkg_resources import setuptools.package_index from setuptools.tests.server import IndexServer -class TestPackageIndex(unittest.TestCase): + +class TestPackageIndex: def test_bad_url_bad_port(self): index = setuptools.package_index.PackageIndex() @@ -21,9 +18,9 @@ class TestPackageIndex(unittest.TestCase): v = index.open_url(url) except Exception: v = sys.exc_info()[1] - self.assertTrue(url in str(v)) + assert url in str(v) else: - self.assertTrue(isinstance(v, urllib.error.HTTPError)) + assert isinstance(v, urllib.error.HTTPError) def test_bad_url_typo(self): # issue 16 @@ -38,9 +35,9 @@ class TestPackageIndex(unittest.TestCase): v = index.open_url(url) except Exception: v = sys.exc_info()[1] - self.assertTrue(url in str(v)) + assert url in str(v) else: - self.assertTrue(isinstance(v, urllib.error.HTTPError)) + assert isinstance(v, urllib.error.HTTPError) def test_bad_url_bad_status_line(self): index = setuptools.package_index.PackageIndex( @@ -56,7 +53,7 @@ class TestPackageIndex(unittest.TestCase): v = index.open_url(url) except Exception: v = sys.exc_info()[1] - self.assertTrue('line' in str(v)) + assert 'line' in str(v) else: raise AssertionError('Should have raise here!') @@ -97,7 +94,7 @@ class TestPackageIndex(unittest.TestCase): hosts=('www.example.com',) ) url = 'file:///tmp/test_package_index' - self.assertTrue(index.url_ok(url, True)) + assert index.url_ok(url, True) def test_links_priority(self): """ @@ -130,21 +127,30 @@ class TestPackageIndex(unittest.TestCase): server.stop() # the distribution has been found - self.assertTrue('foobar' in pi) + assert 'foobar' in pi # we have only one link, because links are compared without md5 - self.assertTrue(len(pi['foobar'])==1) + assert len(pi['foobar'])==1 # the link should be from the index - self.assertTrue('correct_md5' in pi['foobar'][0].location) + assert 'correct_md5' in pi['foobar'][0].location def test_parse_bdist_wininst(self): - self.assertEqual(setuptools.package_index.parse_bdist_wininst( - 'reportlab-2.5.win32-py2.4.exe'), ('reportlab-2.5', '2.4', 'win32')) - self.assertEqual(setuptools.package_index.parse_bdist_wininst( - 'reportlab-2.5.win32.exe'), ('reportlab-2.5', None, 'win32')) - self.assertEqual(setuptools.package_index.parse_bdist_wininst( - 'reportlab-2.5.win-amd64-py2.7.exe'), ('reportlab-2.5', '2.7', 'win-amd64')) - self.assertEqual(setuptools.package_index.parse_bdist_wininst( - 'reportlab-2.5.win-amd64.exe'), ('reportlab-2.5', None, 'win-amd64')) + parse = setuptools.package_index.parse_bdist_wininst + + actual = parse('reportlab-2.5.win32-py2.4.exe') + expected = 'reportlab-2.5', '2.4', 'win32' + assert actual == expected + + actual = parse('reportlab-2.5.win32.exe') + expected = 'reportlab-2.5', None, 'win32' + assert actual == expected + + actual = parse('reportlab-2.5.win-amd64-py2.7.exe') + expected = 'reportlab-2.5', '2.7', 'win-amd64' + assert actual == expected + + actual = parse('reportlab-2.5.win-amd64.exe') + expected = 'reportlab-2.5', None, 'win-amd64' + assert actual == expected def test__vcs_split_rev_from_url(self): """ @@ -152,55 +158,51 @@ class TestPackageIndex(unittest.TestCase): """ vsrfu = setuptools.package_index.PackageIndex._vcs_split_rev_from_url url, rev = vsrfu('https://example.com/bar@2995') - self.assertEqual(url, 'https://example.com/bar') - self.assertEqual(rev, '2995') + assert url == 'https://example.com/bar' + assert rev == '2995' - def test_local_index(self): + def test_local_index(self, tmpdir): """ local_open should be able to read an index from the file system. """ - f = open('index.html', 'w') - f.write('<div>content</div>') - f.close() - try: - url = 'file:' + urllib.request.pathname2url(os.getcwd()) + '/' - res = setuptools.package_index.local_open(url) - finally: - os.remove('index.html') + index_file = tmpdir / 'index.html' + with index_file.open('w') as f: + f.write('<div>content</div>') + url = 'file:' + urllib.request.pathname2url(str(tmpdir)) + '/' + res = setuptools.package_index.local_open(url) assert 'content' in res.read() -class TestContentCheckers(unittest.TestCase): +class TestContentCheckers: def test_md5(self): checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') checker.feed('You should probably not be using MD5'.encode('ascii')) - self.assertEqual(checker.hash.hexdigest(), - 'f12895fdffbd45007040d2e44df98478') - self.assertTrue(checker.is_valid()) + assert checker.hash.hexdigest() == 'f12895fdffbd45007040d2e44df98478' + assert checker.is_valid() def test_other_fragment(self): "Content checks should succeed silently if no hash is present" checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#something%20completely%20different') checker.feed('anything'.encode('ascii')) - self.assertTrue(checker.is_valid()) + assert checker.is_valid() def test_blank_md5(self): "Content checks should succeed if a hash is empty" checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=') checker.feed('anything'.encode('ascii')) - self.assertTrue(checker.is_valid()) + assert checker.is_valid() def test_get_hash_name_md5(self): checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') - self.assertEqual(checker.hash_name, 'md5') + assert checker.hash_name == 'md5' def test_report(self): checker = setuptools.package_index.HashChecker.from_url( 'http://foo/bar#md5=f12895fdffbd45007040d2e44df98478') rep = checker.report(lambda x: x, 'My message about %s') - self.assertEqual(rep, 'My message about md5') + assert rep == 'My message about md5' diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py index b688cfe0..465c9343 100644 --- a/setuptools/tests/test_resources.py +++ b/setuptools/tests/test_resources.py @@ -1,21 +1,23 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# NOTE: the shebang and encoding lines are for ScriptHeaderTests do not remove +# NOTE: the shebang and encoding lines are for TestScriptHeader do not remove import os import sys import tempfile import shutil -from unittest import TestCase + +import pytest import pkg_resources from pkg_resources import (parse_requirements, VersionConflict, parse_version, Distribution, EntryPoint, Requirement, safe_version, safe_name, WorkingSet) +packaging = pkg_resources.packaging + from setuptools.command.easy_install import (get_script_header, is_sh, nt_quote_arg) -from .py26compat import skipIf import six @@ -46,36 +48,32 @@ class Metadata(pkg_resources.EmptyProvider): dist_from_fn = pkg_resources.Distribution.from_filename -class DistroTests(TestCase): +class TestDistro: def testCollection(self): # empty path should produce no distributions ad = pkg_resources.Environment([], platform=None, python=None) - self.assertEqual(list(ad), []) - self.assertEqual(ad['FooPkg'],[]) + assert list(ad) == [] + assert ad['FooPkg'] == [] ad.add(dist_from_fn("FooPkg-1.3_1.egg")) ad.add(dist_from_fn("FooPkg-1.4-py2.4-win32.egg")) ad.add(dist_from_fn("FooPkg-1.2-py2.4.egg")) # Name is in there now - self.assertTrue(ad['FooPkg']) + assert ad['FooPkg'] # But only 1 package - self.assertEqual(list(ad), ['foopkg']) + assert list(ad) == ['foopkg'] # Distributions sort by version - self.assertEqual( - [dist.version for dist in ad['FooPkg']], ['1.4','1.3-1','1.2'] - ) + assert [dist.version for dist in ad['FooPkg']] == ['1.4','1.3-1','1.2'] + # Removing a distribution leaves sequence alone ad.remove(ad['FooPkg'][1]) - self.assertEqual( - [dist.version for dist in ad['FooPkg']], ['1.4','1.2'] - ) + assert [dist.version for dist in ad['FooPkg']] == ['1.4','1.2'] + # And inserting adds them in order ad.add(dist_from_fn("FooPkg-1.9.egg")) - self.assertEqual( - [dist.version for dist in ad['FooPkg']], ['1.9','1.4','1.2'] - ) + assert [dist.version for dist in ad['FooPkg']] == ['1.9','1.4','1.2'] ws = WorkingSet([]) foo12 = dist_from_fn("FooPkg-1.2-py2.4.egg") @@ -83,31 +81,32 @@ class DistroTests(TestCase): req, = parse_requirements("FooPkg>=1.3") # Nominal case: no distros on path, should yield all applicable - self.assertEqual(ad.best_match(req,ws).version, '1.9') + assert ad.best_match(req, ws).version == '1.9' # If a matching distro is already installed, should return only that ws.add(foo14) - self.assertEqual(ad.best_match(req,ws).version, '1.4') + assert ad.best_match(req, ws).version == '1.4' # If the first matching distro is unsuitable, it's a version conflict ws = WorkingSet([]) ws.add(foo12) ws.add(foo14) - self.assertRaises(VersionConflict, ad.best_match, req, ws) + with pytest.raises(VersionConflict): + ad.best_match(req, ws) # If more than one match on the path, the first one takes precedence ws = WorkingSet([]) ws.add(foo14) ws.add(foo12) ws.add(foo14) - self.assertEqual(ad.best_match(req,ws).version, '1.4') + assert ad.best_match(req, ws).version == '1.4' def checkFooPkg(self,d): - self.assertEqual(d.project_name, "FooPkg") - self.assertEqual(d.key, "foopkg") - self.assertEqual(d.version, "1.3-1") - self.assertEqual(d.py_version, "2.4") - self.assertEqual(d.platform, "win32") - self.assertEqual(d.parsed_version, parse_version("1.3-1")) + assert d.project_name == "FooPkg" + assert d.key == "foopkg" + assert d.version == "1.3.post1" + assert d.py_version == "2.4" + assert d.platform == "win32" + assert d.parsed_version == parse_version("1.3-1") def testDistroBasics(self): d = Distribution( @@ -117,13 +116,13 @@ class DistroTests(TestCase): self.checkFooPkg(d) d = Distribution("/some/path") - self.assertEqual(d.py_version, sys.version[:3]) - self.assertEqual(d.platform, None) + assert d.py_version == sys.version[:3] + assert d.platform == None def testDistroParse(self): - d = dist_from_fn("FooPkg-1.3_1-py2.4-win32.egg") + d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg") self.checkFooPkg(d) - d = dist_from_fn("FooPkg-1.3_1-py2.4-win32.egg-info") + d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg-info") self.checkFooPkg(d) def testDistroMetadata(self): @@ -139,10 +138,7 @@ class DistroTests(TestCase): return Distribution("/foo", metadata=Metadata(('depends.txt', txt))) def checkRequires(self, dist, txt, extras=()): - self.assertEqual( - list(dist.requires(extras)), - list(parse_requirements(txt)) - ) + assert list(dist.requires(extras)) == list(parse_requirements(txt)) def testDistroDependsSimple(self): for v in "Twisted>=1.5", "Twisted>=1.5\nZConfig>=2.0": @@ -152,11 +148,11 @@ class DistroTests(TestCase): ad = pkg_resources.Environment([]) ws = WorkingSet([]) # Resolving no requirements -> nothing to install - self.assertEqual(list(ws.resolve([],ad)), []) + assert list(ws.resolve([], ad)) == [] # Request something not in the collection -> DistributionNotFound - self.assertRaises( - pkg_resources.DistributionNotFound, ws.resolve, parse_requirements("Foo"), ad - ) + with pytest.raises(pkg_resources.DistributionNotFound): + ws.resolve(parse_requirements("Foo"), ad) + Foo = Distribution.from_filename( "/foo_dir/Foo-1.2.egg", metadata=Metadata(('depends.txt', "[bar]\nBaz>=2.0")) @@ -167,28 +163,25 @@ class DistroTests(TestCase): # Request thing(s) that are available -> list to activate for i in range(3): targets = list(ws.resolve(parse_requirements("Foo"), ad)) - self.assertEqual(targets, [Foo]) + assert targets == [Foo] list(map(ws.add,targets)) - self.assertRaises(VersionConflict, ws.resolve, - parse_requirements("Foo==0.9"), ad) + with pytest.raises(VersionConflict): + ws.resolve(parse_requirements("Foo==0.9"), ad) ws = WorkingSet([]) # reset # Request an extra that causes an unresolved dependency for "Baz" - self.assertRaises( - pkg_resources.DistributionNotFound, ws.resolve,parse_requirements("Foo[bar]"), ad - ) + with pytest.raises(pkg_resources.DistributionNotFound): + ws.resolve(parse_requirements("Foo[bar]"), ad) Baz = Distribution.from_filename( "/foo_dir/Baz-2.1.egg", metadata=Metadata(('depends.txt', "Foo")) ) ad.add(Baz) # Activation list now includes resolved dependency - self.assertEqual( - list(ws.resolve(parse_requirements("Foo[bar]"), ad)), [Foo,Baz] - ) + assert list(ws.resolve(parse_requirements("Foo[bar]"), ad)) ==[Foo,Baz] # Requests for conflicting versions produce VersionConflict - self.assertRaises(VersionConflict, - ws.resolve, parse_requirements("Foo==1.2\nFoo!=1.2"), ad) + with pytest.raises(VersionConflict): + ws.resolve(parse_requirements("Foo==1.2\nFoo!=1.2"), ad) def testDistroDependsOptions(self): d = self.distRequires(""" @@ -213,49 +206,55 @@ class DistroTests(TestCase): d,"Twisted>=1.5 fcgiapp>=0.1 ZConfig>=2.0 docutils>=0.3".split(), ["fastcgi", "docgen"] ) - self.assertRaises(pkg_resources.UnknownExtra, d.requires, ["foo"]) + with pytest.raises(pkg_resources.UnknownExtra): + d.requires(["foo"]) -class EntryPointTests(TestCase): +class TestEntryPoints: def assertfields(self, ep): - self.assertEqual(ep.name,"foo") - self.assertEqual(ep.module_name,"setuptools.tests.test_resources") - self.assertEqual(ep.attrs, ("EntryPointTests",)) - self.assertEqual(ep.extras, ("x",)) - self.assertTrue(ep.load() is EntryPointTests) - self.assertEqual( - str(ep), - "foo = setuptools.tests.test_resources:EntryPointTests [x]" + assert ep.name == "foo" + assert ep.module_name == "setuptools.tests.test_resources" + assert ep.attrs == ("TestEntryPoints",) + assert ep.extras == ("x",) + assert ep.load() is TestEntryPoints + assert ( + str(ep) == + "foo = setuptools.tests.test_resources:TestEntryPoints [x]" ) - def setUp(self): + def setup_method(self, method): self.dist = Distribution.from_filename( "FooPkg-1.2-py2.4.egg", metadata=Metadata(('requires.txt','[x]'))) def testBasics(self): ep = EntryPoint( - "foo", "setuptools.tests.test_resources", ["EntryPointTests"], + "foo", "setuptools.tests.test_resources", ["TestEntryPoints"], ["x"], self.dist ) self.assertfields(ep) def testParse(self): - s = "foo = setuptools.tests.test_resources:EntryPointTests [x]" + s = "foo = setuptools.tests.test_resources:TestEntryPoints [x]" ep = EntryPoint.parse(s, self.dist) self.assertfields(ep) ep = EntryPoint.parse("bar baz= spammity[PING]") - self.assertEqual(ep.name,"bar baz") - self.assertEqual(ep.module_name,"spammity") - self.assertEqual(ep.attrs, ()) - self.assertEqual(ep.extras, ("ping",)) + assert ep.name == "bar baz" + assert ep.module_name == "spammity" + assert ep.attrs == () + assert ep.extras == ("ping",) ep = EntryPoint.parse(" fizzly = wocka:foo") - self.assertEqual(ep.name,"fizzly") - self.assertEqual(ep.module_name,"wocka") - self.assertEqual(ep.attrs, ("foo",)) - self.assertEqual(ep.extras, ()) + assert ep.name == "fizzly" + assert ep.module_name == "wocka" + assert ep.attrs == ("foo",) + assert ep.extras == () + + # plus in the name + spec = "html+mako = mako.ext.pygmentplugin:MakoHtmlLexer" + ep = EntryPoint.parse(spec) + assert ep.name == 'html+mako' def testRejects(self): for ep in [ @@ -266,9 +265,9 @@ class EntryPointTests(TestCase): else: raise AssertionError("Should've been bad", ep) def checkSubMap(self, m): - self.assertEqual(len(m), len(self.submap_expect)) + assert len(m) == len(self.submap_expect) for key, ep in six.iteritems(self.submap_expect): - self.assertEqual(repr(m.get(key)), repr(ep)) + assert repr(m.get(key)) == repr(ep) submap_expect = dict( feature1=EntryPoint('feature1', 'somemodule', ['somefunction']), @@ -284,72 +283,71 @@ class EntryPointTests(TestCase): def testParseList(self): self.checkSubMap(EntryPoint.parse_group("xyz", self.submap_str)) - self.assertRaises(ValueError, EntryPoint.parse_group, "x a", "foo=bar") - self.assertRaises(ValueError, EntryPoint.parse_group, "x", - ["foo=baz", "foo=bar"]) + with pytest.raises(ValueError): + EntryPoint.parse_group("x a", "foo=bar") + with pytest.raises(ValueError): + EntryPoint.parse_group("x", ["foo=baz", "foo=bar"]) def testParseMap(self): m = EntryPoint.parse_map({'xyz':self.submap_str}) self.checkSubMap(m['xyz']) - self.assertEqual(list(m.keys()),['xyz']) + assert list(m.keys()) == ['xyz'] m = EntryPoint.parse_map("[xyz]\n"+self.submap_str) self.checkSubMap(m['xyz']) - self.assertEqual(list(m.keys()),['xyz']) - self.assertRaises(ValueError, EntryPoint.parse_map, ["[xyz]", "[xyz]"]) - self.assertRaises(ValueError, EntryPoint.parse_map, self.submap_str) + assert list(m.keys()) == ['xyz'] + with pytest.raises(ValueError): + EntryPoint.parse_map(["[xyz]", "[xyz]"]) + with pytest.raises(ValueError): + EntryPoint.parse_map(self.submap_str) -class RequirementsTests(TestCase): +class TestRequirements: def testBasics(self): r = Requirement.parse("Twisted>=1.2") - self.assertEqual(str(r),"Twisted>=1.2") - self.assertEqual(repr(r),"Requirement.parse('Twisted>=1.2')") - self.assertEqual(r, Requirement("Twisted", [('>=','1.2')], ())) - self.assertEqual(r, Requirement("twisTed", [('>=','1.2')], ())) - self.assertNotEqual(r, Requirement("Twisted", [('>=','2.0')], ())) - self.assertNotEqual(r, Requirement("Zope", [('>=','1.2')], ())) - self.assertNotEqual(r, Requirement("Zope", [('>=','3.0')], ())) - self.assertNotEqual(r, Requirement.parse("Twisted[extras]>=1.2")) + assert str(r) == "Twisted>=1.2" + assert repr(r) == "Requirement.parse('Twisted>=1.2')" + assert r == Requirement("Twisted", [('>=','1.2')], ()) + assert r == Requirement("twisTed", [('>=','1.2')], ()) + assert r != Requirement("Twisted", [('>=','2.0')], ()) + assert r != Requirement("Zope", [('>=','1.2')], ()) + assert r != Requirement("Zope", [('>=','3.0')], ()) + assert r != Requirement.parse("Twisted[extras]>=1.2") def testOrdering(self): r1 = Requirement("Twisted", [('==','1.2c1'),('>=','1.2')], ()) r2 = Requirement("Twisted", [('>=','1.2'),('==','1.2c1')], ()) - self.assertEqual(r1,r2) - self.assertEqual(str(r1),str(r2)) - self.assertEqual(str(r2),"Twisted==1.2c1,>=1.2") + assert r1 == r2 + assert str(r1) == str(r2) + assert str(r2) == "Twisted==1.2c1,>=1.2" def testBasicContains(self): r = Requirement("Twisted", [('>=','1.2')], ()) foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg") twist11 = Distribution.from_filename("Twisted-1.1.egg") twist12 = Distribution.from_filename("Twisted-1.2.egg") - self.assertTrue(parse_version('1.2') in r) - self.assertTrue(parse_version('1.1') not in r) - self.assertTrue('1.2' in r) - self.assertTrue('1.1' not in r) - self.assertTrue(foo_dist not in r) - self.assertTrue(twist11 not in r) - self.assertTrue(twist12 in r) - - def testAdvancedContains(self): - r, = parse_requirements("Foo>=1.2,<=1.3,==1.9,>2.0,!=2.5,<3.0,==4.5") - for v in ('1.2','1.2.2','1.3','1.9','2.0.1','2.3','2.6','3.0c1','4.5'): - self.assertTrue(v in r, (v,r)) - for v in ('1.2c1','1.3.1','1.5','1.9.1','2.0','2.5','3.0','4.0'): - self.assertTrue(v not in r, (v,r)) + assert parse_version('1.2') in r + assert parse_version('1.1') not in r + assert '1.2' in r + assert '1.1' not in r + assert foo_dist not in r + assert twist11 not in r + assert twist12 in r def testOptionsAndHashing(self): r1 = Requirement.parse("Twisted[foo,bar]>=1.2") r2 = Requirement.parse("Twisted[bar,FOO]>=1.2") - r3 = Requirement.parse("Twisted[BAR,FOO]>=1.2.0") - self.assertEqual(r1,r2) - self.assertEqual(r1,r3) - self.assertEqual(r1.extras, ("foo","bar")) - self.assertEqual(r2.extras, ("bar","foo")) # extras are normalized - self.assertEqual(hash(r1), hash(r2)) - self.assertEqual( - hash(r1), hash(("twisted", ((">=",parse_version("1.2")),), - frozenset(["foo","bar"]))) + assert r1 == r2 + assert r1.extras == ("foo","bar") + assert r2.extras == ("bar","foo") # extras are normalized + assert hash(r1) == hash(r2) + assert ( + hash(r1) + == + hash(( + "twisted", + packaging.specifiers.SpecifierSet(">=1.2"), + frozenset(["foo","bar"]), + )) ) def testVersionEquality(self): @@ -357,42 +355,42 @@ class RequirementsTests(TestCase): r2 = Requirement.parse("foo!=0.3a4") d = Distribution.from_filename - self.assertTrue(d("foo-0.3a4.egg") not in r1) - self.assertTrue(d("foo-0.3a1.egg") not in r1) - self.assertTrue(d("foo-0.3a4.egg") not in r2) + assert d("foo-0.3a4.egg") not in r1 + assert d("foo-0.3a1.egg") not in r1 + assert d("foo-0.3a4.egg") not in r2 - self.assertTrue(d("foo-0.3a2.egg") in r1) - self.assertTrue(d("foo-0.3a2.egg") in r2) - self.assertTrue(d("foo-0.3a3.egg") in r2) - self.assertTrue(d("foo-0.3a5.egg") in r2) + assert d("foo-0.3a2.egg") in r1 + assert d("foo-0.3a2.egg") in r2 + assert d("foo-0.3a3.egg") in r2 + assert d("foo-0.3a5.egg") in r2 def testSetuptoolsProjectName(self): """ The setuptools project should implement the setuptools package. """ - self.assertEqual( - Requirement.parse('setuptools').project_name, 'setuptools') + assert ( + Requirement.parse('setuptools').project_name == 'setuptools') # setuptools 0.7 and higher means setuptools. - self.assertEqual( - Requirement.parse('setuptools == 0.7').project_name, 'setuptools') - self.assertEqual( - Requirement.parse('setuptools == 0.7a1').project_name, 'setuptools') - self.assertEqual( - Requirement.parse('setuptools >= 0.7').project_name, 'setuptools') + assert ( + Requirement.parse('setuptools == 0.7').project_name == 'setuptools') + assert ( + Requirement.parse('setuptools == 0.7a1').project_name == 'setuptools') + assert ( + Requirement.parse('setuptools >= 0.7').project_name == 'setuptools') -class ParseTests(TestCase): +class TestParsing: def testEmptyParse(self): - self.assertEqual(list(parse_requirements('')), []) + assert list(parse_requirements('')) == [] def testYielding(self): for inp,out in [ ([], []), ('x',['x']), ([[]],[]), (' x\n y', ['x','y']), (['x\n\n','y'], ['x','y']), ]: - self.assertEqual(list(pkg_resources.yield_lines(inp)),out) + assert list(pkg_resources.yield_lines(inp)) == out def testSplitting(self): sample = """ @@ -408,64 +406,81 @@ class ParseTests(TestCase): [q] v """ - self.assertEqual(list(pkg_resources.split_sections(sample)), - [(None,["x"]), ("Y",["z","a"]), ("b",["c"]), ("d",[]), ("q",["v"])] + assert ( + list(pkg_resources.split_sections(sample)) + == + [ + (None, ["x"]), + ("Y", ["z", "a"]), + ("b", ["c"]), + ("d", []), + ("q", ["v"]), + ] ) - self.assertRaises(ValueError,list,pkg_resources.split_sections("[foo")) + with pytest.raises(ValueError): + list(pkg_resources.split_sections("[foo")) def testSafeName(self): - self.assertEqual(safe_name("adns-python"), "adns-python") - self.assertEqual(safe_name("WSGI Utils"), "WSGI-Utils") - self.assertEqual(safe_name("WSGI Utils"), "WSGI-Utils") - self.assertEqual(safe_name("Money$$$Maker"), "Money-Maker") - self.assertNotEqual(safe_name("peak.web"), "peak-web") + assert safe_name("adns-python") == "adns-python" + assert safe_name("WSGI Utils") == "WSGI-Utils" + assert safe_name("WSGI Utils") == "WSGI-Utils" + assert safe_name("Money$$$Maker") == "Money-Maker" + assert safe_name("peak.web") != "peak-web" def testSafeVersion(self): - self.assertEqual(safe_version("1.2-1"), "1.2-1") - self.assertEqual(safe_version("1.2 alpha"), "1.2.alpha") - self.assertEqual(safe_version("2.3.4 20050521"), "2.3.4.20050521") - self.assertEqual(safe_version("Money$$$Maker"), "Money-Maker") - self.assertEqual(safe_version("peak.web"), "peak.web") + assert safe_version("1.2-1") == "1.2.post1" + assert safe_version("1.2 alpha") == "1.2.alpha" + assert safe_version("2.3.4 20050521") == "2.3.4.20050521" + assert safe_version("Money$$$Maker") == "Money-Maker" + assert safe_version("peak.web") == "peak.web" def testSimpleRequirements(self): - self.assertEqual( - list(parse_requirements('Twis-Ted>=1.2-1')), + assert ( + list(parse_requirements('Twis-Ted>=1.2-1')) + == [Requirement('Twis-Ted',[('>=','1.2-1')], ())] ) - self.assertEqual( - list(parse_requirements('Twisted >=1.2, \ # more\n<2.0')), + assert ( + list(parse_requirements('Twisted >=1.2, \ # more\n<2.0')) + == [Requirement('Twisted',[('>=','1.2'),('<','2.0')], ())] ) - self.assertEqual( - Requirement.parse("FooBar==1.99a3"), + assert ( + Requirement.parse("FooBar==1.99a3") + == Requirement("FooBar", [('==','1.99a3')], ()) ) - self.assertRaises(ValueError,Requirement.parse,">=2.3") - self.assertRaises(ValueError,Requirement.parse,"x\\") - self.assertRaises(ValueError,Requirement.parse,"x==2 q") - self.assertRaises(ValueError,Requirement.parse,"X==1\nY==2") - self.assertRaises(ValueError,Requirement.parse,"#") + with pytest.raises(ValueError): + Requirement.parse(">=2.3") + with pytest.raises(ValueError): + Requirement.parse("x\\") + with pytest.raises(ValueError): + Requirement.parse("x==2 q") + with pytest.raises(ValueError): + Requirement.parse("X==1\nY==2") + with pytest.raises(ValueError): + Requirement.parse("#") def testVersionEquality(self): def c(s1,s2): p1, p2 = parse_version(s1),parse_version(s2) - self.assertEqual(p1,p2, (s1,s2,p1,p2)) + assert p1 == p2, (s1,s2,p1,p2) c('1.2-rc1', '1.2rc1') c('0.4', '0.4.0') c('0.4.0.0', '0.4.0') c('0.4.0-0', '0.4-0') - c('0pl1', '0.0pl1') + c('0post1', '0.0post1') c('0pre1', '0.0c1') c('0.0.0preview1', '0c1') c('0.0c1', '0-rc1') c('1.2a1', '1.2.a.1') - c('1.2...a', '1.2a') + c('1.2.a', '1.2a') def testVersionOrdering(self): def c(s1,s2): p1, p2 = parse_version(s1),parse_version(s2) - self.assertTrue(p1<p2, (s1,s2,p1,p2)) + assert p1<p2, (s1,s2,p1,p2) c('2.1','2.1.1') c('2a1','2b0') @@ -473,16 +488,14 @@ class ParseTests(TestCase): c('2.3a1', '2.3') c('2.1-1', '2.1-2') c('2.1-1', '2.1.1') - c('2.1', '2.1pl4') + c('2.1', '2.1post4') c('2.1a0-20040501', '2.1') c('1.1', '02.1') - c('A56','B27') - c('3.2', '3.2.pl0') - c('3.2-1', '3.2pl1') - c('3.2pl1', '3.2pl1-1') + c('3.2', '3.2.post0') + c('3.2post1', '3.2post2') c('0.4', '4.0') c('0.0.4', '0.4.0') - c('0pl1', '0.4pl1') + c('0post1', '0.4post1') c('2.1.0-rc1','2.1.0') c('2.1dev','2.1a0') @@ -496,8 +509,59 @@ class ParseTests(TestCase): for v2 in torture[p+1:]: c(v2,v1) + def testVersionBuildout(self): + """ + Buildout has a function in it's bootstrap.py that inspected the return + value of parse_version. The new parse_version returns a Version class + which needs to support this behavior, at least for now. + """ + def buildout(parsed_version): + _final_parts = '*final-', '*final' + + def _final_version(parsed_version): + for part in parsed_version: + if (part[:1] == '*') and (part not in _final_parts): + return False + return True + return _final_version(parsed_version) + + assert buildout(parse_version("1.0")) + assert not buildout(parse_version("1.0a1")) + + def testVersionIndexable(self): + """ + Some projects were doing things like parse_version("v")[0], so we'll + support indexing the same as we support iterating. + """ + assert parse_version("1.0")[0] == "00000001" -class ScriptHeaderTests(TestCase): + def testVersionTupleSort(self): + """ + Some projects expected to be able to sort tuples against the return + value of parse_version. So again we'll add a warning enabled shim to + make this possible. + """ + assert parse_version("1.0") < tuple(parse_version("2.0")) + assert parse_version("1.0") <= tuple(parse_version("2.0")) + assert parse_version("1.0") == tuple(parse_version("1.0")) + assert parse_version("3.0") > tuple(parse_version("2.0")) + assert parse_version("3.0") >= tuple(parse_version("2.0")) + assert parse_version("3.0") != tuple(parse_version("2.0")) + assert not (parse_version("3.0") != tuple(parse_version("3.0"))) + + def testVersionHashable(self): + """ + Ensure that our versions stay hashable even though we've subclassed + them and added some shim code to them. + """ + assert ( + hash(parse_version("1.0")) + == + hash(parse_version("1.0")) + ) + + +class TestScriptHeader: non_ascii_exe = '/Users/José/bin/python' exe_with_spaces = r'C:\Program Files\Python33\python.exe' @@ -505,17 +569,15 @@ class ScriptHeaderTests(TestCase): if not sys.platform.startswith('java') or not is_sh(sys.executable): # This test is for non-Jython platforms expected = '#!%s\n' % nt_quote_arg(os.path.normpath(sys.executable)) - self.assertEqual(get_script_header('#!/usr/local/bin/python'), - expected) + assert get_script_header('#!/usr/local/bin/python') == expected expected = '#!%s -x\n' % nt_quote_arg(os.path.normpath(sys.executable)) - self.assertEqual(get_script_header('#!/usr/bin/python -x'), - expected) - self.assertEqual(get_script_header('#!/usr/bin/python', - executable=self.non_ascii_exe), - '#!%s -x\n' % self.non_ascii_exe) + assert get_script_header('#!/usr/bin/python -x') == expected + candidate = get_script_header('#!/usr/bin/python', + executable=self.non_ascii_exe) + assert candidate == '#!%s -x\n' % self.non_ascii_exe candidate = get_script_header('#!/usr/bin/python', executable=self.exe_with_spaces) - self.assertEqual(candidate, '#!"%s"\n' % self.exe_with_spaces) + assert candidate == '#!"%s"\n' % self.exe_with_spaces def test_get_script_header_jython_workaround(self): # This test doesn't work with Python 3 in some locales @@ -536,44 +598,46 @@ class ScriptHeaderTests(TestCase): try: # A mock sys.executable that uses a shebang line (this file) exe = os.path.normpath(os.path.splitext(__file__)[0] + '.py') - self.assertEqual( - get_script_header('#!/usr/local/bin/python', executable=exe), - '#!/usr/bin/env %s\n' % exe) + assert ( + get_script_header('#!/usr/local/bin/python', executable=exe) + == + '#!/usr/bin/env %s\n' % exe + ) # Ensure we generate what is basically a broken shebang line # when there's options, with a warning emitted sys.stdout = sys.stderr = six.StringIO() - self.assertEqual(get_script_header('#!/usr/bin/python -x', - executable=exe), - '#!%s -x\n' % exe) - self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalue()) + candidate = get_script_header('#!/usr/bin/python -x', + executable=exe) + assert candidate == '#!%s -x\n' % exe + assert 'Unable to adapt shebang line' in sys.stdout.getvalue() sys.stdout = sys.stderr = six.StringIO() - self.assertEqual(get_script_header('#!/usr/bin/python', - executable=self.non_ascii_exe), - '#!%s -x\n' % self.non_ascii_exe) - self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalue()) + candidate = get_script_header('#!/usr/bin/python', + executable=self.non_ascii_exe) + assert candidate == '#!%s -x\n' % self.non_ascii_exe + assert 'Unable to adapt shebang line' in sys.stdout.getvalue() finally: del sys.modules["java"] sys.platform = platform sys.stdout, sys.stderr = stdout, stderr -class NamespaceTests(TestCase): +class TestNamespaces: - def setUp(self): + def setup_method(self, method): self._ns_pkgs = pkg_resources._namespace_packages.copy() self._tmpdir = tempfile.mkdtemp(prefix="tests-setuptools-") os.makedirs(os.path.join(self._tmpdir, "site-pkgs")) self._prev_sys_path = sys.path[:] sys.path.append(os.path.join(self._tmpdir, "site-pkgs")) - def tearDown(self): + def teardown_method(self, method): shutil.rmtree(self._tmpdir) pkg_resources._namespace_packages = self._ns_pkgs.copy() sys.path = self._prev_sys_path[:] - msg = "Test fails when /tmp is a symlink. See #231" - @skipIf(os.path.islink(tempfile.gettempdir()), msg) + @pytest.mark.skipif(os.path.islink(tempfile.gettempdir()), + reason="Test fails when /tmp is a symlink. See #231") def test_two_levels_deep(self): """ Test nested namespace packages diff --git a/setuptools/tests/test_sandbox.py b/setuptools/tests/test_sandbox.py index 6a890ebc..6e5ce04a 100644 --- a/setuptools/tests/test_sandbox.py +++ b/setuptools/tests/test_sandbox.py @@ -1,67 +1,45 @@ """develop tests """ -import sys import os -import shutil -import unittest -import tempfile import types +import pytest + import pkg_resources import setuptools.sandbox from setuptools.sandbox import DirectorySandbox, SandboxViolation -def has_win32com(): - """ - Run this to determine if the local machine has win32com, and if it - does, include additional tests. - """ - if not sys.platform.startswith('win32'): - return False - try: - __import__('win32com') - except ImportError: - return False - return True - -class TestSandbox(unittest.TestCase): - def setUp(self): - self.dir = tempfile.mkdtemp() +class TestSandbox: - def tearDown(self): - shutil.rmtree(self.dir) - - def test_devnull(self): - sandbox = DirectorySandbox(self.dir) + def test_devnull(self, tmpdir): + sandbox = DirectorySandbox(str(tmpdir)) sandbox.run(self._file_writer(os.devnull)) + @staticmethod def _file_writer(path): def do_write(): - f = open(path, 'w') - f.write('xxx') - f.close() + with open(path, 'w') as f: + f.write('xxx') return do_write - _file_writer = staticmethod(_file_writer) - - if has_win32com(): - def test_win32com(self): - """ - win32com should not be prevented from caching COM interfaces - in gen_py. - """ - import win32com - gen_py = win32com.__gen_path__ - target = os.path.join(gen_py, 'test_write') - sandbox = DirectorySandbox(self.dir) + def test_win32com(self, tmpdir): + """ + win32com should not be prevented from caching COM interfaces + in gen_py. + """ + win32com = pytest.importorskip('win32com') + gen_py = win32com.__gen_path__ + target = os.path.join(gen_py, 'test_write') + sandbox = DirectorySandbox(str(tmpdir)) + try: try: - try: - sandbox.run(self._file_writer(target)) - except SandboxViolation: - self.fail("Could not create gen_py file due to SandboxViolation") - finally: - if os.path.exists(target): os.remove(target) + sandbox.run(self._file_writer(target)) + except SandboxViolation: + self.fail("Could not create gen_py file due to SandboxViolation") + finally: + if os.path.exists(target): + os.remove(target) def test_setup_py_with_BOM(self): """ @@ -73,11 +51,8 @@ class TestSandbox(unittest.TestCase): setuptools.sandbox._execfile(target, vars(namespace)) assert namespace.result == 'passed' - def test_setup_py_with_CRLF(self): - setup_py = os.path.join(self.dir, 'setup.py') - with open(setup_py, 'wb') as stream: + def test_setup_py_with_CRLF(self, tmpdir): + setup_py = tmpdir / 'setup.py' + with setup_py.open('wb') as stream: stream.write(b'"degenerate script"\r\n') - setuptools.sandbox._execfile(setup_py, globals()) - -if __name__ == '__main__': - unittest.main() + setuptools.sandbox._execfile(str(setup_py), globals()) diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py index 26b072cc..d30e21ac 100644 --- a/setuptools/tests/test_sdist.py +++ b/setuptools/tests/test_sdist.py @@ -6,19 +6,16 @@ import os import shutil import sys import tempfile -import unittest import unicodedata -import re import contextlib import six +import pytest -from setuptools.tests import environment, test_svn -from setuptools.tests.py26compat import skipIf -from setuptools.command.sdist import sdist, walk_revctrl +import pkg_resources +from setuptools.command.sdist import sdist from setuptools.command.egg_info import manifest_maker from setuptools.dist import Distribution -from setuptools import svn_utils SETUP_ATTRS = { 'name': 'sdist_test', @@ -80,9 +77,9 @@ def decompose(path): return path -class TestSdistTest(unittest.TestCase): +class TestSdistTest: - def setUp(self): + def setup_method(self, method): self.temp_dir = tempfile.mkdtemp() f = open(os.path.join(self.temp_dir, 'setup.py'), 'w') f.write(SETUP_PY) @@ -100,7 +97,7 @@ class TestSdistTest(unittest.TestCase): self.old_cwd = os.getcwd() os.chdir(self.temp_dir) - def tearDown(self): + def teardown_method(self, method): os.chdir(self.old_cwd) shutil.rmtree(self.temp_dir) @@ -119,9 +116,9 @@ class TestSdistTest(unittest.TestCase): cmd.run() manifest = cmd.filelist.files - self.assertTrue(os.path.join('sdist_test', 'a.txt') in manifest) - self.assertTrue(os.path.join('sdist_test', 'b.txt') in manifest) - self.assertTrue(os.path.join('sdist_test', 'c.rst') not in manifest) + assert os.path.join('sdist_test', 'a.txt') in manifest + assert os.path.join('sdist_test', 'b.txt') in manifest + assert os.path.join('sdist_test', 'c.rst') not in manifest def test_defaults_case_sensitivity(self): @@ -146,9 +143,9 @@ class TestSdistTest(unittest.TestCase): # lowercase all names so we can test in a case-insensitive way to make sure the files are not included manifest = map(lambda x: x.lower(), cmd.filelist.files) - self.assertFalse('readme.rst' in manifest, manifest) - self.assertFalse('setup.py' in manifest, manifest) - self.assertFalse('setup.cfg' in manifest, manifest) + assert 'readme.rst' not in manifest, manifest + assert 'setup.py' not in manifest, manifest + assert 'setup.cfg' not in manifest, manifest def test_manifest_is_written_with_utf8_encoding(self): # Test for #303. @@ -186,7 +183,7 @@ class TestSdistTest(unittest.TestCase): fs_enc = sys.getfilesystemencoding() filename = filename.decode(fs_enc) - self.assertTrue(posix(filename) in u_contents) + assert posix(filename) in u_contents # Python 3 only if six.PY3: @@ -225,10 +222,10 @@ class TestSdistTest(unittest.TestCase): self.fail(e) # The manifest should contain the UTF-8 filename - self.assertTrue(posix(filename) in contents) + assert posix(filename) in contents # The filelist should have been updated as well - self.assertTrue(u_filename in mm.filelist.files) + assert u_filename in mm.filelist.files def test_write_manifest_skips_non_utf8_filenames(self): """ @@ -266,10 +263,10 @@ class TestSdistTest(unittest.TestCase): self.fail(e) # The Latin-1 filename should have been skipped - self.assertFalse(posix(filename) in contents) + assert posix(filename) not in contents # The filelist should have been updated as well - self.assertFalse(u_filename in mm.filelist.files) + assert u_filename not in mm.filelist.files def test_manifest_is_read_with_utf8_encoding(self): # Test for #303. @@ -300,7 +297,7 @@ class TestSdistTest(unittest.TestCase): # The filelist should contain the UTF-8 filename if six.PY3: filename = filename.decode('utf-8') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files # Python 3 only if six.PY3: @@ -337,10 +334,11 @@ class TestSdistTest(unittest.TestCase): # The Latin-1 filename should have been skipped filename = filename.decode('latin-1') - self.assertFalse(filename in cmd.filelist.files) + assert filename not in cmd.filelist.files - @skipIf(six.PY3 and locale.getpreferredencoding() != 'UTF-8', - 'Unittest fails if locale is not utf-8 but the manifests is recorded correctly') + @pytest.mark.skipif(six.PY3 and locale.getpreferredencoding() != 'UTF-8', + reason='Unittest fails if locale is not utf-8 but the manifests is ' + 'recorded correctly') def test_sdist_with_utf8_encoded_filename(self): # Test for #303. dist = Distribution(SETUP_ATTRS) @@ -365,15 +363,15 @@ class TestSdistTest(unittest.TestCase): if fs_enc == 'cp1252': # Python 3 mangles the UTF-8 filename filename = filename.decode('cp1252') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files else: filename = filename.decode('mbcs') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files else: filename = filename.decode('utf-8') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files else: - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files def test_sdist_with_latin1_encoded_filename(self): # Test for #303. @@ -385,7 +383,7 @@ class TestSdistTest(unittest.TestCase): # Latin-1 filename filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) open(filename, 'w').close() - self.assertTrue(os.path.isfile(filename)) + assert os.path.isfile(filename) with quiet(): cmd.run() @@ -401,11 +399,11 @@ class TestSdistTest(unittest.TestCase): else: filename = filename.decode('latin-1') - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files else: # The Latin-1 filename should have been skipped filename = filename.decode('latin-1') - self.assertFalse(filename in cmd.filelist.files) + filename not in cmd.filelist.files else: # Under Python 2 there seems to be no decoded string in the # filelist. However, due to decode and encoding of the @@ -415,139 +413,23 @@ class TestSdistTest(unittest.TestCase): # be proformed for the manifest output. fs_enc = sys.getfilesystemencoding() filename.decode(fs_enc) - self.assertTrue(filename in cmd.filelist.files) + assert filename in cmd.filelist.files except UnicodeDecodeError: - self.assertFalse(filename in cmd.filelist.files) - -class TestDummyOutput(environment.ZippedEnvironment): - - def setUp(self): - self.datafile = os.path.join('setuptools', 'tests', - 'svn_data', "dummy.zip") - self.dataname = "dummy" - super(TestDummyOutput, self).setUp() - - def _run(self): - code, data = environment.run_setup_py(["sdist"], - pypath=self.old_cwd, - data_stream=0) - if code: - info = "DIR: " + os.path.abspath('.') - info += "\n SDIST RETURNED: %i\n\n" % code - info += data - raise AssertionError(info) - - datalines = data.splitlines() - - possible = ( - "running sdist", - "running egg_info", - "creating dummy\.egg-info", - "writing dummy\.egg-info", - "writing top-level names to dummy\.egg-info", - "writing dependency_links to dummy\.egg-info", - "writing manifest file 'dummy\.egg-info", - "reading manifest file 'dummy\.egg-info", - "reading manifest template 'MANIFEST\.in'", - "writing manifest file 'dummy\.egg-info", - "creating dummy-0.1.1", - "making hard links in dummy-0\.1\.1", - "copying files to dummy-0\.1\.1", - "copying \S+ -> dummy-0\.1\.1", - "copying dummy", - "copying dummy\.egg-info", - "hard linking \S+ -> dummy-0\.1\.1", - "hard linking dummy", - "hard linking dummy\.egg-info", - "Writing dummy-0\.1\.1", - "creating dist", - "creating 'dist", - "Creating tar archive", - "running check", - "adding 'dummy-0\.1\.1", - "tar .+ dist/dummy-0\.1\.1\.tar dummy-0\.1\.1", - "gzip .+ dist/dummy-0\.1\.1\.tar", - "removing 'dummy-0\.1\.1' \\(and everything under it\\)", - ) - - print(" DIR: " + os.path.abspath('.')) - for line in datalines: - found = False - for pattern in possible: - if re.match(pattern, line): - print(" READ: " + line) - found = True - break - if not found: - raise AssertionError("Unexpexected: %s\n-in-\n%s" - % (line, data)) - - return data - - def test_sources(self): - self._run() - - -class TestSvn(environment.ZippedEnvironment): - - def setUp(self): - version = svn_utils.SvnInfo.get_svn_version() - if not version: # None or Empty - return - - self.base_version = tuple([int(x) for x in version.split('.')][:2]) - - if not self.base_version: - raise ValueError('No SVN tools installed') - elif self.base_version < (1, 3): - raise ValueError('Insufficient SVN Version %s' % version) - elif self.base_version >= (1, 9): - # trying the latest version - self.base_version = (1, 8) - - self.dataname = "svn%i%i_example" % self.base_version - self.datafile = os.path.join('setuptools', 'tests', - 'svn_data', self.dataname + ".zip") - super(TestSvn, self).setUp() - - @skipIf(not test_svn._svn_check, "No SVN to text, in the first place") - def test_walksvn(self): - if self.base_version >= (1, 6): - folder2 = 'third party2' - folder3 = 'third party3' - else: - folder2 = 'third_party2' - folder3 = 'third_party3' - - # TODO is this right - expected = set([ - os.path.join('a file'), - os.path.join(folder2, 'Changes.txt'), - os.path.join(folder2, 'MD5SUMS'), - os.path.join(folder2, 'README.txt'), - os.path.join(folder3, 'Changes.txt'), - os.path.join(folder3, 'MD5SUMS'), - os.path.join(folder3, 'README.txt'), - os.path.join(folder3, 'TODO.txt'), - os.path.join(folder3, 'fin'), - os.path.join('third_party', 'README.txt'), - os.path.join('folder', folder2, 'Changes.txt'), - os.path.join('folder', folder2, 'MD5SUMS'), - os.path.join('folder', folder2, 'WatashiNiYomimasu.txt'), - os.path.join('folder', folder3, 'Changes.txt'), - os.path.join('folder', folder3, 'fin'), - os.path.join('folder', folder3, 'MD5SUMS'), - os.path.join('folder', folder3, 'oops'), - os.path.join('folder', folder3, 'WatashiNiYomimasu.txt'), - os.path.join('folder', folder3, 'ZuMachen.txt'), - os.path.join('folder', 'third_party', 'WatashiNiYomimasu.txt'), - os.path.join('folder', 'lalala.txt'), - os.path.join('folder', 'quest.txt'), - # The example will have a deleted file - # (or should) but shouldn't return it - ]) - self.assertEqual(set(x for x in walk_revctrl()), expected) - - -def test_suite(): - return unittest.defaultTestLoader.loadTestsFromName(__name__) + filename not in cmd.filelist.files + + +def test_default_revctrl(): + """ + When _default_revctrl was removed from the `setuptools.command.sdist` + module in 10.0, it broke some systems which keep an old install of + setuptools (Distribute) around. Those old versions require that the + setuptools package continue to implement that interface, so this + function provides that interface, stubbed. See #320 for details. + + This interface must be maintained until Ubuntu 12.04 is no longer + supported (by Setuptools). + """ + ep_def = 'svn_cvs = setuptools.command.sdist:_default_revctrl' + ep = pkg_resources.EntryPoint.parse(ep_def) + res = ep._load() + assert hasattr(res, '__iter__') diff --git a/setuptools/tests/test_svn.py b/setuptools/tests/test_svn.py deleted file mode 100644 index 0e6c3e95..00000000 --- a/setuptools/tests/test_svn.py +++ /dev/null @@ -1,246 +0,0 @@ -# -*- coding: utf-8 -*- -"""svn tests""" - -import io -import os -import subprocess -import sys -import unittest - -import six - -from setuptools.tests import environment -from setuptools import svn_utils -from setuptools.tests.py26compat import skipIf - - -def _do_svn_check(): - try: - subprocess.check_call(["svn", "--version"], - shell=(sys.platform == 'win32')) - return True - except (OSError, subprocess.CalledProcessError): - return False -_svn_check = _do_svn_check() - - -class TestSvnVersion(unittest.TestCase): - - def test_no_svn_found(self): - path_variable = None - for env in os.environ: - if env.lower() == 'path': - path_variable = env - - if path_variable is None: - try: - self.skipTest('Cannot figure out how to modify path') - except AttributeError: # PY26 doesn't have this - return - - old_path = os.environ[path_variable] - os.environ[path_variable] = '' - try: - version = svn_utils.SvnInfo.get_svn_version() - self.assertEqual(version, '') - finally: - os.environ[path_variable] = old_path - - @skipIf(not _svn_check, "No SVN to text, in the first place") - def test_svn_should_exist(self): - version = svn_utils.SvnInfo.get_svn_version() - self.assertNotEqual(version, '') - -def _read_utf8_file(path): - fileobj = None - try: - fileobj = io.open(path, 'r', encoding='utf-8') - data = fileobj.read() - return data - finally: - if fileobj: - fileobj.close() - - -class ParserInfoXML(unittest.TestCase): - - def parse_tester(self, svn_name, ext_spaces): - path = os.path.join('setuptools', 'tests', - 'svn_data', svn_name + '_info.xml') - #Remember these are pre-generated to test XML parsing - # so these paths might not valid on your system - example_base = "%s_example" % svn_name - - data = _read_utf8_file(path) - - expected = set([ - ("\\".join((example_base, 'a file')), 'file'), - ("\\".join((example_base, 'folder')), 'dir'), - ("\\".join((example_base, 'folder', 'lalala.txt')), 'file'), - ("\\".join((example_base, 'folder', 'quest.txt')), 'file'), - ]) - self.assertEqual(set(x for x in svn_utils.parse_dir_entries(data)), - expected) - - def test_svn13(self): - self.parse_tester('svn13', False) - - def test_svn14(self): - self.parse_tester('svn14', False) - - def test_svn15(self): - self.parse_tester('svn15', False) - - def test_svn16(self): - self.parse_tester('svn16', True) - - def test_svn17(self): - self.parse_tester('svn17', True) - - def test_svn18(self): - self.parse_tester('svn18', True) - -class ParserExternalXML(unittest.TestCase): - - def parse_tester(self, svn_name, ext_spaces): - path = os.path.join('setuptools', 'tests', - 'svn_data', svn_name + '_ext_list.xml') - example_base = svn_name + '_example' - data = _read_utf8_file(path) - - if ext_spaces: - folder2 = 'third party2' - folder3 = 'third party3' - else: - folder2 = 'third_party2' - folder3 = 'third_party3' - - expected = set([ - os.sep.join((example_base, folder2)), - os.sep.join((example_base, folder3)), - # folder is third_party大介 - os.sep.join((example_base, - six.text_type('third_party') + - six.unichr(0x5927) + six.unichr(0x4ecb))), - os.sep.join((example_base, 'folder', folder2)), - os.sep.join((example_base, 'folder', folder3)), - os.sep.join((example_base, 'folder', - six.text_type('third_party') + - six.unichr(0x5927) + six.unichr(0x4ecb))), - ]) - - expected = set(os.path.normpath(x) for x in expected) - dir_base = os.sep.join(('C:', 'development', 'svn_example')) - self.assertEqual(set(x for x - in svn_utils.parse_externals_xml(data, dir_base)), expected) - - def test_svn15(self): - self.parse_tester('svn15', False) - - def test_svn16(self): - self.parse_tester('svn16', True) - - def test_svn17(self): - self.parse_tester('svn17', True) - - def test_svn18(self): - self.parse_tester('svn18', True) - - -class ParseExternal(unittest.TestCase): - - def parse_tester(self, svn_name, ext_spaces): - path = os.path.join('setuptools', 'tests', - 'svn_data', svn_name + '_ext_list.txt') - data = _read_utf8_file(path) - - if ext_spaces: - expected = set(['third party2', 'third party3', - 'third party3b', 'third_party']) - else: - expected = set(['third_party2', 'third_party3', 'third_party']) - - self.assertEqual(set(x for x in svn_utils.parse_external_prop(data)), - expected) - - def test_svn13(self): - self.parse_tester('svn13', False) - - def test_svn14(self): - self.parse_tester('svn14', False) - - def test_svn15(self): - self.parse_tester('svn15', False) - - def test_svn16(self): - self.parse_tester('svn16', True) - - def test_svn17(self): - self.parse_tester('svn17', True) - - def test_svn18(self): - self.parse_tester('svn18', True) - - -class TestSvn(environment.ZippedEnvironment): - - def setUp(self): - version = svn_utils.SvnInfo.get_svn_version() - if not version: # empty or null - self.dataname = None - self.datafile = None - return - - self.base_version = tuple([int(x) for x in version.split('.')[:2]]) - - if self.base_version < (1,3): - raise ValueError('Insufficient SVN Version %s' % version) - elif self.base_version >= (1,9): - #trying the latest version - self.base_version = (1,8) - - self.dataname = "svn%i%i_example" % self.base_version - self.datafile = os.path.join('setuptools', 'tests', - 'svn_data', self.dataname + ".zip") - super(TestSvn, self).setUp() - - @skipIf(not _svn_check, "No SVN to text, in the first place") - def test_revision(self): - rev = svn_utils.SvnInfo.load('.').get_revision() - self.assertEqual(rev, 6) - - @skipIf(not _svn_check, "No SVN to text, in the first place") - def test_entries(self): - expected = set([ - (os.path.join('a file'), 'file'), - (os.path.join('folder'), 'dir'), - (os.path.join('folder', 'lalala.txt'), 'file'), - (os.path.join('folder', 'quest.txt'), 'file'), - #The example will have a deleted file (or should) - #but shouldn't return it - ]) - info = svn_utils.SvnInfo.load('.') - self.assertEqual(set(x for x in info.entries), expected) - - @skipIf(not _svn_check, "No SVN to text, in the first place") - def test_externals(self): - if self.base_version >= (1,6): - folder2 = 'third party2' - folder3 = 'third party3' - else: - folder2 = 'third_party2' - folder3 = 'third_party3' - - expected = set([ - os.path.join(folder2), - os.path.join(folder3), - os.path.join('third_party'), - os.path.join('folder', folder2), - os.path.join('folder', folder3), - os.path.join('folder', 'third_party'), - ]) - info = svn_utils.SvnInfo.load('.') - self.assertEqual(set([x for x in info.externals]), expected) - -def test_suite(): - return unittest.defaultTestLoader.loadTestsFromName(__name__) diff --git a/setuptools/tests/test_test.py b/setuptools/tests/test_test.py index 67df14e5..6587dc40 100644 --- a/setuptools/tests/test_test.py +++ b/setuptools/tests/test_test.py @@ -1,127 +1,93 @@ # -*- coding: UTF-8 -*- -"""develop tests -""" +from __future__ import unicode_literals + import os -import shutil import site -import sys -import tempfile -import unittest from distutils.errors import DistutilsError import six +import pytest from setuptools.command.test import test -from setuptools.command import easy_install as easy_install_pkg from setuptools.dist import Distribution -SETUP_PY = """\ -from setuptools import setup - -setup(name='foo', - packages=['name', 'name.space', 'name.space.tests'], - namespace_packages=['name'], - test_suite='name.space.tests.test_suite', -) -""" - -NS_INIT = """# -*- coding: Latin-1 -*- -# Söme Arbiträry Ünicode to test Issüé 310 -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - from pkgutil import extend_path - __path__ = extend_path(__path__, __name__) -""" -# Make sure this is Latin-1 binary, before writing: -if six.PY2: - NS_INIT = NS_INIT.decode('UTF-8') -NS_INIT = NS_INIT.encode('Latin-1') - -TEST_PY = """import unittest - -class TestTest(unittest.TestCase): - def test_test(self): - print "Foo" # Should fail under Python 3 unless 2to3 is used +from .textwrap import DALS +from . import contexts + +SETUP_PY = DALS(""" + from setuptools import setup + + setup(name='foo', + packages=['name', 'name.space', 'name.space.tests'], + namespace_packages=['name'], + test_suite='name.space.tests.test_suite', + ) + """) + +NS_INIT = DALS(""" + # -*- coding: Latin-1 -*- + # Söme Arbiträry Ünicode to test Distribute Issüé 310 + try: + __import__('pkg_resources').declare_namespace(__name__) + except ImportError: + from pkgutil import extend_path + __path__ = extend_path(__path__, __name__) + """) + +TEST_PY = DALS(""" + import unittest + + class TestTest(unittest.TestCase): + def test_test(self): + print "Foo" # Should fail under Python 3 unless 2to3 is used -test_suite = unittest.makeSuite(TestTest) -""" + test_suite = unittest.makeSuite(TestTest) + """) -class TestTestTest(unittest.TestCase): - def setUp(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix'): - return +@pytest.fixture +def sample_test(tmpdir_cwd): + os.makedirs('name/space/tests') - # Directory structure - self.dir = tempfile.mkdtemp() - os.mkdir(os.path.join(self.dir, 'name')) - os.mkdir(os.path.join(self.dir, 'name', 'space')) - os.mkdir(os.path.join(self.dir, 'name', 'space', 'tests')) - # setup.py - setup = os.path.join(self.dir, 'setup.py') - f = open(setup, 'wt') + # setup.py + with open('setup.py', 'wt') as f: f.write(SETUP_PY) - f.close() - self.old_cwd = os.getcwd() - # name/__init__.py - init = os.path.join(self.dir, 'name', '__init__.py') - f = open(init, 'wb') - f.write(NS_INIT) - f.close() - # name/space/__init__.py - init = os.path.join(self.dir, 'name', 'space', '__init__.py') - f = open(init, 'wt') + + # name/__init__.py + with open('name/__init__.py', 'wb') as f: + f.write(NS_INIT.encode('Latin-1')) + + # name/space/__init__.py + with open('name/space/__init__.py', 'wt') as f: f.write('#empty\n') - f.close() - # name/space/tests/__init__.py - init = os.path.join(self.dir, 'name', 'space', 'tests', '__init__.py') - f = open(init, 'wt') - f.write(TEST_PY) - f.close() - os.chdir(self.dir) - self.old_base = site.USER_BASE - site.USER_BASE = tempfile.mkdtemp() - self.old_site = site.USER_SITE - site.USER_SITE = tempfile.mkdtemp() + # name/space/tests/__init__.py + with open('name/space/tests/__init__.py', 'wt') as f: + f.write(TEST_PY) - def tearDown(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix'): - return - os.chdir(self.old_cwd) - shutil.rmtree(self.dir) - shutil.rmtree(site.USER_BASE) - shutil.rmtree(site.USER_SITE) - site.USER_BASE = self.old_base - site.USER_SITE = self.old_site +@pytest.mark.skipif('hasattr(sys, "real_prefix")') +@pytest.mark.usefixtures('user_override') +@pytest.mark.usefixtures('sample_test') +class TestTestTest: def test_test(self): - if sys.version < "2.6" or hasattr(sys, 'real_prefix'): - return - - dist = Distribution(dict( + params = dict( name='foo', packages=['name', 'name.space', 'name.space.tests'], namespace_packages=['name'], test_suite='name.space.tests.test_suite', use_2to3=True, - )) + ) + dist = Distribution(params) dist.script_name = 'setup.py' cmd = test(dist) cmd.user = 1 cmd.ensure_finalized() cmd.install_dir = site.USER_SITE cmd.user = 1 - old_stdout = sys.stdout - sys.stdout = six.StringIO() - try: - try: # try/except/finally doesn't work in Python 2.4, so we need nested try-statements. + with contexts.quiet(): + # The test runner calls sys.exit + with contexts.suppress_exceptions(SystemExit): cmd.run() - except SystemExit: # The test runner calls sys.exit, stop that making an error. - pass - finally: - sys.stdout = old_stdout - diff --git a/setuptools/tests/test_upload_docs.py b/setuptools/tests/test_upload_docs.py index 769f16cc..cc71cadb 100644 --- a/setuptools/tests/test_upload_docs.py +++ b/setuptools/tests/test_upload_docs.py @@ -1,72 +1,59 @@ -"""build_ext tests -""" -import sys, os, shutil, tempfile, unittest, site, zipfile +import os +import zipfile +import contextlib + +import pytest + from setuptools.command.upload_docs import upload_docs from setuptools.dist import Distribution -SETUP_PY = """\ -from setuptools import setup +from .textwrap import DALS +from . import contexts + -setup(name='foo') -""" +SETUP_PY = DALS( + """ + from setuptools import setup -class TestUploadDocsTest(unittest.TestCase): - def setUp(self): - self.dir = tempfile.mkdtemp() - setup = os.path.join(self.dir, 'setup.py') - f = open(setup, 'w') + setup(name='foo') + """) + + +@pytest.fixture +def sample_project(tmpdir_cwd): + # setup.py + with open('setup.py', 'wt') as f: f.write(SETUP_PY) - f.close() - self.old_cwd = os.getcwd() - os.chdir(self.dir) - self.upload_dir = os.path.join(self.dir, 'build') - os.mkdir(self.upload_dir) + os.mkdir('build') - # A test document. - f = open(os.path.join(self.upload_dir, 'index.html'), 'w') + # A test document. + with open('build/index.html', 'w') as f: f.write("Hello world.") - f.close() - - # An empty folder. - os.mkdir(os.path.join(self.upload_dir, 'empty')) - - if sys.version >= "2.6": - self.old_base = site.USER_BASE - site.USER_BASE = upload_docs.USER_BASE = tempfile.mkdtemp() - self.old_site = site.USER_SITE - site.USER_SITE = upload_docs.USER_SITE = tempfile.mkdtemp() - - def tearDown(self): - os.chdir(self.old_cwd) - shutil.rmtree(self.dir) - if sys.version >= "2.6": - shutil.rmtree(site.USER_BASE) - shutil.rmtree(site.USER_SITE) - site.USER_BASE = self.old_base - site.USER_SITE = self.old_site + + # An empty folder. + os.mkdir('build/empty') + + +@pytest.mark.usefixtures('sample_project') +@pytest.mark.usefixtures('user_override') +class TestUploadDocsTest: def test_create_zipfile(self): - # Test to make sure zipfile creation handles common cases. - # This explicitly includes a folder containing an empty folder. + """ + Ensure zipfile creation handles common cases, including a folder + containing an empty folder. + """ dist = Distribution() cmd = upload_docs(dist) - cmd.upload_dir = self.upload_dir - cmd.target_dir = self.upload_dir - tmp_dir = tempfile.mkdtemp() - tmp_file = os.path.join(tmp_dir, 'foo.zip') - try: + cmd.target_dir = cmd.upload_dir = 'build' + with contexts.tempdir() as tmp_dir: + tmp_file = os.path.join(tmp_dir, 'foo.zip') zip_file = cmd.create_zipfile(tmp_file) assert zipfile.is_zipfile(tmp_file) - zip_file = zipfile.ZipFile(tmp_file) # woh... - - assert zip_file.namelist() == ['index.html'] - - zip_file.close() - finally: - shutil.rmtree(tmp_dir) - + with contextlib.closing(zipfile.ZipFile(tmp_file)) as zip_file: + assert zip_file.namelist() == ['index.html'] diff --git a/setuptools/tests/test_windows_wrappers.py b/setuptools/tests/test_windows_wrappers.py new file mode 100644 index 00000000..5b14d07b --- /dev/null +++ b/setuptools/tests/test_windows_wrappers.py @@ -0,0 +1,183 @@ +""" +Python Script Wrapper for Windows +================================= + +setuptools includes wrappers for Python scripts that allows them to be +executed like regular windows programs. There are 2 wrappers, one +for command-line programs, cli.exe, and one for graphical programs, +gui.exe. These programs are almost identical, function pretty much +the same way, and are generated from the same source file. The +wrapper programs are used by copying them to the directory containing +the script they are to wrap and with the same name as the script they +are to wrap. +""" + +from __future__ import absolute_import + +import sys +import textwrap +import subprocess + +import pytest + +from setuptools.command.easy_install import nt_quote_arg +import pkg_resources + + +pytestmark = pytest.mark.skipif(sys.platform != 'win32', reason="Windows only") + + +class WrapperTester: + + @classmethod + def prep_script(cls, template): + python_exe = nt_quote_arg(sys.executable) + return template % locals() + + @classmethod + def create_script(cls, tmpdir): + """ + Create a simple script, foo-script.py + + Note that the script starts with a Unix-style '#!' line saying which + Python executable to run. The wrapper will use this line to find the + correct Python executable. + """ + + script = cls.prep_script(cls.script_tmpl) + + with (tmpdir / cls.script_name).open('w') as f: + f.write(script) + + # also copy cli.exe to the sample directory + with (tmpdir / cls.wrapper_name).open('wb') as f: + w = pkg_resources.resource_string('setuptools', cls.wrapper_source) + f.write(w) + + +class TestCLI(WrapperTester): + script_name = 'foo-script.py' + wrapper_source = 'cli-32.exe' + wrapper_name = 'foo.exe' + script_tmpl = textwrap.dedent(""" + #!%(python_exe)s + import sys + input = repr(sys.stdin.read()) + print(sys.argv[0][-14:]) + print(sys.argv[1:]) + print(input) + if __debug__: + print('non-optimized') + """).lstrip() + + def test_basic(self, tmpdir): + """ + When the copy of cli.exe, foo.exe in this example, runs, it examines + the path name it was run with and computes a Python script path name + by removing the '.exe' suffix and adding the '-script.py' suffix. (For + GUI programs, the suffix '-script.pyw' is added.) This is why we + named out script the way we did. Now we can run out script by running + the wrapper: + + This example was a little pathological in that it exercised windows + (MS C runtime) quoting rules: + + - Strings containing spaces are surrounded by double quotes. + + - Double quotes in strings need to be escaped by preceding them with + back slashes. + + - One or more backslashes preceding double quotes need to be escaped + by preceding each of them with back slashes. + """ + self.create_script(tmpdir) + cmd = [ + str(tmpdir / 'foo.exe'), + 'arg1', + 'arg 2', + 'arg "2\\"', + 'arg 4\\', + 'arg5 a\\\\b', + ] + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) + stdout, stderr = proc.communicate('hello\nworld\n'.encode('ascii')) + actual = stdout.decode('ascii').replace('\r\n', '\n') + expected = textwrap.dedent(r""" + \foo-script.py + ['arg1', 'arg 2', 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b'] + 'hello\nworld\n' + non-optimized + """).lstrip() + assert actual == expected + + def test_with_options(self, tmpdir): + """ + Specifying Python Command-line Options + -------------------------------------- + + You can specify a single argument on the '#!' line. This can be used + to specify Python options like -O, to run in optimized mode or -i + to start the interactive interpreter. You can combine multiple + options as usual. For example, to run in optimized mode and + enter the interpreter after running the script, you could use -Oi: + """ + self.create_script(tmpdir) + tmpl = textwrap.dedent(""" + #!%(python_exe)s -Oi + import sys + input = repr(sys.stdin.read()) + print(sys.argv[0][-14:]) + print(sys.argv[1:]) + print(input) + if __debug__: + print('non-optimized') + sys.ps1 = '---' + """).lstrip() + with (tmpdir / 'foo-script.py').open('w') as f: + f.write(self.prep_script(tmpl)) + cmd = [str(tmpdir / 'foo.exe')] + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, stderr = proc.communicate() + actual = stdout.decode('ascii').replace('\r\n', '\n') + expected = textwrap.dedent(r""" + \foo-script.py + [] + '' + --- + """).lstrip() + assert actual == expected + + +class TestGUI(WrapperTester): + """ + Testing the GUI Version + ----------------------- + """ + script_name = 'bar-script.pyw' + wrapper_source = 'gui-32.exe' + wrapper_name = 'bar.exe' + + script_tmpl = textwrap.dedent(""" + #!%(python_exe)s + import sys + f = open(sys.argv[1], 'wb') + bytes_written = f.write(repr(sys.argv[2]).encode('utf-8')) + f.close() + """).strip() + + def test_basic(self, tmpdir): + """Test the GUI version with the simple scipt, bar-script.py""" + self.create_script(tmpdir) + + cmd = [ + str(tmpdir / 'bar.exe'), + str(tmpdir / 'test_output.txt'), + 'Test Argument', + ] + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, stderr = proc.communicate() + assert not stdout + assert not stderr + with (tmpdir / 'test_output.txt').open('rb') as f_out: + actual = f_out.read().decode('ascii') + assert actual == repr('Test Argument') diff --git a/setuptools/tests/textwrap.py b/setuptools/tests/textwrap.py new file mode 100644 index 00000000..5cd9e5bc --- /dev/null +++ b/setuptools/tests/textwrap.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import + +import textwrap + + +def DALS(s): + "dedent and left-strip" + return textwrap.dedent(s).lstrip() diff --git a/setuptools/tests/win_script_wrapper.txt b/setuptools/tests/win_script_wrapper.txt deleted file mode 100644 index b3a52e0a..00000000 --- a/setuptools/tests/win_script_wrapper.txt +++ /dev/null @@ -1,154 +0,0 @@ -Python Script Wrapper for Windows -================================= - -setuptools includes wrappers for Python scripts that allows them to be -executed like regular windows programs. There are 2 wrappers, once -for command-line programs, cli.exe, and one for graphical programs, -gui.exe. These programs are almost identical, function pretty much -the same way, and are generated from the same source file. The -wrapper programs are used by copying them to the directory containing -the script they are to wrap and with the same name as the script they -are to wrap. In the rest of this document, we'll give an example that -will illustrate this. - -Let's create a simple script, foo-script.py: - - >>> import os, sys, tempfile - >>> from setuptools.command.easy_install import nt_quote_arg - >>> sample_directory = tempfile.mkdtemp() - >>> f = open(os.path.join(sample_directory, 'foo-script.py'), 'w') - >>> bytes_written = f.write( - ... """#!%(python_exe)s - ... import sys - ... input = repr(sys.stdin.read()) - ... print(sys.argv[0][-14:]) - ... print(sys.argv[1:]) - ... print(input) - ... if __debug__: - ... print('non-optimized') - ... """ % dict(python_exe=nt_quote_arg(sys.executable))) - >>> f.close() - -Note that the script starts with a Unix-style '#!' line saying which -Python executable to run. The wrapper will use this to find the -correct Python executable. - -We'll also copy cli.exe to the sample-directory with the name foo.exe: - - >>> import pkg_resources - >>> f = open(os.path.join(sample_directory, 'foo.exe'), 'wb') - >>> bytes_written = f.write( - ... pkg_resources.resource_string('setuptools', 'cli-32.exe') - ... ) - >>> f.close() - -When the copy of cli.exe, foo.exe in this example, runs, it examines -the path name it was run with and computes a Python script path name -by removing the '.exe' suffix and adding the '-script.py' suffix. (For -GUI programs, the suffix '-script-pyw' is added.) This is why we -named out script the way we did. Now we can run out script by running -the wrapper: - - >>> import subprocess - >>> cmd = [os.path.join(sample_directory, 'foo.exe'), 'arg1', 'arg 2', - ... 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b'] - >>> proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) - >>> stdout, stderr = proc.communicate('hello\nworld\n'.encode('ascii')) - >>> bytes = sys.stdout.write(stdout.decode('ascii').replace('\r\n', '\n')) - \foo-script.py - ['arg1', 'arg 2', 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b'] - 'hello\nworld\n' - non-optimized - -This example was a little pathological in that it exercised windows -(MS C runtime) quoting rules: - -- Strings containing spaces are surrounded by double quotes. - -- Double quotes in strings need to be escaped by preceding them with - back slashes. - -- One or more backslashes preceding double quotes need to be escaped - by preceding each of them with back slashes. - - -Specifying Python Command-line Options --------------------------------------- - -You can specify a single argument on the '#!' line. This can be used -to specify Python options like -O, to run in optimized mode or -i -to start the interactive interpreter. You can combine multiple -options as usual. For example, to run in optimized mode and -enter the interpreter after running the script, you could use -Oi: - - >>> f = open(os.path.join(sample_directory, 'foo-script.py'), 'w') - >>> bytes_written = f.write( - ... """#!%(python_exe)s -Oi - ... import sys - ... input = repr(sys.stdin.read()) - ... print(sys.argv[0][-14:]) - ... print(sys.argv[1:]) - ... print(input) - ... if __debug__: - ... print('non-optimized') - ... sys.ps1 = '---' - ... """ % dict(python_exe=nt_quote_arg(sys.executable))) - >>> f.close() - >>> cmd = [os.path.join(sample_directory, 'foo.exe')] - >>> proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) - >>> stdout, stderr = proc.communicate() - >>> bytes = sys.stdout.write(stdout.decode('ascii').replace('\r\n', '\n')) - \foo-script.py - [] - '' - --- - -Testing the GUI Version ------------------------ - -Now let's test the GUI version with the simple scipt, bar-script.py: - - >>> import os, sys, tempfile - >>> from setuptools.command.easy_install import nt_quote_arg - >>> sample_directory = tempfile.mkdtemp() - >>> f = open(os.path.join(sample_directory, 'bar-script.pyw'), 'w') - >>> bytes_written = f.write( - ... """#!%(python_exe)s - ... import sys - ... f = open(sys.argv[1], 'wb') - ... bytes_written = f.write(repr(sys.argv[2]).encode('utf-8')) - ... f.close() - ... """ % dict(python_exe=nt_quote_arg(sys.executable))) - >>> f.close() - -We'll also copy gui.exe to the sample-directory with the name bar.exe: - - >>> import pkg_resources - >>> f = open(os.path.join(sample_directory, 'bar.exe'), 'wb') - >>> bytes_written = f.write( - ... pkg_resources.resource_string('setuptools', 'gui-32.exe') - ... ) - >>> f.close() - -Finally, we'll run the script and check the result: - - >>> cmd = [ - ... os.path.join(sample_directory, 'bar.exe'), - ... os.path.join(sample_directory, 'test_output.txt'), - ... 'Test Argument', - ... ] - >>> proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) - >>> stdout, stderr = proc.communicate() - >>> print(stdout.decode('ascii')) - <BLANKLINE> - >>> f_out = open(os.path.join(sample_directory, 'test_output.txt'), 'rb') - >>> print(f_out.read().decode('ascii')) - 'Test Argument' - >>> f_out.close() - - -We're done with the sample_directory: - - >>> import shutil - >>> shutil.rmtree(sample_directory) - diff --git a/setuptools/version.py b/setuptools/version.py index 0ab618ea..addf63a6 100644 --- a/setuptools/version.py +++ b/setuptools/version.py @@ -1 +1 @@ -__version__ = '7.1' +__version__ = '10.2.2' |