diff options
Diffstat (limited to 'setuptools')
| -rwxr-xr-x | setuptools/package_index.py | 73 | ||||
| -rw-r--r-- | setuptools/ssl_support.py | 86 | ||||
| -rw-r--r-- | setuptools/svn_utils.py | 107 | ||||
| -rw-r--r-- | setuptools/tests/environment.py | 56 | ||||
| -rw-r--r-- | setuptools/tests/svn17_example.zip | bin | 19342 -> 0 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy.zip | bin | 0 -> 1771 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy13.zip | bin | 0 -> 9243 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy14.zip | bin | 0 -> 7496 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy15.zip | bin | 0 -> 7506 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy16.zip | bin | 0 -> 7155 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy17.zip | bin | 0 -> 7512 bytes | |||
| -rw-r--r-- | setuptools/tests/svn_data/dummy18.zip | bin | 0 -> 7639 bytes | |||
| -rw-r--r-- | setuptools/tests/test_egg_info.py | 96 | ||||
| -rw-r--r-- | setuptools/tests/test_sdist.py | 89 | ||||
| -rw-r--r-- | setuptools/tests/test_svn.py | 21 | ||||
| -rw-r--r-- | setuptools/version.py | 2 |
16 files changed, 416 insertions, 114 deletions
diff --git a/setuptools/package_index.py b/setuptools/package_index.py index 94873620..4a3f49c7 100755 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -17,7 +17,8 @@ from distutils.errors import DistutilsError from setuptools.compat import (urllib2, httplib, StringIO, HTTPError, urlparse, urlunparse, unquote, splituser, url2pathname, name2codepoint, - unichr, urljoin, urlsplit, urlunsplit) + unichr, urljoin, urlsplit, urlunsplit, + ConfigParser) from setuptools.compat import filterfalse from fnmatch import translate from setuptools.py24compat import hashlib @@ -907,8 +908,13 @@ def _encode_auth(auth): """ A function compatible with Python 2.3-3.3 that will encode auth from a URL suitable for an HTTP header. - >>> _encode_auth('username%3Apassword') - u'dXNlcm5hbWU6cGFzc3dvcmQ=' + >>> str(_encode_auth('username%3Apassword')) + 'dXNlcm5hbWU6cGFzc3dvcmQ=' + + Long auth strings should not cause a newline to be inserted. + >>> long_auth = 'username:' + 'password'*10 + >>> chr(10) in str(_encode_auth(long_auth)) + False """ auth_s = unquote(auth) # convert to bytes @@ -920,6 +926,60 @@ def _encode_auth(auth): # strip the trailing carriage return return encoded.replace('\n','') +class Credential(object): + """ + A username/password pair. Use like a namedtuple. + """ + def __init__(self, username, password): + self.username = username + self.password = password + + def __iter__(self): + yield self.username + yield self.password + + def __str__(self): + return '%(username)s:%(password)s' % vars(self) + +class PyPIConfig(ConfigParser.ConfigParser): + + def __init__(self): + """ + Load from ~/.pypirc + """ + defaults = dict.fromkeys(['username', 'password', 'repository'], '') + ConfigParser.ConfigParser.__init__(self, defaults) + + rc = os.path.join(os.path.expanduser('~'), '.pypirc') + if os.path.exists(rc): + self.read(rc) + + @property + def creds_by_repository(self): + sections_with_repositories = [ + section for section in self.sections() + if self.get(section, 'repository').strip() + ] + + return dict(map(self._get_repo_cred, sections_with_repositories)) + + def _get_repo_cred(self, section): + repo = self.get(section, 'repository').strip() + return repo, Credential( + self.get(section, 'username').strip(), + self.get(section, 'password').strip(), + ) + + def find_credential(self, url): + """ + If the URL indicated appears to be a repository defined in this + config, return the credential for that repository. + """ + for repository, cred in self.creds_by_repository.items(): + if url.startswith(repository): + return cred + + def open_with_auth(url, opener=urllib2.urlopen): """Open a urllib2 request, handling HTTP authentication""" @@ -935,6 +995,13 @@ def open_with_auth(url, opener=urllib2.urlopen): else: auth = None + if not auth: + cred = PyPIConfig().find_credential(url) + if cred: + auth = str(cred) + info = cred.username, url + log.info('Authenticating as %s for %s (from .pypirc)' % info) + if auth: auth = "Basic " + _encode_auth(auth) new_url = urlunparse((scheme,host,path,params,query,frag)) diff --git a/setuptools/ssl_support.py b/setuptools/ssl_support.py index 90359b2c..346188f2 100644 --- a/setuptools/ssl_support.py +++ b/setuptools/ssl_support.py @@ -44,6 +44,7 @@ is_available = ssl is not None and object not in (HTTPSHandler, HTTPSConnection) try: from socket import create_connection except ImportError: + from socket import error _GLOBAL_DEFAULT_TIMEOUT = getattr(socket, '_GLOBAL_DEFAULT_TIMEOUT', object()) def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None): @@ -85,33 +86,74 @@ except ImportError: try: from ssl import CertificateError, match_hostname except ImportError: + try: + from backports.ssl_match_hostname import CertificateError + from backports.ssl_match_hostname import match_hostname + except ImportError: + CertificateError = None + match_hostname = None + +if not CertificateError: class CertificateError(ValueError): pass - def _dnsname_to_pat(dn, max_wildcards=1): +if not match_hostname: + def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + http://tools.ietf.org/html/rfc6125#section-6.4.3 + """ pats = [] - for frag in dn.split(r'.'): - if frag.count('*') > max_wildcards: - # Issue #17980: avoid denials of service by refusing more - # than one wildcard per fragment. A survery of established - # policy among SSL implementations showed it to be a - # reasonable choice. - raise CertificateError( - "too many wildcards in certificate DNS name: " + repr(dn)) - if frag == '*': - # When '*' is a fragment by itself, it matches a non-empty dotless - # fragment. - pats.append('[^.]+') - else: - # Otherwise, '*' matches any dotless fragment. - frag = re.escape(frag) - pats.append(frag.replace(r'\*', '[^.]*')) - return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + if not dn: + return False + + # Ported from python3-syntax: + # leftmost, *remainder = dn.split(r'.') + parts = dn.split(r'.') + leftmost = parts[0] + remainder = parts[1:] + + wildcards = leftmost.count('*') + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn)) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + elif leftmost.startswith('xn--') or hostname.startswith('xn--'): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + return pat.match(hostname) def match_hostname(cert, hostname): """Verify that *cert* (in decoded format as returned by - SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules - are mostly followed, but IP addresses are not accepted for *hostname*. + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. CertificateError is raised on failure. On success, the function returns nothing. @@ -122,7 +164,7 @@ except ImportError: san = cert.get('subjectAltName', ()) for key, value in san: if key == 'DNS': - if _dnsname_to_pat(value).match(hostname): + if _dnsname_match(value, hostname): return dnsnames.append(value) if not dnsnames: @@ -133,7 +175,7 @@ except ImportError: # XXX according to RFC 2818, the most specific Common Name # must be used. if key == 'commonName': - if _dnsname_to_pat(value).match(hostname): + if _dnsname_match(value, hostname): return dnsnames.append(value) if len(dnsnames) > 1: diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py index 22b45cd7..224d11ea 100644 --- a/setuptools/svn_utils.py +++ b/setuptools/svn_utils.py @@ -27,18 +27,18 @@ from subprocess import Popen as _Popen, PIPE as _PIPE # python-subprocess-popen-environment-path
-def _run_command(args, stdout=_PIPE, stderr=_PIPE):
+def _run_command(args, stdout=_PIPE, stderr=_PIPE, encoding=None, stream=0):
#regarding the shell argument, see: http://bugs.python.org/issue8557
try:
- args = [fsdecode(x) for x in args]
proc = _Popen(args, stdout=stdout, stderr=stderr,
shell=(sys.platform == 'win32'))
- data = proc.communicate()[0]
+ data = proc.communicate()[stream]
except OSError:
return 1, ''
- data = consoledecode(data)
+ #doubled checked and
+ data = decode_as_string(data, encoding)
#communciate calls wait()
return proc.returncode, data
@@ -73,40 +73,28 @@ def joinpath(prefix, *suffix): return os.path.join(prefix, *suffix)
-def fsencode(path):
- "Path must be unicode or in file system encoding already"
- encoding = sys.getfilesystemencoding()
-
- if isinstance(path, unicode):
- path = path.encode()
- elif not isinstance(path, bytes):
- raise TypeError('%s is not a string or byte type'
- % type(path).__name__)
-
- #getfilessystemencoding doesn't have the mac-roman issue
- if encoding == 'utf-8' and sys.platform == 'darwin':
- path = path.decode('utf-8')
- path = unicodedata.normalize('NFD', path)
- path = path.encode('utf-8')
-
- return path
-
-
-def fsdecode(path):
- "Path must be unicode or in file system encoding already"
- encoding = sys.getfilesystemencoding()
- if isinstance(path, bytes):
- path = path.decode(encoding)
- elif not isinstance(path, unicode):
- raise TypeError('%s is not a byte type'
- % type(path).__name__)
-
- return unicodedata.normalize('NFC', path)
+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 = locale.getpreferredencoding()
-def consoledecode(text):
- encoding = locale.getpreferredencoding()
- return text.decode(encoding)
+ if not isinstance(text, unicode):
+ text = text.decode(encoding)
+
+ text = unicodedata.normalize('NFC', text)
+
+ return text
def parse_dir_entries(decoded_str):
@@ -141,6 +129,7 @@ def parse_externals_xml(decoded_str, 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))
@@ -177,6 +166,7 @@ def parse_external_prop(lines): else:
external = line[-1]
+ external = decode_as_string(external, encoding="utf-8")
externals.append(os.path.normpath(external))
return externals
@@ -214,9 +204,9 @@ class SvnInfo(object): def get_svn_version():
code, data = _run_command(['svn', '--version', '--quiet'])
if code == 0 and data:
- return unicode(data).strip()
+ return data.strip()
else:
- return unicode('')
+ return ''
#svnversion return values (previous implementations return max revision)
# 4123:4168 mixed revision working copy
@@ -229,7 +219,13 @@ class SvnInfo(object): def load(cls, dirname=''):
normdir = os.path.normpath(dirname)
code, data = _run_command(['svn', 'info', normdir])
- has_svn = os.path.isdir(os.path.join(normdir, '.svn'))
+ # Must check for some contents, as some use empty directories
+ # in testcases
+ svn_dir = os.path.join(normdir, '.svn')
+ has_svn = (os.path.isfile(os.path.join(svn_dir, 'entries')) or
+ os.path.isfile(os.path.join(svn_dir, 'dir-props')) or
+ os.path.isfile(os.path.join(svn_dir, 'dir-prop-base')))
+
svn_version = tuple(cls.get_svn_version().split('.'))
try:
@@ -239,12 +235,10 @@ class SvnInfo(object): if has_svn and (code or not base_svn_version
or base_svn_version < (1, 3)):
- log.warn('Fallback onto .svn parsing')
warnings.warn(("No SVN 1.3+ command found: falling back "
"on pre 1.7 .svn parsing"), DeprecationWarning)
return SvnFileInfo(dirname)
elif not has_svn:
- log.warn('Not SVN Repository')
return SvnInfo(dirname)
elif base_svn_version < (1, 5):
return Svn13Info(dirname)
@@ -315,7 +309,8 @@ class SvnInfo(object): class Svn13Info(SvnInfo):
def get_entries(self):
- code, data = _run_command(['svn', 'info', '-R', '--xml', self.path])
+ code, data = _run_command(['svn', 'info', '-R', '--xml', self.path],
+ encoding="utf-8")
if code:
log.debug("svn info failed")
@@ -329,10 +324,11 @@ class Svn13Info(SvnInfo): cmd = ['svn', 'propget', 'svn:externals']
result = []
for folder in self.iter_dirs():
- code, lines = _run_command(cmd + [folder])
+ 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)
@@ -344,7 +340,7 @@ class Svn13Info(SvnInfo): class Svn15Info(Svn13Info):
def get_externals(self):
cmd = ['svn', 'propget', 'svn:externals', self.path, '-R', '--xml']
- code, lines = _run_command(cmd)
+ code, lines = _run_command(cmd, encoding="utf-8")
if code:
log.debug("svn propget failed")
return []
@@ -364,6 +360,7 @@ class SvnFileInfo(SvnInfo): 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)
@@ -372,18 +369,17 @@ class SvnFileInfo(SvnInfo): yield item
def _build_entries(self):
- dirs = list()
- files = list()
+ entries = list()
+
rev = 0
for path, isfile, dir_rev in self._walk_svn(self.path):
if isfile:
- files.append(path)
+ entries.append((path, 'file'))
else:
- dirs.append(path)
+ entries.append((path, 'dir'))
rev = max(rev, dir_rev)
- self._directories = dirs
- self._entries = files
+ self._entries = entries
self._revision = rev
def get_entries(self):
@@ -397,14 +393,11 @@ class SvnFileInfo(SvnInfo): return self._revision
def get_externals(self):
- if self._directories is None:
- self._build_entries()
-
prop_files = [['.svn', 'dir-prop-base'],
['.svn', 'dir-props']]
externals = []
- for dirname in self._directories:
+ for dirname in self.iter_dirs():
prop_file = None
for rel_parts in prop_files:
filename = joinpath(dirname, *rel_parts)
@@ -413,6 +406,8 @@ class SvnFileInfo(SvnInfo): 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
@@ -423,12 +418,12 @@ def svn_finder(dirname=''): #combined externals and entries due to lack of dir_props in 1.7
info = SvnInfo.load(dirname)
for path in info.iter_files():
- yield fsencode(path)
+ yield path
for path in info.iter_externals():
sub_info = SvnInfo.load(path)
for sub_path in sub_info.iter_files():
- yield fsencode(sub_path)
+ yield sub_path
class SVNEntriesFile(object):
diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py index 7c754b8e..bd2c53d2 100644 --- a/setuptools/tests/environment.py +++ b/setuptools/tests/environment.py @@ -5,6 +5,9 @@ import tempfile import unittest import shutil import stat +import unicodedata + +from subprocess import Popen as _Popen, PIPE as _PIPE def _extract(self, member, path=None, pwd=None): @@ -25,13 +28,14 @@ def _extract_from_zip(self, name, dest_path): finally: dest_file.close() + def _extract_member(self, member, targetpath, pwd): """for zipfile py2.5 borrowed from cpython""" # build the destination pathname, replacing # forward slashes to platform specific separators. # Strip trailing path separator, unless it represents the root. if (targetpath[-1:] in (os.path.sep, os.path.altsep) - and len(os.path.splitdrive(targetpath)[1]) > 1): + and len(os.path.splitdrive(targetpath)[1]) > 1): targetpath = targetpath[:-1] # don't include leading "/" from file name if present @@ -102,3 +106,53 @@ class ZippedEnvironment(unittest.TestCase): #sigh? pass + +def _which_dirs(cmd): + result = set() + for path in os.environ.get('PATH', '').split(os.pathsep): + filename = os.path.join(path, cmd) + if os.access(filename, os.X_OK): + result.add(path) + return result + + +def run_setup_py(cmd, pypath=None, path=None, + data_stream=0, env=None): + """ + Execution command for tests, separate from those used by the + code directly to prevent accidental behavior issues + """ + if env is None: + env = dict() + for envname in os.environ: + env[envname] = os.environ[envname] + + #override the python path if needed + if pypath is not None: + env["PYTHONPATH"] = pypath + + #overide the execution path if needed + if path is not None: + env["PATH"] = path + if not env.get("PATH", ""): + env["PATH"] = _which_dirs("tar").union(_which_dirs("gzip")) + env["PATH"] = os.pathsep.join(env["PATH"]) + + cmd = [sys.executable, "setup.py"] + list(cmd) + + #regarding the shell argument, see: http://bugs.python.org/issue8557 + try: + proc = _Popen(cmd, stdout=_PIPE, stderr=_PIPE, + shell=(sys.platform == 'win32'), env=env) + + data = proc.communicate()[data_stream] + except OSError: + return 1, '' + + #decode the console string if needed + if hasattr(data, "decode"): + data = data.decode() # should use the preffered encoding + data = unicodedata.normalize('NFC', data) + + #communciate calls wait() + return proc.returncode, data diff --git a/setuptools/tests/svn17_example.zip b/setuptools/tests/svn17_example.zip Binary files differdeleted file mode 100644 index cfabd2b2..00000000 --- a/setuptools/tests/svn17_example.zip +++ /dev/null diff --git a/setuptools/tests/svn_data/dummy.zip b/setuptools/tests/svn_data/dummy.zip Binary files differnew file mode 100644 index 00000000..1347be53 --- /dev/null +++ b/setuptools/tests/svn_data/dummy.zip diff --git a/setuptools/tests/svn_data/dummy13.zip b/setuptools/tests/svn_data/dummy13.zip Binary files differnew file mode 100644 index 00000000..47764342 --- /dev/null +++ b/setuptools/tests/svn_data/dummy13.zip diff --git a/setuptools/tests/svn_data/dummy14.zip b/setuptools/tests/svn_data/dummy14.zip Binary files differnew file mode 100644 index 00000000..02ed8cf0 --- /dev/null +++ b/setuptools/tests/svn_data/dummy14.zip diff --git a/setuptools/tests/svn_data/dummy15.zip b/setuptools/tests/svn_data/dummy15.zip Binary files differnew file mode 100644 index 00000000..ed8daeeb --- /dev/null +++ b/setuptools/tests/svn_data/dummy15.zip diff --git a/setuptools/tests/svn_data/dummy16.zip b/setuptools/tests/svn_data/dummy16.zip Binary files differnew file mode 100644 index 00000000..b6e98d6c --- /dev/null +++ b/setuptools/tests/svn_data/dummy16.zip diff --git a/setuptools/tests/svn_data/dummy17.zip b/setuptools/tests/svn_data/dummy17.zip Binary files differnew file mode 100644 index 00000000..d96e1513 --- /dev/null +++ b/setuptools/tests/svn_data/dummy17.zip diff --git a/setuptools/tests/svn_data/dummy18.zip b/setuptools/tests/svn_data/dummy18.zip Binary files differnew file mode 100644 index 00000000..a7267838 --- /dev/null +++ b/setuptools/tests/svn_data/dummy18.zip diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index 7abafd71..28682dfd 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -1,3 +1,4 @@ + import os import sys import tempfile @@ -5,12 +6,15 @@ import shutil import unittest import pkg_resources +import warnings from setuptools.command import egg_info +from setuptools.tests import environment from setuptools import svn_utils 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): @@ -37,7 +41,7 @@ class TestEggInfo(unittest.TestCase): #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 version != [1, 6]: if hasattr(self, 'skipTest'): self.skipTest('') else: @@ -61,14 +65,104 @@ class TestEggInfo(unittest.TestCase): 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 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() + 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() + + def test_sources(self): + code, data = environment.run_setup_py(["sdist"], + pypath=self.old_cwd, + 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 + + +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__) diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py index 65a9f0b3..b42dcc57 100644 --- a/setuptools/tests/test_sdist.py +++ b/setuptools/tests/test_sdist.py @@ -8,6 +8,7 @@ import sys import tempfile import unittest import unicodedata +import re from setuptools.tests import environment from setuptools.compat import StringIO, unicode @@ -16,7 +17,6 @@ from setuptools.command.sdist import sdist, walk_revctrl from setuptools.command.egg_info import manifest_maker from setuptools.dist import Distribution from setuptools import svn_utils -from setuptools.svn_utils import fsencode SETUP_ATTRS = { 'name': 'sdist_test', @@ -400,6 +400,75 @@ class TestSdistTest(unittest.TestCase): self.assertTrue(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): @@ -408,11 +477,11 @@ class TestSvn(environment.ZippedEnvironment): if not self.base_version: raise ValueError('No SVN tools installed') - elif self.base_version < (1,3): + elif self.base_version < (1, 3): raise ValueError('Insufficient SVN Version %s' % version) - elif self.base_version >= (1,9): + elif self.base_version >= (1, 9): #trying the latest version - self.base_version = (1,8) + self.base_version = (1, 8) self.dataname = "svn%i%i_example" % self.base_version self.datafile = os.path.join('setuptools', 'tests', @@ -420,7 +489,7 @@ class TestSvn(environment.ZippedEnvironment): super(TestSvn, self).setUp() def test_walksvn(self): - if self.base_version >= (1,6): + if self.base_version >= (1, 6): folder2 = 'third party2' folder3 = 'third party3' else: @@ -442,7 +511,7 @@ class TestSvn(environment.ZippedEnvironment): 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, 'Changes.txt'), os.path.join('folder', folder3, 'fin'), os.path.join('folder', folder3, 'MD5SUMS'), os.path.join('folder', folder3, 'oops'), @@ -451,13 +520,11 @@ class TestSvn(environment.ZippedEnvironment): 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 - ]) - expected = set(fsencode(x) for x in expected) + # 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__) - diff --git a/setuptools/tests/test_svn.py b/setuptools/tests/test_svn.py index 59ecb25b..5418b9a4 100644 --- a/setuptools/tests/test_svn.py +++ b/setuptools/tests/test_svn.py @@ -3,21 +3,13 @@ import os -import sys import unittest import codecs from setuptools.tests import environment -from setuptools.svn_utils import fsencode from setuptools.compat import unicode, unichr from setuptools import svn_utils -#requires python >= 2.4 -from subprocess import call as _call - -from distutils import log - - class TestSvnVersion(unittest.TestCase): @@ -64,13 +56,6 @@ class ParserInfoXML(unittest.TestCase): data = _read_utf8_file(path) - if ext_spaces: - folder2 = 'third party2' - folder3 = 'third party3' - else: - folder2 = 'third_party2' - folder3 = 'third_party3' - expected = set([ ("\\".join((example_base, 'a file')), 'file'), ("\\".join((example_base, 'folder')), 'dir'), @@ -116,7 +101,7 @@ class ParserExternalXML(unittest.TestCase): expected = set([ os.sep.join((example_base, folder2)), os.sep.join((example_base, folder3)), - #third_party大介 + # folder is third_party大介 os.sep.join((example_base, unicode('third_party') + unichr(0x5927) + unichr(0x4ecb))), @@ -129,7 +114,7 @@ class ParserExternalXML(unittest.TestCase): 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 \ + self.assertEqual(set(x for x in svn_utils.parse_externals_xml(data, dir_base)), expected) def test_svn15(self): @@ -150,7 +135,6 @@ 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') - example_base = svn_name + '_example' data = _read_utf8_file(path) if ext_spaces: @@ -237,4 +221,3 @@ class TestSvn(environment.ZippedEnvironment): def test_suite(): return unittest.defaultTestLoader.loadTestsFromName(__name__) - diff --git a/setuptools/version.py b/setuptools/version.py index 64477cf2..0f663085 100644 --- a/setuptools/version.py +++ b/setuptools/version.py @@ -1 +1 @@ -__version__ = '1.2' +__version__ = '1.4' |
