[Checkins] SVN: zope.publisher/branches/py3/ Checkpoint of my porting efforts. I am done for today.

Stephen Richter cvs-admin at zope.org
Fri Feb 15 03:45:23 UTC 2013


Log message for revision 129426:
  Checkpoint of my porting efforts. I am done for today.
  

Changed:
  A   zope.publisher/branches/py3/MANIFEST.in
  U   zope.publisher/branches/py3/bootstrap.py
  U   zope.publisher/branches/py3/buildout.cfg
  U   zope.publisher/branches/py3/setup.py
  U   zope.publisher/branches/py3/src/zope/publisher/base.py
  U   zope.publisher/branches/py3/src/zope/publisher/browser.py
  U   zope.publisher/branches/py3/src/zope/publisher/defaultview.py
  U   zope.publisher/branches/py3/src/zope/publisher/ftp.py
  U   zope.publisher/branches/py3/src/zope/publisher/http.py
  U   zope.publisher/branches/py3/src/zope/publisher/interfaces/__init__.py
  U   zope.publisher/branches/py3/src/zope/publisher/publish.py
  U   zope.publisher/branches/py3/src/zope/publisher/skinnable.txt
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_baserequest.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_baseresponse.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_browserrequest.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_ftp.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_http.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_ipublication.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_publisher.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_xmlrpc.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_xmlrpcrequest.py
  U   zope.publisher/branches/py3/src/zope/publisher/tests/test_zcml.py
  U   zope.publisher/branches/py3/src/zope/publisher/xmlrpc.py
  A   zope.publisher/branches/py3/tox.ini

-=-
Added: zope.publisher/branches/py3/MANIFEST.in
===================================================================
--- zope.publisher/branches/py3/MANIFEST.in	                        (rev 0)
+++ zope.publisher/branches/py3/MANIFEST.in	2013-02-15 03:45:22 UTC (rev 129426)
@@ -0,0 +1,9 @@
+include *.rst
+include *.txt
+include tox.ini
+include bootstrap.py
+include buildout.cfg
+
+recursive-include src *
+
+global-exclude *.pyc

Modified: zope.publisher/branches/py3/bootstrap.py
===================================================================
--- zope.publisher/branches/py3/bootstrap.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/bootstrap.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -18,33 +18,148 @@
 use the -c option to specify an alternate configuration file.
 """
 
-import os, shutil, sys, tempfile, urllib2
+import os, shutil, sys, tempfile
+from optparse import OptionParser
 
 tmpeggs = tempfile.mkdtemp()
 
-ez = {}
-exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
-                     ).read() in ez
-ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
 
-import pkg_resources
+Bootstraps a buildout-based project.
 
-cmd = 'from setuptools.command.easy_install import main; main()'
-if sys.platform == 'win32':
-    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
 
-ws = pkg_resources.working_set
-assert os.spawnle(
-    os.P_WAIT, sys.executable, sys.executable,
-    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
-    dict(os.environ,
-         PYTHONPATH=
-         ws.find(pkg_resources.Requirement.parse('setuptools')).location
-         ),
-    ) == 0
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
 
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", help="use a specific zc.buildout version")
+
+parser.add_option("-t", "--accept-buildout-test-releases",
+                  dest='accept_buildout_test_releases',
+                  action="store_true", default=False,
+                  help=("Normally, if you do not specify a --version, the "
+                        "bootstrap script and buildout gets the newest "
+                        "*final* versions of zc.buildout and its recipes and "
+                        "extensions for you.  If you use this flag, "
+                        "bootstrap and buildout will get the newest releases "
+                        "even if they are alphas or betas."))
+parser.add_option("-c", "--config-file",
+                   help=("Specify the path to the buildout configuration "
+                         "file to be used."))
+parser.add_option("-f", "--find-links",
+                   help=("Specify a URL to search for buildout releases"))
+
+
+options, args = parser.parse_args()
+
+######################################################################
+# load/install distribute
+
+to_reload = False
+try:
+    import pkg_resources, setuptools
+    if not hasattr(pkg_resources, '_distribute'):
+        to_reload = True
+        raise ImportError
+except ImportError:
+    ez = {}
+
+    try:
+        from urllib.request import urlopen
+    except ImportError:
+        from urllib2 import urlopen
+
+    exec(urlopen('http://python-distribute.org/distribute_setup.py').read(), ez)
+    setup_args = dict(to_dir=tmpeggs, download_delay=0, no_fake=True)
+    ez['use_setuptools'](**setup_args)
+
+    if to_reload:
+        reload(pkg_resources)
+    import pkg_resources
+    # This does not (always?) update the default working set.  We will
+    # do it.
+    for path in sys.path:
+        if path not in pkg_resources.working_set.entries:
+            pkg_resources.working_set.add_entry(path)
+
+######################################################################
+# Install buildout
+
+ws  = pkg_resources.working_set
+
+cmd = [sys.executable, '-c',
+       'from setuptools.command.easy_install import main; main()',
+       '-mZqNxd', tmpeggs]
+
+find_links = os.environ.get(
+    'bootstrap-testing-find-links',
+    options.find_links or
+    ('http://downloads.buildout.org/'
+     if options.accept_buildout_test_releases else None)
+    )
+if find_links:
+    cmd.extend(['-f', find_links])
+
+distribute_path = ws.find(
+    pkg_resources.Requirement.parse('distribute')).location
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+    # Figure out the most recent final version of zc.buildout.
+    import setuptools.package_index
+    _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
+    index = setuptools.package_index.PackageIndex(
+        search_path=[distribute_path])
+    if find_links:
+        index.add_find_links((find_links,))
+    req = pkg_resources.Requirement.parse(requirement)
+    if index.obtain(req) is not None:
+        best = []
+        bestv = None
+        for dist in index[req.project_name]:
+            distv = dist.parsed_version
+            if _final_version(distv):
+                if bestv is None or distv > bestv:
+                    best = [dist]
+                    bestv = distv
+                elif distv == bestv:
+                    best.append(dist)
+        if best:
+            best.sort()
+            version = best[-1].version
+if version:
+    requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+import subprocess
+if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=distribute_path)) != 0:
+    raise Exception(
+        "Failed to execute command:\n%s",
+        repr(cmd)[1:-1])
+
+######################################################################
+# Import and run buildout
+
 ws.add_entry(tmpeggs)
-ws.require('zc.buildout')
+ws.require(requirement)
 import zc.buildout.buildout
-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+
+if not [a for a in args if '=' not in a]:
+    args.append('bootstrap')
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+    args[0:0] = ['-c', options.config_file]
+
+zc.buildout.buildout.main(args)
 shutil.rmtree(tmpeggs)

Modified: zope.publisher/branches/py3/buildout.cfg
===================================================================
--- zope.publisher/branches/py3/buildout.cfg	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/buildout.cfg	2013-02-15 03:45:22 UTC (rev 129426)
@@ -1,5 +1,6 @@
 [buildout]
 develop = .
+          ../zope.i18n
 parts = test
 
 [test]

Modified: zope.publisher/branches/py3/setup.py
===================================================================
--- zope.publisher/branches/py3/setup.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/setup.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -16,16 +16,30 @@
 # When developing and releasing this package, please follow the documented
 # Zope Toolkit policies as described by this documentation.
 ##############################################################################
-
 from setuptools import setup, find_packages
 
-entry_points = """
+def alltests():
+    import os
+    import sys
+    import unittest
+    # use the zope.testrunner machinery to find all the
+    # test suites we've put under ourselves
+    import zope.testrunner.find
+    import zope.testrunner.options
+    here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src'))
+    args = sys.argv[:]
+    defaults = ["--test-path", here]
+    options = zope.testrunner.options.get_options(args, defaults)
+    suites = list(zope.testrunner.find.find_suites(options))
+    return unittest.TestSuite(suites)
+
+entry_points = '''
 [paste.app_factory]
 main = zope.publisher.paste:Application
 
 [zope.publisher.publication_factory]
 sample = zope.publisher.tests.test_paste:SamplePublication
-"""
+'''
 
 setup(name='zope.publisher',
       version='4.0.0dev',
@@ -33,7 +47,7 @@
       license='ZPL 2.1',
       author='Zope Foundation and Contributors',
       author_email='zope-dev at zope.org',
-      description="The Zope publisher publishes Python objects on the web.",
+      description='The Zope publisher publishes Python objects on the web.',
       long_description=(open('README.txt').read()
                         + '\n\n'
                         + open('CHANGES.txt').read()),
@@ -42,16 +56,17 @@
         'Intended Audience :: Developers',
         'License :: OSI Approved :: Zope Public License',
         'Programming Language :: Python',
-        "Programming Language :: Python :: 2",
-        "Programming Language :: Python :: 2.6",
-        "Programming Language :: Python :: 2.7",
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.6',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.3',
+        'Programming Language :: Python :: Implementation :: CPython',
+        'Programming Language :: Python :: Implementation :: PyPy',
         'Natural Language :: English',
         'Operating System :: OS Independent',
         'Topic :: Internet :: WWW/HTTP',
         ],
