summaryrefslogtreecommitdiff
path: root/setuptools
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools')
-rwxr-xr-xsetuptools/package_index.py73
-rw-r--r--setuptools/ssl_support.py86
-rw-r--r--setuptools/svn_utils.py107
-rw-r--r--setuptools/tests/environment.py56
-rw-r--r--setuptools/tests/svn17_example.zipbin19342 -> 0 bytes
-rw-r--r--setuptools/tests/svn_data/dummy.zipbin0 -> 1771 bytes
-rw-r--r--setuptools/tests/svn_data/dummy13.zipbin0 -> 9243 bytes
-rw-r--r--setuptools/tests/svn_data/dummy14.zipbin0 -> 7496 bytes
-rw-r--r--setuptools/tests/svn_data/dummy15.zipbin0 -> 7506 bytes
-rw-r--r--setuptools/tests/svn_data/dummy16.zipbin0 -> 7155 bytes
-rw-r--r--setuptools/tests/svn_data/dummy17.zipbin0 -> 7512 bytes
-rw-r--r--setuptools/tests/svn_data/dummy18.zipbin0 -> 7639 bytes
-rw-r--r--setuptools/tests/test_egg_info.py96
-rw-r--r--setuptools/tests/test_sdist.py89
-rw-r--r--setuptools/tests/test_svn.py21
-rw-r--r--setuptools/version.py2
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
deleted file mode 100644
index cfabd2b2..00000000
--- a/setuptools/tests/svn17_example.zip
+++ /dev/null
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy.zip b/setuptools/tests/svn_data/dummy.zip
new file mode 100644
index 00000000..1347be53
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy13.zip b/setuptools/tests/svn_data/dummy13.zip
new file mode 100644
index 00000000..47764342
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy13.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy14.zip b/setuptools/tests/svn_data/dummy14.zip
new file mode 100644
index 00000000..02ed8cf0
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy14.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy15.zip b/setuptools/tests/svn_data/dummy15.zip
new file mode 100644
index 00000000..ed8daeeb
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy15.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy16.zip b/setuptools/tests/svn_data/dummy16.zip
new file mode 100644
index 00000000..b6e98d6c
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy16.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy17.zip b/setuptools/tests/svn_data/dummy17.zip
new file mode 100644
index 00000000..d96e1513
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy17.zip
Binary files differ
diff --git a/setuptools/tests/svn_data/dummy18.zip b/setuptools/tests/svn_data/dummy18.zip
new file mode 100644
index 00000000..a7267838
--- /dev/null
+++ b/setuptools/tests/svn_data/dummy18.zip
Binary files differ
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'