Index: src/zc/buildout/__init__.py =================================================================== --- src/zc/buildout/__init__.py (revision 103702) +++ src/zc/buildout/__init__.py (working copy) @@ -21,4 +21,4 @@ """ def __str__(self): - return " ".join(map(str, self)) + return " ".join(map(str, self.args)) Index: src/zc/buildout/download.py =================================================================== --- src/zc/buildout/download.py (revision 103702) +++ src/zc/buildout/download.py (working copy) @@ -24,15 +24,20 @@ import re import shutil import tempfile -import urllib +import sys +# Rename to _urllib on importing, as 2to3 will replace urlparse +# below with urllib.parse +if sys.version_info < (3,): + import urllib as _urllib +else: + from urllib import request as _urllib import urlparse import zc.buildout +class URLOpener(_urllib.FancyURLopener): + Http_error_default = _urllib.URLopener.http_error_default -class URLOpener(urllib.FancyURLopener): - http_error_default = urllib.URLopener.http_error_default - class ChecksumError(zc.buildout.UserError): pass @@ -166,11 +171,11 @@ "Couldn't download %r in offline mode." % url) self.logger.info('Downloading %s' % url) - urllib._urlopener = url_opener + _urllib._urlopener = url_opener handle, tmp_path = tempfile.mkstemp(prefix='buildout-') try: try: - tmp_path, headers = urllib.urlretrieve(url, tmp_path) + tmp_path, headers = _urllib.urlretrieve(url, tmp_path) if not check_md5sum(tmp_path, md5sum): raise ChecksumError( 'MD5 checksum mismatch downloading %r' % url) Index: src/zc/buildout/easy_install.py =================================================================== --- src/zc/buildout/easy_install.py (revision 103702) +++ src/zc/buildout/easy_install.py (working copy) @@ -659,7 +659,7 @@ try: ws.resolve(requirements) except pkg_resources.DistributionNotFound, err: - [requirement] = err + requirement = err.args[0] # XXX - mvl - why was this list unpacking? requirement = self._constrain(requirement) if dest: logger.debug('Getting required %r', str(requirement)) @@ -832,6 +832,13 @@ return result[0] +if sys.version_info <= (3,): + def _bytes(s): + return s +else: + def _bytes(s): + return s.encode("ascii") + def develop(setup, dest, build_ext=None, executable=sys.executable): @@ -863,12 +870,12 @@ undo.append(lambda: os.remove(tsetup)) undo.append(lambda: os.close(fd)) - os.write(fd, runsetup_template % dict( + os.write(fd, _bytes(runsetup_template % dict( setuptools=setuptools_loc, setupdir=directory, setup=setup, __file__ = setup, - )) + ))) tmp3 = tempfile.mkdtemp('build', dir=dest) undo.append(lambda : shutil.rmtree(tmp3)) @@ -1144,7 +1151,7 @@ sys.argv[:] = _args __file__ = _args[0] del _options, _args - execfile(__file__) + exec(compile(open(__file__).read(), __file__, 'exec')) if _interactive: del _interactive @@ -1161,7 +1168,7 @@ os.chdir(%(setupdir)r) sys.argv[0] = %(setup)r -execfile(%(setup)r) +exec(compile(open(%(setup)r).read(), %(setup)r, 'exec')) """ class VersionConflict(zc.buildout.UserError): Index: src/zc/buildout/buildout.py =================================================================== --- src/zc/buildout/buildout.py (revision 103702) +++ src/zc/buildout/buildout.py (working copy) @@ -33,7 +33,19 @@ import shutil import sys import tempfile -import UserDict +import base64 +if sys.version_info <= (3,): + from UserDict import DictMixin +else: + from collections import MutableMapping + class DictMixin(MutableMapping): + def __len__(self): + # MutableMapping can't predefine __len__, since .keys() won't necessarily + # return a list. However, 2.x DictMixin assumes exactly that, and so can we here + return len(self.keys()) + def __iter__(self): + # likewise + return iter(self.keys()) import zc.buildout import zc.buildout.download import zc.buildout.easy_install @@ -124,7 +136,7 @@ }, 'DEFAULT_VALUE') -class Buildout(UserDict.DictMixin): +class Buildout(DictMixin): def __init__(self, config_file, cloptions, user_defaults=True, windows_restart=False, command=None): @@ -1014,7 +1026,7 @@ group, entry, spec, v) raise -class Options(UserDict.DictMixin): +class Options(DictMixin): def __init__(self, buildout, section, data): self.buildout = buildout @@ -1345,6 +1357,16 @@ seen.pop() return result +if sys.version_info <= (3,): + def _fsenc(s): + return s + def _tostring(b): + return b +else: + def _fsenc(s): + return s.encode(sys.getfilesystemencoding()) + def _tostring(b): + return b.decode("ascii") ignore_directories = '.svn', 'CVS' def _dir_hash(dir): @@ -1355,11 +1377,11 @@ if (not (f.endswith('pyc') or f.endswith('pyo')) and os.path.exists(os.path.join(dirpath, f))) ] - hash.update(' '.join(dirnames)) - hash.update(' '.join(filenames)) + hash.update(_fsenc(' '.join(dirnames))) + hash.update(_fsenc(' '.join(filenames))) for name in filenames: - hash.update(open(os.path.join(dirpath, name)).read()) - return hash.digest().encode('base64').strip() + hash.update(open(os.path.join(dirpath, name), 'rb').read()) + return _tostring(base64.encodestring(hash.digest()).strip()) def _dists_sig(dists): result = [] Index: setup.py =================================================================== --- setup.py (revision 103702) +++ setup.py (working copy) @@ -17,6 +17,9 @@ import os from setuptools import setup +import setuptools +setuptools.run_2to3=True + def read(*rnames): return open(os.path.join(os.path.dirname(__file__), *rnames)).read()