-
-      entry_points=entry_points,
-
       packages=find_packages('src'),
       package_dir={'': 'src'},
       namespace_packages=['zope',],
@@ -63,13 +78,15 @@
                         'zope.event',
                         'zope.exceptions',
                         'zope.i18n',
-                        'zope.interface',
+                        'zope.interface >= 3.8.0',
                         'zope.location',
                         'zope.proxy',
-                        'zope.security',
+                        'zope.security >= 4.0.0a1',
                        ],
       extras_require={'test': ['zope.testing']},
+      tests_require = ['zope.testing', 'zope.testrunner'],
+      test_suite = '__main__.alltests',
+      entry_points=entry_points,
       include_package_data=True,
-
       zip_safe=False,
       )

Modified: zope.publisher/branches/py3/src/zope/publisher/base.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/base.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/base.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -16,8 +16,6 @@
 Specifically, 'BaseRequest', 'BaseResponse', and 'DefaultPublication' are
 specified here.
 """
-from cStringIO import StringIO
-
 from zope.interface import implementer
 from zope.interface.common.mapping import IReadMapping, IEnumerableMapping
 from zope.exceptions.exceptionformatter import print_exception
@@ -28,6 +26,12 @@
 from zope.publisher.interfaces import IRequest, IResponse, IDebugFlags
 from zope.publisher.publish import mapply
 
+try:
+    from cStringIO import StringIO as BytesIO
+except:
+    # Py3
+    from io import BytesIO
+
 _marker = object()
 
 @implementer(IResponse)
@@ -50,7 +54,7 @@
 
     def handleException(self, exc_info):
         'See IPublisherResponse'
-        f = StringIO()
+        f = BytesIO()
         print_exception(
             exc_info[0], exc_info[1], exc_info[2], 100, f)
         self.setResult(f.getvalue())
@@ -398,7 +402,7 @@
 
         environ['PATH_INFO'] = path
         if body_instream is None:
-            body_instream = StringIO('')
+            body_instream = BytesIO('')
 
         super(TestRequest, self).__init__(body_instream, environ)
 

Modified: zope.publisher/branches/py3/src/zope/publisher/browser.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/browser.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/browser.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -21,7 +21,6 @@
 __docformat__ = 'restructuredtext'
 
 import re
-from types import ListType, TupleType, StringType
 from cgi import FieldStorage
 import tempfile
 
@@ -51,9 +50,14 @@
 from zope.publisher.skinnable import setDefaultSkin #BBB import
 from zope.publisher.skinnable import applySkin #BBB import
 from zope.publisher.skinnable import SkinChangedEvent #BBB import
+import six
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
 
-__ArrayTypes = (ListType, TupleType)
+__ArrayTypes = (list, type)
 
 start_of_header_search=re.compile('(<head[^>]*>)', re.I).search
 base_re_search=re.compile('(<base.*?>)',re.I).search
@@ -89,7 +93,7 @@
 
 def field2int(v):
     if isinstance(v, __ArrayTypes):
-        return map(field2int, v)
+        return list(map(field2int, v))
     v = field2string(v)
     if not v:
         raise ValueError('Empty entry when <strong>integer</strong> expected')
@@ -100,7 +104,7 @@
 
 def field2float(v):
     if isinstance(v, __ArrayTypes):
-        return map(field2float, v)
+        return list(map(field2float, v))
     v = field2string(v)
     if not v:
         raise ValueError(
@@ -113,7 +117,7 @@
 
 def field2long(v):
     if isinstance(v, __ArrayTypes):
-        return map(field2long, v)
+        return list(map(field2long, v))
     v = field2string(v)
 
     # handle trailing 'L' if present.
@@ -185,12 +189,12 @@
     'CONTENT_TYPE' : 1,
     'CONTENT_LENGTH' : 1,
     'SERVER_URL': 1,
-    }.has_key
+    }.__contains__
 
 hide_key={
     'HTTP_AUTHORIZATION':1,
     'HTTP_CGI_AUTHORIZATION': 1,
-    }.has_key
+    }.__contains__
 
 class Record(object):
 
@@ -393,7 +397,7 @@
         if key is not None:
             key = self._decode(key)
 
-        if type(item) == StringType:
+        if isinstance(item, bytes):
             item = self._decode(item)
 
         if flags:
@@ -516,7 +520,7 @@
         """Insert defaults into form dictionary."""
         form = self.form
 
-        for keys, values in self.__defaults.iteritems():
+        for keys, values in six.iteritems(self.__defaults):
             if not keys in form:
                 form[keys] = values
             else:
@@ -661,8 +665,7 @@
         if kw:
             _testEnv.update(kw)
         if body_instream is None:
-            from StringIO import StringIO
-            body_instream = StringIO('')
+            body_instream = BytesIO(b'')
 
         super(TestRequest, self).__init__(body_instream, _testEnv)
         if form:

Modified: zope.publisher/branches/py3/src/zope/publisher/defaultview.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/defaultview.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/defaultview.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -18,6 +18,8 @@
 
 import zope.interface
 from zope.publisher.interfaces import IDefaultViewName
+from six.moves import map
+from six.moves import zip
 
 
 class IDefaultViewNameAPI(zope.interface.Interface):

Modified: zope.publisher/branches/py3/src/zope/publisher/ftp.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/ftp.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/ftp.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -13,6 +13,7 @@
 ##############################################################################
 """FTP Publisher
 """
+import six
 from zope.interface import implementer
 from zope.publisher.interfaces.ftp import IFTPCredentials, IFTPRequest
 from zope.publisher.base import BaseResponse, BaseRequest
@@ -27,7 +28,7 @@
 
     def getResult(self):
         if getattr(self, '_exc', None) is not None:
-            raise self._exc[0], self._exc[1], self._exc[2]
+            six.reraise(self._exc[0], self._exc[1], self._exc[2])
         return self._result
 
     def handleException(self, exc_info):

Modified: zope.publisher/branches/py3/src/zope/publisher/http.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/http.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/http.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -13,7 +13,17 @@
 ##############################################################################
 """HTTP Publisher
 """
-from cStringIO import StringIO
+import base64
+import cgi
+import logging
+import re
+import tempfile
+import types
+import urllib
+import zope.component
+import zope.contenttype.parse
+import zope.event
+import zope.interface
 from zope.i18n.interfaces import IUserPreferredCharsets
 from zope.i18n.interfaces import IUserPreferredLanguages
 from zope.i18n.locales import locales, LoadLocaleError
@@ -31,24 +41,34 @@
 from zope.publisher.interfaces.http import IResult
 from zope.publisher.interfaces.logginginfo import ILoggingInfo
 from zope.publisher.skinnable import setDefaultSkin
-import Cookie
-import cgi
-import logging
-import tempfile
-import types
-import urllib
-import urlparse
-import zope.component
-import zope.contenttype.parse
-import zope.event
-import zope.interface
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
 
+try:
+    import Cookie as cookies
+except ImportError:
+    # Py3
+    from http import cookies
+
+try:
+    import urlparse
+except ImportError:
+    # Py3
+    from urllib.parse import urlparse
+
+try:
+    unicode
+except NameError:
+    # Py3
+    unicode = str
+
 # Default Encoding
 ENCODING = 'UTF-8'
 
 # not just text/* but RFC 3023 and */*+xml
-import re
 unicode_mimetypes_re = re.compile(r"^text\/.*$|^.*\/xml.*$|^.*\+xml$")
 
 eventlog = logging.getLogger('eventlog')
@@ -176,7 +196,7 @@
                 return self.__request.getURL(i)
             else:
                 return self.__request.getApplicationURL(i)
-        except IndexError, v:
+        except IndexError as v:
             if v[0] == i:
                 return default
             raise
@@ -195,7 +215,7 @@
         if not size:
             size = environment.get('HTTP_CONTENT_LENGTH')
         if not size or int(size) < 65536:
-            self.cacheStream = StringIO()
+            self.cacheStream = BytesIO()
         else:
             self.cacheStream = tempfile.TemporaryFile()
         self.size = size and int(size) or -1
@@ -214,7 +234,7 @@
         # Previous versions of Twisted did not support the ``size`` argument
         # See http://twistedmatrix.com/trac/ticket/1451
         #     https://bugs.launchpad.net/zope3/+bug/98284
-        # Note, however, that we cannot pass a size of None to cStringIO
+        # Note, however, that we cannot pass a size of None to BytesIO
         # objects, or we'll get a TypeError: an integer is required
         if size is not None:
             data = self.stream.readline(size)
@@ -349,10 +369,10 @@
         get_env = self._environ.get
         # Get base info first. This isn't likely to cause
         # errors and might be useful to error handlers.
-        script = get_env('SCRIPT_NAME', '').strip()
+        script = get_env('SCRIPT_NAME', b'').strip()
 
         # _script and the other _names are meant for URL construction
-        self._app_names = filter(None, script.split('/'))
+        self._app_names = list(filter(None, script.split(b'/')))
 
         # get server URL and store it too, since we are already looking it up
         server_url = get_env('SERVER_URL', None)
@@ -361,11 +381,11 @@
         else:
             server_url = self.__deduceServerURL()
 
-        if server_url.endswith('/'):
+        if server_url.endswith(b'/'):
             server_url = server_url[:-1]
 
         # strip off leading /'s of script
-        while script.startswith('/'):
+        while script.startswith(b'/'):
             script = script[1:]
 
         self._app_server = server_url
@@ -373,13 +393,13 @@
     def __deduceServerURL(self):
         environ = self._environ
 
-        if (environ.get('HTTPS', '').lower() == "on" or
-            environ.get('SERVER_PORT_SECURE') == "1"):
+        if (environ.get('HTTPS', '').lower() == b"on" or
+            environ.get('SERVER_PORT_SECURE') == b"1"):
             protocol = 'https'
         else:
             protocol = 'http'
 
-        if environ.has_key('HTTP_HOST'):
+        if 'HTTP_HOST' in environ:
             host = environ['HTTP_HOST'].strip()
             hostname, port = urllib.splitport(host)
         else:
@@ -401,8 +421,8 @@
 
         # ignore cookies on a CookieError
         try:
-            c = Cookie.SimpleCookie(text)
-        except Cookie.CookieError, e:
+            c = cookies.SimpleCookie(text)
+        except cookies.CookieError as e:
             eventlog.warn(e)
             return result
 
@@ -489,9 +509,9 @@
 
     def _authUserPW(self):
         'See IHTTPCredentials'
-        if self._auth and self._auth.lower().startswith('basic '):
+        if self._auth and self._auth.lower().startswith(b'basic '):
             encoded = self._auth.split(None, 1)[-1]
-            name, password = encoded.decode("base64").split(':', 1)
+            name, password = base64.decode(encoded).split(':', 1)
             return name, password
 
     def unauthorized(self, challenge):
@@ -833,7 +853,7 @@
         Calls self.setBody() with an error response.
         """
         t, v = exc_info[:2]
-        if isinstance(t, (types.ClassType, type)):
+        if isinstance(t, (type, type)):
             if issubclass(t, Redirect):
                 self.redirect(v.getLocation())
                 return
@@ -900,8 +920,8 @@
 
     def _cookie_list(self):
         try:
-            c = Cookie.SimpleCookie()
-        except Cookie.CookieError, e:
+            c = cookies.SimpleCookie()
+        except cookies.CookieError as e:
             eventlog.warn(e)
             return []
         for name, attrs in self._cookies.items():
@@ -929,12 +949,8 @@
             "for more information."
             )
 
-def sort_charsets(x, y):
-    if y[1] == 'utf-8':
-        return 1
-    if x[1] == 'utf-8':
-        return -1
-    return cmp(y, x)
+def sort_charsets_key(x):
+    return (int(x[1] == 'utf-8'), x)
 
 
 def extract_host(url):
@@ -996,7 +1012,7 @@
         # range , unlike many other encodings. Since Zope can easily use very
         # different ranges, like providing a French-Chinese dictionary, it is
         # always good to use UTF-8.
-        charsets.sort(sort_charsets)
+        charsets = sorted(charsets, key=sort_charsets_key, reverse=True)
         charsets = [charset for quality, charset in charsets]
         if sawstar and 'utf-8' not in charsets:
             charsets.insert(0, 'utf-8')

Modified: zope.publisher/branches/py3/src/zope/publisher/interfaces/__init__.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/interfaces/__init__.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/interfaces/__init__.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -62,10 +62,10 @@
 
     def __str__(self):
         try:
-            ob = `self.ob`
+            ob = repr(self.ob)
         except:
             ob = 'unprintable object'
-        return 'Object: %s, name: %s' % (ob, `self.name`)
+        return 'Object: %s, name: %s' % (ob, repr(self.name))
 
 class IDebugError(ITraversalException):
     def getObject():

Modified: zope.publisher/branches/py3/src/zope/publisher/publish.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/publish.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/publish.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -15,6 +15,7 @@
 
 Provide an apply-like facility that works with any mapping object
 """
+import six
 import sys
 from zope import component
 from zope.interface import implementer
@@ -64,8 +65,8 @@
 
     unwrapped, wrapperCount = unwrapMethod(unwrapped)
 
-    code = unwrapped.func_code
-    defaults = unwrapped.func_defaults
+    code = unwrapped.__code__
+    defaults = unwrapped.__defaults__
     names = code.co_varnames[wrapperCount:code.co_argcount]
 
     nargs = len(names)
@@ -154,7 +155,7 @@
 
                     break # Successful.
 
-                except Retry, retryException:
+                except Retry as retryException:
                     if request.supportsRetry():
                         # Create a copy of the request and use it.
                         newrequest = request.retry()
@@ -187,7 +188,7 @@
 
         response = request.response
         if to_raise is not None:
-            raise to_raise[0], to_raise[1], to_raise[2]
+            six.reraise(to_raise[0], to_raise[1], to_raise[2])
 
     finally:
         to_raise = None  # Avoid circ. ref.
@@ -201,8 +202,7 @@
 @implementer(IReRaiseException)
 class DoNotReRaiseException(object):
     """Marker adapter for exceptions that should not be re-raised"""
-    
-    
+
     def __init__(self, exc):
         pass
 

Modified: zope.publisher/branches/py3/src/zope/publisher/skinnable.txt
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/skinnable.txt	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/skinnable.txt	2013-02-15 03:45:22 UTC (rev 129426)
@@ -88,8 +88,11 @@
 
 Now our request provides IJSONRequest because it implement that interface:
 
-  >>> from StringIO import StringIO
-  >>> request = JSONRequest(StringIO(''), {})
+  >>> try:
+  ...     from StringIO import BytesIO
+  ... except ImportError:
+  ...     from io import BytesIO
+  >>> request = JSONRequest(BytesIO(b''), {})
   >>> IJSONRequest.providedBy(request)
   True
 

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_baserequest.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_baserequest.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_baserequest.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -24,10 +24,14 @@
 from zope.publisher.tests.basetestiapplicationrequest \
      import BaseTestIApplicationRequest
 
-from StringIO import StringIO
 from zope.interface import Interface, providedBy, alsoProvides
 from zope.component import provideAdapter
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
+
 class TestBaseRequest(BaseTestIPublicationRequest,
                       BaseTestIApplicationRequest,
                       BaseTestIPublisherRequest,
@@ -35,7 +39,7 @@
 
     def _Test__new(self, **kw):
         from zope.publisher.base import BaseRequest
-        return BaseRequest(StringIO(''), kw)
+        return BaseRequest(BytesIO(b''), kw)
 
     def _Test__expectedViewType(self):
         return None # we don't expect
@@ -43,7 +47,7 @@
     def test_IApplicationRequest_bodyStream(self):
         from zope.publisher.base import BaseRequest
 
-        request = BaseRequest(StringIO('spam'), {})
+        request = BaseRequest(BytesIO(b'spam'), {})
         self.assertEqual(request.bodyStream.read(), 'spam')
 
     def test_IPublicationRequest_getPositionalArguments(self):

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_baseresponse.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_baseresponse.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_baseresponse.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -13,12 +13,10 @@
 ##############################################################################
 """Tests for BaseResponse
 """
-
 from unittest import TestCase, TestSuite, main, makeSuite
 from zope.publisher.base import BaseResponse
 from zope.publisher.interfaces import IResponse
 from zope.interface.verify import verifyObject
-from StringIO import StringIO
 
 
 class TestBaseResponse(TestCase):

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_browserrequest.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_browserrequest.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_browserrequest.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -14,7 +14,6 @@
 
 import sys
 import unittest
-from StringIO import StringIO
 
 from zope.interface import implementer, directlyProvides, Interface
 from zope.interface.verify import verifyObject
@@ -39,6 +38,11 @@
 from zope.publisher.tests.basetestiapplicationrequest \
      import BaseTestIApplicationRequest
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
+
 LARGE_FILE_BODY = """-----------------------------1
 Content-Disposition: form-data; name="upload"; filename="test"
 Content-Type: text/plain
@@ -101,7 +105,7 @@
         class Item(object):
             """Required docstring for the publisher."""
             def __call__(self, a, b):
-                return u"%s, %s" % (`a`, `b`)
+                return u"%s, %s" % (repr(a), repr(b))
 
         class Item3(object):
             """Required docstring for the publisher."""
@@ -115,7 +119,7 @@
 
             def index(self, a, b):
                 """Required docstring for the publisher."""
-                return u"%s, %s" % (`a`, `b`)
+                return u"%s, %s" % (repr(a), repr(b))
 
         class Item2(object):
             """Required docstring for the publisher."""
@@ -131,14 +135,14 @@
         self.app.folder.item2 = Item2()
         self.app.folder.item3 = Item3()
 
-    def _createRequest(self, extra_env={}, body=""):
+    def _createRequest(self, extra_env={}, body=b''):
         env = self._testEnv.copy()
         env.update(extra_env)
         if len(body):
             env['CONTENT_LENGTH'] = str(len(body))
 
         publication = Publication(self.app)
-        instream = StringIO(body)
+        instream = BytesIO(body)
         request = TestBrowserRequest(instream, env)
         request.setPublication(publication)
         return request

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_ftp.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_ftp.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_ftp.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -14,14 +14,18 @@
 """FTP Publisher Tests
 """
 import sys
-from cStringIO import StringIO
 from unittest import TestCase, TestSuite, main, makeSuite
 import zope.publisher.ftp
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
+
 class Test(TestCase):
 
     def setUp(self):
-        self.__input = StringIO('')
+        self.__input = BytesIO(b'')
         env = {'credentials': ('bob', '123'),
                'path': '/a/b/c',
                'command': 'foo',

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_http.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_http.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_http.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -14,11 +14,10 @@
 ##############################################################################
 """HTTP Publisher Tests
 """
+import base64
 import sys
 import tempfile
 import unittest
-from cStringIO import StringIO
-from Cookie import CookieError
 from doctest import DocFileSuite
 
 import zope.event
@@ -48,8 +47,17 @@
 from zope.publisher.tests.basetestiapplicationrequest \
      import BaseTestIApplicationRequest
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
 
+try:
+    import Cookie as cookies
+except ImportError:
+    from http import cookies
 
+
 @implementer(ILoggingInfo)
 class UserStub(object):
 
@@ -63,7 +71,7 @@
         return self._id
 
 
-data = '''\
+data = b'''\
 line 1
 line 2
 line 3'''
@@ -86,8 +94,8 @@
         return result
 
     def testRead(self):
-        stream = HTTPInputStream(StringIO(data), {})
-        output = ''
+        stream = HTTPInputStream(BytesIO(data), {})
+        output = b''
         self.assertEqual(output, self.getCacheStreamValue(stream))
         output += stream.read(5)
         self.assertEqual(output, self.getCacheStreamValue(stream))
@@ -96,7 +104,7 @@
         self.assertEqual(data, self.getCacheStreamValue(stream))
 
     def testReadLine(self):
-        stream = HTTPInputStream(StringIO(data), {})
+        stream = HTTPInputStream(BytesIO(data), {})
         output = stream.readline()
         self.assertEqual(output, self.getCacheStreamValue(stream))
         output += stream.readline()
@@ -108,15 +116,15 @@
         self.assertEqual(data, self.getCacheStreamValue(stream))
 
     def testReadLines(self):
-        stream = HTTPInputStream(StringIO(data), {})
-        output = ''.join(stream.readlines(4))
+        stream = HTTPInputStream(BytesIO(data), {})
+        output = b''.join(stream.readlines(4))
         self.assertEqual(output, self.getCacheStreamValue(stream))
-        output += ''.join(stream.readlines())
+        output += b''.join(stream.readlines())
         self.assertEqual(output, self.getCacheStreamValue(stream))
         self.assertEqual(data, self.getCacheStreamValue(stream))
 
     def testGetCacheStream(self):
-        stream = HTTPInputStream(StringIO(data), {})
+        stream = HTTPInputStream(BytesIO(data), {})
         stream.read(5)
         self.assertEqual(data, stream.getCacheStream().read())
 
@@ -127,26 +135,26 @@
         # definitely over that).
 
         # HTTPInputStream understands both CONTENT_LENGTH...
-        stream = HTTPInputStream(StringIO(data), {'CONTENT_LENGTH': '100000'})
+        stream = HTTPInputStream(BytesIO(data), {'CONTENT_LENGTH': b'100000'})
         self.assert_(isinstance(stream.getCacheStream(), TempFileType))
 
         # ... and HTTP_CONTENT_LENGTH.
-        stream = HTTPInputStream(StringIO(data), {'HTTP_CONTENT_LENGTH':
-                                                  '100000'})
+        stream = HTTPInputStream(BytesIO(data), {'HTTP_CONTENT_LENGTH':
+                                                  b'100000'})
         self.assert_(isinstance(stream.getCacheStream(), TempFileType))
 
         # If CONTENT_LENGTH is absent or empty, it takes the value
         # given in HTTP_CONTENT_LENGTH:
-        stream = HTTPInputStream(StringIO(data),
-                                 {'CONTENT_LENGTH': '',
-                                  'HTTP_CONTENT_LENGTH': '100000'})
+        stream = HTTPInputStream(BytesIO(data),
+                                 {'CONTENT_LENGTH': b'',
+                                  'HTTP_CONTENT_LENGTH': b'100000'})
         self.assert_(isinstance(stream.getCacheStream(), TempFileType))
 
         # In fact, HTTPInputStream can be instantiated with both an
         # empty CONTENT_LENGTH and an empty HTTP_CONTENT_LENGTH:
-        stream = HTTPInputStream(StringIO(data),
-                                 {'CONTENT_LENGTH': '',
-                                  'HTTP_CONTENT_LENGTH': ''})
+        stream = HTTPInputStream(BytesIO(data),
+                                 {'CONTENT_LENGTH': b'',
+                                  'HTTP_CONTENT_LENGTH': b''})
 
     def testWorkingWithNonClosingStreams(self):
         # It turns out that some Web servers (Paste for example) do not send
@@ -162,26 +170,26 @@
             def read(self, size=-1):
                 if size == -1:
                     raise ServerHung
-                return 'a'*size
+                return b'a'*size
 
-        stream = HTTPInputStream(NonClosingStream(), {'CONTENT_LENGTH': '10'})
-        self.assertEquals(stream.getCacheStream().read(), 'aaaaaaaaaa')
+        stream = HTTPInputStream(NonClosingStream(), {'CONTENT_LENGTH': b'10'})
+        self.assertEquals(stream.getCacheStream().read(), b'aaaaaaaaaa')
         stream = HTTPInputStream(NonClosingStream(), {})
         self.assertRaises(ServerHung, stream.getCacheStream)
 
 class HTTPTests(unittest.TestCase):
 
     _testEnv =  {
-        'PATH_INFO':          '/folder/item',
-        'a':                  '5',
-        'b':                  6,
-        'SERVER_URL':         'http://foobar.com',
-        'HTTP_HOST':          'foobar.com',
-        'CONTENT_LENGTH':     '0',
-        'HTTP_AUTHORIZATION': 'Should be in accessible',
-        'GATEWAY_INTERFACE':  'TestFooInterface/1.0',
-        'HTTP_OFF_THE_WALL':  "Spam 'n eggs",
-        'HTTP_ACCEPT_CHARSET': 'ISO-8859-1, UTF-8;q=0.66, UTF-16;q=0.33',
+        'PATH_INFO':           b'/folder/item',
+        'a':                   b'5',
+        'b':                   6,
+        'SERVER_URL':          b'http://foobar.com',
+        'HTTP_HOST':           b'foobar.com',
+        'CONTENT_LENGTH':      b'0',
+        'HTTP_AUTHORIZATION':  b'Should be in accessible',
+        'GATEWAY_INTERFACE':   b'TestFooInterface/1.0',
+        'HTTP_OFF_THE_WALL':   b"Spam 'n eggs",
+        'HTTP_ACCEPT_CHARSET': b'ISO-8859-1, UTF-8;q=0.66, UTF-16;q=0.33',
     }
 
     def setUp(self):
@@ -194,37 +202,37 @@
         class Item(object):
             """Required docstring for the publisher."""
             def __call__(self, a, b):
-                return "%s, %s" % (`a`, `b`)
+                return "%s, %s" % (repr(a), repr(b))
 
         self.app = AppRoot()
         self.app.folder = Folder()
         self.app.folder.item = Item()
         self.app.xxx = Item()
 
-    def _createRequest(self, extra_env={}, body=""):
+    def _createRequest(self, extra_env={}, body=b''):
         env = self._testEnv.copy()
         env.update(extra_env)
         if len(body):
-            env['CONTENT_LENGTH'] = str(len(body))
+            env['CONTENT_LENGTH'] = bytes(len(body))
 
         publication = DefaultPublication(self.app)
-        instream = StringIO(body)
+        instream = BytesIO(body)
         request = HTTPRequest(instream, env)
         request.setPublication(publication)
         return request
 
-    def _publisherResults(self, extra_env={}, body=""):
+    def _publisherResults(self, extra_env={}, body=b''):
         request = self._createRequest(extra_env, body)
         response = request.response
         publish(request, handle_errors=False)
         headers = response.getHeaders()
         headers.sort()
         return (
-            "Status: %s\r\n" % response.getStatusString()
+            b"Status: %s\r\n" % response.getStatusString()
             +
-            "\r\n".join([("%s: %s" % h) for h in headers]) + "\r\n\r\n"
+            b"\r\n".join([("%s: %s" % h) for h in headers]) + b"\r\n\r\n"
             +
-            ''.join(response.consumeBody())
+            b''.join(response.consumeBody())
             )
 
     def test_double_dots(self):
@@ -238,10 +246,10 @@
         # context to do so, and the publisher will raise it anyway given
         # improper input.  It was fixed and this test added.
 
-        request = self._createRequest(extra_env={'PATH_INFO': '..'})
+        request = self._createRequest(extra_env={'PATH_INFO': b'..'})
         self.assertRaises(NotFound, publish, request, handle_errors=0)
 
-        request = self._createRequest(extra_env={'PATH_INFO': '../folder'})
+        request = self._createRequest(extra_env={'PATH_INFO': b'../folder'})
         self.assertRaises(NotFound, publish, request, handle_errors=0)
 
     def test_repr(self):
@@ -254,15 +262,15 @@
         res = self._publisherResults()
         self.failUnlessEqual(
             res,
-            "Status: 200 Ok\r\n"
-            "Content-Length: 6\r\n"
-            "X-Powered-By: Zope (www.zope.org), Python (www.python.org)\r\n"
-            "\r\n"
-            "'5', 6")
+            b"Status: 200 Ok\r\n"
+            b"Content-Length: 6\r\n"
+            b"X-Powered-By: Zope (www.zope.org), Python (www.python.org)\r\n"
+            b"\r\n"
+            b"'5', 6")
 
     def testRedirect(self):
         # test HTTP/1.0
-        env = {'SERVER_PROTOCOL':'HTTP/1.0'}
+        env = {'SERVER_PROTOCOL': b'HTTP/1.0'}
 
         request = self._createRequest(env, '')
         location = request.response.redirect('http://foobar.com/redirected')
@@ -271,19 +279,19 @@
         self.assertEquals(request.response.getHeader('location'), location)
 
         # test HTTP/1.1
-        env = {'SERVER_PROTOCOL':'HTTP/1.1'}
+        env = {'SERVER_PROTOCOL': b'HTTP/1.1'}
 
-        request = self._createRequest(env, '')
+        request = self._createRequest(env, b'')
         location = request.response.redirect('http://foobar.com/redirected')
         self.assertEquals(request.response.getStatus(), 303)
 
         # test explicit status
-        request = self._createRequest(env, '')
+        request = self._createRequest(env, b'')
         request.response.redirect('http://foobar.com/explicit', 304)
         self.assertEquals(request.response.getStatus(), 304)
 
         # test non-string location, like URLGetter
-        request = self._createRequest(env, '')
+        request = self._createRequest(env, b'')
         request.response.redirect(request.URL)
         self.assertEquals(request.response.getStatus(), 303)
         self.assertEquals(request.response.getHeader('location'),
@@ -292,7 +300,7 @@
     def testUntrustedRedirect(self):
         # Redirects are by default only allowed to target the same host as the
         # request was directed to. This is to counter fishing.
-        request = self._createRequest({}, '')
+        request = self._createRequest({}, b'')
         self.assertRaises(
             ValueError,
             request.response.redirect, 'http://phishing-inc.com')
@@ -398,7 +406,7 @@
             eq(locale.id.territory, territory)
             eq(locale.id.variant, variant)
         # Now test for non-existant locale fallback
-        req = self._createRequest({'HTTP_ACCEPT_LANGUAGE': 'xx'})
+        req = self._createRequest({'HTTP_ACCEPT_LANGUAGE': b'xx'})
         locale = req.locale
         unless(ILocale.providedBy(locale))
         eq(locale.id.language, None)
@@ -406,7 +414,7 @@
         eq(locale.id.variant, None)
 
         # If the first language is not available we should try others
-        req = self._createRequest({'HTTP_ACCEPT_LANGUAGE': 'xx,en;q=0.5'})
+        req = self._createRequest({'HTTP_ACCEPT_LANGUAGE': b'xx,en;q=0.5'})
         locale = req.locale
         unless(ILocale.providedBy(locale))
         eq(locale.id.language, 'en')
@@ -415,7 +423,7 @@
 
         # Regression test: there was a bug where territory and variant were
         # not reset
-        req = self._createRequest({'HTTP_ACCEPT_LANGUAGE': 'xx-YY,en;q=0.5'})
+        req = self._createRequest({'HTTP_ACCEPT_LANGUAGE': b'xx-YY,en;q=0.5'})
         locale = req.locale
         unless(ILocale.providedBy(locale))
         eq(locale.id.language, 'en')
@@ -458,7 +466,7 @@
         self.assertEquals(req[u'this'], u'Should be accepted')
 
         # Reserved key
-        self.failIf(req.cookies.has_key('path'))
+        self.failIf('path' in req.cookies)
 
     def testCookieErrorToLog(self):
         cookies = {
@@ -467,17 +475,17 @@
         }
         req = self._createRequest(extra_env=cookies)
 
-        self.failIf(req.cookies.has_key('foo'))
-        self.failIf(req.has_key('foo'))
+        self.failIf('foo' in req.cookies)
+        self.failIf('foo' in req)
 
-        self.failIf(req.cookies.has_key('spam'))
-        self.failIf(req.has_key('spam'))
+        self.failIf('spam' in req.cookies)
+        self.failIf('spam' in req)
 
-        self.failIf(req.cookies.has_key('ldap/OU'))
-        self.failIf(req.has_key('ldap/OU'))
+        self.failIf('ldap/OU' in req.cookies)
+        self.failIf('ldap/OU' in req)
 
         # Reserved key
-        self.failIf(req.cookies.has_key('path'))
+        self.failIf('path' in req.cookies)
 
     def testCookiesUnicode(self):
         # Cookie values are assumed to be UTF-8 encoded
@@ -732,7 +740,7 @@
         response = self._createResponse()
         assert(charset == 'utf-8')
         if headers is not None:
-            for hdr, val in headers.iteritems():
+            for hdr, val in headers.items():
                 response.setHeader(hdr, val)
         response.setResult(body)
         return self._parseResult(response)
@@ -863,7 +871,7 @@
                         (r'sign="\342\230\243"' in c))
 
         self.assertRaises(
-                CookieError,
+                cookies.CookieError,
                 self._getCookieFromResponse,
                 [('path', 'invalid key', {}),]
                 )
@@ -922,11 +930,11 @@
     def _Test__new(self, environ=None, **kw):
         if environ is None:
             environ = kw
-        return HTTPRequest(StringIO(''), environ)
+        return HTTPRequest(BytesIO(b''), environ)
 
     def test_IApplicationRequest_bodyStream(self):
-        request = HTTPRequest(StringIO('spam'), {})
-        self.assertEqual(request.bodyStream.read(), 'spam')
+        request = HTTPRequest(BytesIO(b'spam'), {})
+        self.assertEqual(request.bodyStream.read(), b'spam')
 
     # Needed by BaseTestIEnumerableMapping tests:
     def _IEnumerableMapping__stateDict(self):

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_ipublication.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_ipublication.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_ipublication.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -13,14 +13,17 @@
 ##############################################################################
 """IPublication Test
 """
-
 import sys
 from unittest import TestCase, main, makeSuite
-from StringIO import StringIO
 from zope.interface.verify import verifyObject
 
 from zope.publisher.interfaces import IPublication
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
+
 class BaseIPublicationTest(object):
 
     # This test isn't as interesting as we'd like it to be because we
@@ -46,7 +49,7 @@
 
     def _Test__request(self):
         from zope.publisher.base import BaseRequest
-        request = BaseRequest(StringIO(''), {})
+        request = BaseRequest(BytesIO(b''), {})
         request.setTraversalStack(['Engineering', 'ZopeCorp'])
         publication = self._Test__new()
         request.setPublication(publication)

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_publisher.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_publisher.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_publisher.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -26,7 +26,10 @@
 from zope.interface.verify import verifyClass
 from zope.interface import implementedBy
 
-from StringIO import StringIO
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
 
 class ErrorToRetry(Exception):
     """A sample exception that should be retried."""
@@ -65,7 +68,7 @@
         publication = DefaultPublication(self.app)
         path = path.split('/')
         path.reverse()
-        request = TestRequest(StringIO(''), **kw)
+        request = TestRequest(BytesIO(b''), **kw)
         request.setTraversalStack(path)
         request.setPublication(publication)
         return request

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_xmlrpc.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_xmlrpc.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_xmlrpc.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -14,11 +14,15 @@
 """Testing the XML-RPC Publisher code.
 """
 import doctest
-import xmlrpclib
 import zope.component.testing
 from zope.publisher import xmlrpc
 from zope.security.checker import defineChecker, Checker, CheckerPublic
 
+try:
+    import xmlrpclib
+except ImportError:
+    import xmlrpc.client as xmlrpclib
+
 def setUp(test):
     zope.component.testing.setUp(test)
     zope.component.provideAdapter(xmlrpc.ListPreMarshaller)
@@ -40,7 +44,7 @@
                   Checker({'value':CheckerPublic}, {}))
 
 def test_suite():
-    return doctest.DocFileSuite( 
+    return doctest.DocFileSuite(
         "xmlrpc.txt", package="zope.publisher",
         setUp=setUp, tearDown=zope.component.testing.tearDown,
         optionflags=doctest.ELLIPSIS

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_xmlrpcrequest.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_xmlrpcrequest.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_xmlrpcrequest.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -14,12 +14,16 @@
 """XML-RPC Request Tests
 """
 import unittest
-from StringIO import StringIO
 
 from zope.publisher.base import DefaultPublication
 from zope.publisher.http import HTTPCharsets
 from zope.publisher.xmlrpc import XMLRPCRequest
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
+
 class Publication(DefaultPublication):
 
     require_docstrings = 0
@@ -39,7 +43,7 @@
         XMLRPCRequest.__init__(self, *args, **kw)
 
 
-xmlrpc_call = u'''<?xml version='1.0'?>
+xmlrpc_call = b'''<?xml version='1.0'?>
 <methodCall>
   <methodName>action</methodName>
   <params>
@@ -57,16 +61,16 @@
     """
 
     _testEnv =  {
-        'PATH_INFO':          '/folder/item2/view/',
-        'QUERY_STRING':       '',
-        'SERVER_URL':         'http://foobar.com',
-        'HTTP_HOST':          'foobar.com',
-        'CONTENT_LENGTH':     '0',
-        'REQUEST_METHOD':     'POST',
-        'HTTP_AUTHORIZATION': 'Should be in accessible',
-        'GATEWAY_INTERFACE':  'TestFooInterface/1.0',
-        'HTTP_OFF_THE_WALL':  "Spam 'n eggs",
-        'HTTP_ACCEPT_CHARSET': 'ISO-8859-1, UTF-8;q=0.66, UTF-16;q=0.33',
+        'PATH_INFO':           b'/folder/item2/view/',
+        'QUERY_STRING':        b'',
+        'SERVER_URL':          b'http://foobar.com',
+        'HTTP_HOST':           b'foobar.com',
+        'CONTENT_LENGTH':      b'0',
+        'REQUEST_METHOD':      b'POST',
+        'HTTP_AUTHORIZATION':  b'Should be in accessible',
+        'GATEWAY_INTERFACE':   b'TestFooInterface/1.0',
+        'HTTP_OFF_THE_WALL':   b"Spam 'n eggs",
+        'HTTP_ACCEPT_CHARSET': b'ISO-8859-1, UTF-8;q=0.66, UTF-16;q=0.33',
     }
 
     def setUp(self):
@@ -81,7 +85,7 @@
         class Item(object):
 
             def __call__(self, a, b):
-                return "%s, %s" % (`a`, `b`)
+                return "%s, %s" % (repr(a), repr(b))
 
             def doit(self, a, b):
                 return 'do something %s %s' % (a, b)
@@ -90,7 +94,7 @@
 
             def action(self, a):
                 return "Parameter[type: %s; value: %s" %(
-                    type(a).__name__, `a`)
+                    type(a).__name__, repr(a))
 
         class Item2(object):
             view = View()
@@ -102,14 +106,14 @@
         self.app.folder.item2 = Item2()
 
 
-    def _createRequest(self, extra_env={}, body=""):
+    def _createRequest(self, extra_env={}, body=b''):
         env = self._testEnv.copy()
         env.update(extra_env)
         if len(body):
             env['CONTENT_LENGTH'] = str(len(body))
 
         publication = Publication(self.app)
-        instream = StringIO(body)
+        instream = BytesIO(body)
         request = TestXMLRPCRequest(instream, env)
         request.setPublication(publication)
         return request

Modified: zope.publisher/branches/py3/src/zope/publisher/tests/test_zcml.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/tests/test_zcml.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/tests/test_zcml.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -13,7 +13,6 @@
 ##############################################################################
 """Tests for browser:defaultSkin and browser:defaultView directives
 """
-from cStringIO import StringIO
 import doctest
 import unittest
 
@@ -29,6 +28,12 @@
 
 import zope.publisher
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    from io import BytesIO
+
+
 class IOb(Interface):
     pass
 
@@ -52,7 +57,7 @@
 request = TestRequest()
 ob = Ob()
 
-template = """<configure
+template = b"""<configure
    xmlns='http://namespaces.zope.org/zope'
    xmlns:browser='http://namespaces.zope.org/browser'
    i18n_domain='zope'>
@@ -68,7 +73,7 @@
     def testDefaultView(self):
         self.assertTrue(
             component.queryMultiAdapter((ob, request), IDefaultViewName) is None)
-        xmlconfig(StringIO(template % (
+        xmlconfig(BytesIO(template % (
             '''
             <browser:defaultView
                 name="test"
@@ -88,8 +93,8 @@
             component.queryMultiAdapter((ob, request2), IDefaultViewName),
             None)
 
-        xmlconfig(StringIO(template % (
-            '''
+        xmlconfig(BytesIO(template % (
+            b'''
             <browser:defaultView
                 for="zope.publisher.tests.test_zcml.IOb"
                 name="test"
@@ -114,8 +119,8 @@
             component.queryMultiAdapter((ob, request), IDefaultViewName),
             None)
 
-        xmlconfig(StringIO(template % (
-            '''
+        xmlconfig(BytesIO(template % (
+            b'''
             <browser:defaultView
                 for="zope.publisher.tests.test_zcml.Ob"
                 name="test"
@@ -134,8 +139,8 @@
             None)
 
         XMLConfig('meta.zcml', component)()
-        xmlconfig(StringIO(template % (
-            '''
+        xmlconfig(BytesIO(template % (
+            b'''
             <interface
                 interface="
                   zope.publisher.tests.test_zcml.ITestSkin"

Modified: zope.publisher/branches/py3/src/zope/publisher/xmlrpc.py
===================================================================
--- zope.publisher/branches/py3/src/zope/publisher/xmlrpc.py	2013-02-15 03:41:08 UTC (rev 129425)
+++ zope.publisher/branches/py3/src/zope/publisher/xmlrpc.py	2013-02-15 03:45:22 UTC (rev 129426)
@@ -16,11 +16,8 @@
 This module contains the XMLRPCRequest and XMLRPCResponse
 """
 __docformat__ = 'restructuredtext'
-
 import sys
-import xmlrpclib
 import datetime
-from StringIO import StringIO
 
 import zope.component
 import zope.interface
@@ -31,6 +28,19 @@
 from zope.publisher.http import HTTPRequest, HTTPResponse, DirectResult
 from zope.security.proxy import isinstance
 
+try:
+    from cStringIO import StringIO as BytesIO
+except ImportError:
+    # Py3
+    from io import BytesIO
+
+try:
+    import xmlrpclib
+except ImportError:
+    # Py3
+    import xmlrpc.client as xmlrpclib
+
+
 @implementer(IXMLRPCRequest)
 class XMLRPCRequest(HTTPRequest):
 
@@ -183,7 +193,7 @@
         self.data = data
 
     def __call__(self):
-        raise Exception, "Not implemented"
+        raise Exception("Not implemented")
 
 @zope.component.adapter(dict)
 class DictPreMarshaller(PreMarshallerBase):
@@ -198,7 +208,7 @@
     """Pre-marshaller for list"""
 
     def __call__(self):
-        return map(premarshal, self.data)
+        return list(map(premarshal, self.data))
 
 @zope.component.adapter(tuple)
 class TuplePreMarshaller(ListPreMarshaller):

Added: zope.publisher/branches/py3/tox.ini
===================================================================
--- zope.publisher/branches/py3/tox.ini	                        (rev 0)
+++ zope.publisher/branches/py3/tox.ini	2013-02-15 03:45:22 UTC (rev 129426)
@@ -0,0 +1,46 @@
+[tox]
+envlist = py26,py27,py33,pypy
+
+[testenv]
+commands =
+    python setup.py test -q
+# without explicit deps, setup.py test will download a bunch of eggs into $PWD
+deps =
+    zope.browser
+    zope.component
+    zope.configuration
+    zope.contenttype >= 3.5
+    zope.event
+    zope.exceptions
+    zope.i18n
+    zope.interface
+    zope.location
+    zope.proxy
+    zope.security
+
+
+[testenv:coverage]
+basepython =
+    python2.7
+commands =
+#   The installed version messes up nose's test discovery / coverage reporting
+#   So, we uninstall that from the environment, and then install the editable
+#   version, before running nosetests.
+    pip uninstall -y zope.publisher
+    pip install -e .
+    nosetests --with-xunit --with-xcoverage
+deps =
+    nose
+    coverage
+    nosexcover
+    zope.browser
+    zope.component
+    zope.configuration
+    zope.contenttype >= 3.5
+    zope.event
+    zope.exceptions
+    zope.i18n
+    zope.interface
+    zope.location
+    zope.proxy
+    zope.security



More information about the checkins mailing list