git: dd02d1c84468 - main - devel/py-zope.publisher: Fix build with setuptools 58.0.0+

From: Po-Chuan Hsieh <sunpoet_at_FreeBSD.org>
Date: Sat, 16 Apr 2022 04:25:26 UTC
The branch main has been updated by sunpoet:

URL: https://cgit.FreeBSD.org/ports/commit/?id=dd02d1c844689ef999a286e76a9bedbf67a3839f

commit dd02d1c844689ef999a286e76a9bedbf67a3839f
Author:     Po-Chuan Hsieh <sunpoet@FreeBSD.org>
AuthorDate: 2022-04-16 04:15:32 +0000
Commit:     Po-Chuan Hsieh <sunpoet@FreeBSD.org>
CommitDate: 2022-04-16 04:19:53 +0000

    devel/py-zope.publisher: Fix build with setuptools 58.0.0+
    
    With hat:       python
---
 devel/py-zope.publisher/files/patch-2to3 | 1513 ++++++++++++++++++++++++++++++
 1 file changed, 1513 insertions(+)

diff --git a/devel/py-zope.publisher/files/patch-2to3 b/devel/py-zope.publisher/files/patch-2to3
new file mode 100644
index 000000000000..ccf232582607
--- /dev/null
+++ b/devel/py-zope.publisher/files/patch-2to3
@@ -0,0 +1,1513 @@
+--- src/zope/publisher/ftp.py.orig	2012-07-02 06:19:44 UTC
++++ src/zope/publisher/ftp.py
+@@ -27,7 +27,7 @@ class FTPResponse(BaseResponse):
+ 
+     def getResult(self):
+         if getattr(self, '_exc', None) is not None:
+-            raise self._exc[0], self._exc[1], self._exc[2]
++            raise self._exc[0](self._exc[1]).with_traceback(self._exc[2])
+         return self._result
+ 
+     def handleException(self, exc_info):
+--- src/zope/publisher/http.py.orig	2012-07-02 06:19:44 UTC
++++ src/zope/publisher/http.py
+@@ -13,7 +13,7 @@
+ ##############################################################################
+ """HTTP Publisher
+ """
+-from cStringIO import StringIO
++from io import StringIO
+ from zope.i18n.interfaces import IUserPreferredCharsets
+ from zope.i18n.interfaces import IUserPreferredLanguages
+ from zope.i18n.locales import locales, LoadLocaleError
+@@ -31,13 +31,13 @@ from zope.publisher.interfaces.http import IHTTPVirtua
+ from zope.publisher.interfaces.http import IResult
+ from zope.publisher.interfaces.logginginfo import ILoggingInfo
+ from zope.publisher.skinnable import setDefaultSkin
+-import Cookie
++import http.cookies
+ import cgi
+ import logging
+ import tempfile
+ import types
+-import urllib
+-import urlparse
++import urllib.request, urllib.parse, urllib.error
++import urllib.parse
+ import zope.component
+ import zope.contenttype.parse
+ import zope.event
+@@ -65,7 +65,7 @@ def sane_environment(env):
+     # or HTTP_CGI_AUTHORIZATION hacks.
+     # It also makes sure PATH_INFO is a unicode string.
+     dict = {}
+-    for key, val in env.items():
++    for key, val in list(env.items()):
+         while key.startswith('REDIRECT_'):
+             key = key[9:]
+         dict[key] = val
+@@ -138,7 +138,7 @@ status_codes={}
+ def init_status_codes():
+     # Add mappings for builtin exceptions and
+     # provide text -> error code lookups.
+-    for key, val in status_reasons.items():
++    for key, val in list(status_reasons.items()):
+         status_codes[val.replace(' ', '').lower()] = key
+         status_codes[val.lower()] = key
+         status_codes[key] = key
+@@ -176,7 +176,7 @@ class URLGetter(object):
+                 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
+@@ -352,7 +352,7 @@ class HTTPRequest(BaseRequest):
+         script = get_env('SCRIPT_NAME', '').strip()
+ 
+         # _script and the other _names are meant for URL construction
+-        self._app_names = filter(None, script.split('/'))
++        self._app_names = [_f for _f in script.split('/') if _f]
+ 
+         # get server URL and store it too, since we are already looking it up
+         server_url = get_env('SERVER_URL', None)
+@@ -379,9 +379,9 @@ class HTTPRequest(BaseRequest):
+         else:
+             protocol = 'http'
+ 
+-        if environ.has_key('HTTP_HOST'):
++        if 'HTTP_HOST' in environ:
+             host = environ['HTTP_HOST'].strip()
+-            hostname, port = urllib.splitport(host)
++            hostname, port = urllib.parse.splitport(host)
+         else:
+             hostname = environ.get('SERVER_NAME', '').strip()
+             port = environ.get('SERVER_PORT', '')
+@@ -401,13 +401,13 @@ class HTTPRequest(BaseRequest):
+ 
+         # ignore cookies on a CookieError
+         try:
+-            c = Cookie.SimpleCookie(text)
+-        except Cookie.CookieError, e:
++            c = http.cookies.SimpleCookie(text)
++        except http.cookies.CookieError as e:
+             eventlog.warn(e)
+             return result
+ 
+-        for k,v in c.items():
+-            result[unicode(k, ENCODING)] = unicode(v.value, ENCODING)
++        for k,v in list(c.items()):
++            result[str(k, ENCODING)] = str(v.value, ENCODING)
+ 
+         return result
+ 
+@@ -521,7 +521,7 @@ class HTTPRequest(BaseRequest):
+                 raise IndexError(level)
+             names = names[:-level]
+         # See: http://www.ietf.org/rfc/rfc2718.txt, Section 2.2.5
+-        names = [urllib.quote(name.encode("utf-8"), safe='/+@')
++        names = [urllib.parse.quote(name.encode("utf-8"), safe='/+@')
+                  for name in names]
+ 
+         if path_only:
+@@ -544,7 +544,7 @@ class HTTPRequest(BaseRequest):
+             names = self._app_names
+ 
+         # See: http://www.ietf.org/rfc/rfc2718.txt, Section 2.2.5
+-        names = [urllib.quote(name.encode("utf-8"), safe='/+@')
++        names = [urllib.parse.quote(name.encode("utf-8"), safe='/+@')
+                  for name in names]
+ 
+         if path_only:
+@@ -604,7 +604,7 @@ class HTTPRequest(BaseRequest):
+         d = {}
+         d.update(self._environ)
+         d.update(self._cookies)
+-        return d.keys()
++        return list(d.keys())
+ 
+ 
+ 
+@@ -645,7 +645,7 @@ class HTTPResponse(BaseResponse):
+         try:
+             status = int(status)
+         except ValueError:
+-            if isinstance(status, basestring):
++            if isinstance(status, str):
+                 status = status.lower()
+             # Use a standard status code, falling back to 500 for
+             # nonstandard values (such as "valueerror")
+@@ -701,7 +701,7 @@ class HTTPResponse(BaseResponse):
+         result.append(
+             ("X-Powered-By", "Zope (www.zope.org), Python (www.python.org)"))
+ 
+-        for key, values in headers.items():
++        for key, values in list(headers.items()):
+             if key.lower() == key:
+                 # only change non-literal header names
+                 key = '-'.join([k.capitalize() for k in key.split('-')])
+@@ -729,7 +729,7 @@ class HTTPResponse(BaseResponse):
+     def expireCookie(self, name, **kw):
+         'See IHTTPResponse'
+         dict = {'max_age':0, 'expires':'Wed, 31-Dec-97 23:59:59 GMT'}
+-        for k, v in kw.items():
++        for k, v in list(kw.items()):
+             if v is not None:
+                 dict[k] = v
+         cookies = self._cookies
+@@ -744,7 +744,7 @@ class HTTPResponse(BaseResponse):
+         cookies = self._cookies
+         cookie = cookies.setdefault(name, {})
+ 
+-        for k, v in kw.items():
++        for k, v in list(kw.items()):
+             if v is not None:
+                 cookie[k.lower()] = v
+ 
+@@ -764,7 +764,7 @@ class HTTPResponse(BaseResponse):
+             r = zope.component.queryMultiAdapter(
+                 (result, self._request), IResult)
+             if r is None:
+-                if isinstance(result, basestring):
++                if isinstance(result, str):
+                     r = result
+                 elif result is None:
+                     r = ''
+@@ -772,7 +772,7 @@ class HTTPResponse(BaseResponse):
+                     raise TypeError(
+                         'The result should be None, a string, or adaptable to '
+                         'IResult.')
+-            if isinstance(r, basestring):
++            if isinstance(r, str):
+                 r, headers = self._implicitResult(r)
+                 self._headers.update(dict((k, [v]) for (k, v) in headers))
+                 r = (r,) # chunking should be much larger than per character
+@@ -796,7 +796,7 @@ class HTTPResponse(BaseResponse):
+         encoding = getCharsetUsingRequest(self._request) or 'utf-8'
+         content_type = self.getHeader('content-type')
+ 
+-        if isinstance(body, unicode):
++        if isinstance(body, str):
+             if not unicode_mimetypes_re.match(content_type):
+                 raise ValueError(
+                     'Unicode results must have a text, RFC 3023, or '
+@@ -818,7 +818,7 @@ class HTTPResponse(BaseResponse):
+ 
+             params['charset'] = encoding
+             content_type = "%s/%s;" % (major, minor)
+-            content_type += ";".join(k + "=" + v for k, v in params.items())
++            content_type += ";".join(k + "=" + v for k, v in list(params.items()))
+ 
+         if content_type:
+             headers = [('content-type', content_type),
+@@ -833,13 +833,13 @@ class HTTPResponse(BaseResponse):
+         Calls self.setBody() with an error response.
+         """
+         t, v = exc_info[:2]
+-        if isinstance(t, (types.ClassType, type)):
++        if isinstance(t, type):
+             if issubclass(t, Redirect):
+                 self.redirect(v.getLocation())
+                 return
+             title = tname = t.__name__
+         else:
+-            title = tname = unicode(t)
++            title = tname = str(t)
+ 
+         # Throwing non-protocol-specific exceptions is a good way
+         # for apps to control the status code.
+@@ -851,15 +851,15 @@ class HTTPResponse(BaseResponse):
+ 
+     def internalError(self):
+         'See IPublisherResponse'
+-        self.setStatus(500, u"The engines can't take any more, Jim!")
++        self.setStatus(500, "The engines can't take any more, Jim!")
+ 
+     def _html(self, title, content):
+         t = cgi.escape(title)
+         return (
+-            u"<html><head><title>%s</title></head>\n"
+-            u"<body><h2>%s</h2>\n"
+-            u"%s\n"
+-            u"</body></html>\n" %
++            "<html><head><title>%s</title></head>\n"
++            "<body><h2>%s</h2>\n"
++            "%s\n"
++            "</body></html>\n" %
+             (t, t, content)
+             )
+ 
+@@ -900,14 +900,14 @@ class HTTPResponse(BaseResponse):
+ 
+     def _cookie_list(self):
+         try:
+-            c = Cookie.SimpleCookie()
+-        except Cookie.CookieError, e:
++            c = http.cookies.SimpleCookie()
++        except http.cookies.CookieError as e:
+             eventlog.warn(e)
+             return []
+-        for name, attrs in self._cookies.items():
++        for name, attrs in list(self._cookies.items()):
+             name = str(name)
+             c[name] = attrs['value'].encode(ENCODING)
+-            for k,v in attrs.items():
++            for k,v in list(attrs.items()):
+                 if k == 'value':
+                     continue
+                 if k == 'secure':
+@@ -918,7 +918,7 @@ class HTTPResponse(BaseResponse):
+                     k = 'max-age'
+                 elif k == 'comment':
+                     # Encode rather than throw an exception
+-                    v = urllib.quote(v.encode('utf-8'), safe="/?:@&+")
++                    v = urllib.parse.quote(v.encode('utf-8'), safe="/?:@&+")
+                 c[name][k] = str(v)
+         return str(c).splitlines()
+ 
+@@ -938,7 +938,7 @@ def sort_charsets(x, y):
+ 
+ 
+ def extract_host(url):
+-    scheme, host, path, query, fragment = urlparse.urlsplit(url)
++    scheme, host, path, query, fragment = urllib.parse.urlsplit(url)
+     if ':' not in host:
+         port = DEFAULT_PORTS.get(scheme)
+         if port:
+--- src/zope/publisher/interfaces/__init__.py.orig	2012-07-02 06:19:42 UTC
++++ src/zope/publisher/interfaces/__init__.py
+@@ -60,10 +60,10 @@ class NotFound(LookupError, TraversalException):
+ 
+     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():
+--- src/zope/publisher/publish.py.orig	2012-07-02 06:19:44 UTC
++++ src/zope/publisher/publish.py
+@@ -64,8 +64,8 @@ def mapply(obj, positional=(), request={}):
+ 
+     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 +154,7 @@ def publish(request, handle_errors=True):
+ 
+                     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 +187,7 @@ def publish(request, handle_errors=True):
+ 
+         response = request.response
+         if to_raise is not None:
+-            raise to_raise[0], to_raise[1], to_raise[2]
++            raise to_raise[0](to_raise[1]).with_traceback(to_raise[2])
+ 
+     finally:
+         to_raise = None  # Avoid circ. ref.
+--- src/zope/publisher/tests/test_browserrequest.py.orig	2012-07-02 06:19:44 UTC
++++ src/zope/publisher/tests/test_browserrequest.py
+@@ -14,7 +14,7 @@
+ 
+ import sys
+ import unittest
+-from StringIO import StringIO
++from io import StringIO
+ 
+ from zope.interface import implements, directlyProvides, Interface
+ from zope.interface.verify import verifyObject
+@@ -101,12 +101,12 @@ class BrowserTests(HTTPTests):
+         class Item(object):
+             """Required docstring for the publisher."""
+             def __call__(self, a, b):
+-                return u"%s, %s" % (`a`, `b`)
++                return "%s, %s" % (repr(a), repr(b))
+ 
+         class Item3(object):
+             """Required docstring for the publisher."""
+             def __call__(self, *args):
+-                return u"..."
++                return "..."
+ 
+         class View(object):
+             """Required docstring for the publisher."""
+@@ -115,7 +115,7 @@ class BrowserTests(HTTPTests):
+ 
+             def index(self, a, b):
+                 """Required docstring for the publisher."""
+-                return u"%s, %s" % (`a`, `b`)
++                return "%s, %s" % (repr(a), repr(b))
+ 
+         class Item2(object):
+             """Required docstring for the publisher."""
+@@ -145,7 +145,7 @@ class BrowserTests(HTTPTests):
+ 
+     def testTraversalToItem(self):
+         res = self._publisherResults()
+-        self.failUnlessEqual(
++        self.assertEqual(
+             res,
+             "Status: 200 Ok\r\n"
+             "Content-Length: 7\r\n"
+@@ -159,7 +159,7 @@ class BrowserTests(HTTPTests):
+         request = self._createRequest()
+         response = request.response
+         publish(request)
+-        self.failIf(response.getBase())
++        self.assertFalse(response.getBase())
+ 
+     def testDefault(self):
+         extra = {'PATH_INFO': '/folder/item2'}
+@@ -183,7 +183,7 @@ class BrowserTests(HTTPTests):
+         should be catched"""
+ 
+         extra = {'REQUEST_METHOD':'POST',
+-                 'PATH_INFO': u'/',
++                 'PATH_INFO': '/',
+                  'CONTENT_TYPE': 'multipart/form-data;\
+                  boundary=---------------------------1'}
+ 
+@@ -201,17 +201,17 @@ class BrowserTests(HTTPTests):
+         its filename."""
+ 
+         extra = {'REQUEST_METHOD':'POST',
+-                 'PATH_INFO': u'/',
++                 'PATH_INFO': '/',
+                  'CONTENT_TYPE': 'multipart/form-data;\
+                  boundary=---------------------------1'}
+ 
+         request  = self._createRequest(extra, body=LARGE_FILE_BODY)
+         request.processInputs()
+-        self.assert_(request.form['upload'].name)
++        self.assertTrue(request.form['upload'].name)
+ 
+         request  = self._createRequest(extra, body=IE_FILE_BODY)
+         request.processInputs()
+-        self.assertEquals(request.form['upload'].filename, 'notepad.exe')
++        self.assertEqual(request.form['upload'].filename, 'notepad.exe')
+ 
+ 
+     def testDefault2(self):
+@@ -227,14 +227,14 @@ class BrowserTests(HTTPTests):
+         request = self._createRequest(extra)
+         response = request.response
+         publish(request)
+-        self.failIf(response.getBase())
++        self.assertFalse(response.getBase())
+ 
+     def testDefault4(self):
+         extra = {'PATH_INFO': '/folder/item2/view/'}
+         request = self._createRequest(extra)
+         response = request.response
+         publish(request)
+-        self.failIf(response.getBase())
++        self.assertFalse(response.getBase())
+ 
+     def testDefault6(self):
+         extra = {'PATH_INFO': '/folder/item2/'}
+@@ -258,7 +258,7 @@ class BrowserTests(HTTPTests):
+         request = self._createRequest()
+         publish(request)
+         self.assertEqual(request.form,
+-                         {u'a':u'5', u'b':6})
++                         {'a':'5', 'b':6})
+ 
+     def testFormNoEncodingUsesUTF8(self):
+         encoded = 'K\xc3\x83\xc2\xb6hlerstra\xc3\x83\xc2\x9fe'
+@@ -271,8 +271,8 @@ class BrowserTests(HTTPTests):
+         # many mainstream browsers do not send HTTP_ACCEPT_CHARSET
+         del request._environ['HTTP_ACCEPT_CHARSET']
+         publish(request)
+-        self.assert_(isinstance(request.form[u'street'], unicode))
+-        self.assertEqual(unicode(encoded, 'utf-8'), request.form['street'])
++        self.assertTrue(isinstance(request.form['street'], str))
++        self.assertEqual(str(encoded, 'utf-8'), request.form['street'])
+ 
+     def testFormAcceptsStarButNotUTF8(self):
+         extra = {
+@@ -287,100 +287,100 @@ class BrowserTests(HTTPTests):
+         extra = {'QUERY_STRING':'a:list=5&a:list=6&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a':[u'5',u'6'], u'b':u'1'})
++        self.assertEqual(request.form, {'a':['5','6'], 'b':'1'})
+ 
+     def testQueryStringIgnoredForPOST(self):
+         request = self._createRequest(
+             {"REQUEST_METHOD": "POST",
+              'PATH_INFO': '/folder/item3'}, body='c=5&d:int=6')
+         publish(request)
+-        self.assertEqual(request.form, {u'c': u'5', u'd': 6})
++        self.assertEqual(request.form, {'c': '5', 'd': 6})
+         self.assertEqual(request.get('QUERY_STRING'), 'a=5&b:int=6')
+ 
+     def testFormTupleTypes(self):
+         extra = {'QUERY_STRING':'a:tuple=5&a:tuple=6&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a':(u'5',u'6'), u'b':u'1'})
++        self.assertEqual(request.form, {'a':('5','6'), 'b':'1'})
+ 
+     def testFormTupleRecordTypes(self):
+         extra = {'QUERY_STRING':'a.x:tuple:record=5&a.x:tuple:record=6&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        keys = request.form.keys()
++        keys = list(request.form.keys())
+         keys.sort()
+-        self.assertEqual(keys, [u'a',u'b'])
+-        self.assertEqual(request.form[u'b'], u'1')
+-        self.assertEqual(request.form[u'a'].keys(), [u'x'])
+-        self.assertEqual(request.form[u'a'][u'x'], (u'5',u'6'))
+-        self.assertEqual(request.form[u'a'].x, (u'5',u'6'))
+-        self.assertEqual(str(request.form[u'a']), "{x: (u'5', u'6')}")
+-        self.assertEqual(repr(request.form[u'a']), "{x: (u'5', u'6')}")
++        self.assertEqual(keys, ['a','b'])
++        self.assertEqual(request.form['b'], '1')
++        self.assertEqual(list(request.form['a'].keys()), ['x'])
++        self.assertEqual(request.form['a']['x'], ('5','6'))
++        self.assertEqual(request.form['a'].x, ('5','6'))
++        self.assertEqual(str(request.form['a']), "{x: (u'5', u'6')}")
++        self.assertEqual(repr(request.form['a']), "{x: (u'5', u'6')}")
+ 
+     def testFormRecordsTypes(self):
+         extra = {'QUERY_STRING':'a.x:records=5&a.x:records=6&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        keys = request.form.keys()
++        keys = list(request.form.keys())
+         keys.sort()
+-        self.assertEqual(keys, [u'a',u'b'])
+-        self.assertEqual(request.form[u'b'], u'1')
+-        self.assertEqual(len(request.form[u'a']), 2)
+-        self.assertEqual(request.form[u'a'][0][u'x'], u'5')
+-        self.assertEqual(request.form[u'a'][0].x, u'5')
+-        self.assertEqual(request.form[u'a'][1][u'x'], u'6')
+-        self.assertEqual(request.form[u'a'][1].x, u'6')
+-        self.assertEqual(str(request.form[u'a']), "[{x: u'5'}, {x: u'6'}]")
+-        self.assertEqual(repr(request.form[u'a']), "[{x: u'5'}, {x: u'6'}]")
++        self.assertEqual(keys, ['a','b'])
++        self.assertEqual(request.form['b'], '1')
++        self.assertEqual(len(request.form['a']), 2)
++        self.assertEqual(request.form['a'][0]['x'], '5')
++        self.assertEqual(request.form['a'][0].x, '5')
++        self.assertEqual(request.form['a'][1]['x'], '6')
++        self.assertEqual(request.form['a'][1].x, '6')
++        self.assertEqual(str(request.form['a']), "[{x: u'5'}, {x: u'6'}]")
++        self.assertEqual(repr(request.form['a']), "[{x: u'5'}, {x: u'6'}]")
+ 
+     def testFormMultipleRecordsTypes(self):
+         extra = {'QUERY_STRING':'a.x:records:int=5&a.y:records:int=51'
+             '&a.x:records:int=6&a.y:records:int=61&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        keys = request.form.keys()
++        keys = list(request.form.keys())
+         keys.sort()
+-        self.assertEqual(keys, [u'a',u'b'])
+-        self.assertEqual(request.form[u'b'], u'1')
+-        self.assertEqual(len(request.form[u'a']), 2)
+-        self.assertEqual(request.form[u'a'][0][u'x'], 5)
+-        self.assertEqual(request.form[u'a'][0].x, 5)
+-        self.assertEqual(request.form[u'a'][0][u'y'], 51)
+-        self.assertEqual(request.form[u'a'][0].y, 51)
+-        self.assertEqual(request.form[u'a'][1][u'x'], 6)
+-        self.assertEqual(request.form[u'a'][1].x, 6)
+-        self.assertEqual(request.form[u'a'][1][u'y'], 61)
+-        self.assertEqual(request.form[u'a'][1].y, 61)
+-        self.assertEqual(str(request.form[u'a']),
++        self.assertEqual(keys, ['a','b'])
++        self.assertEqual(request.form['b'], '1')
++        self.assertEqual(len(request.form['a']), 2)
++        self.assertEqual(request.form['a'][0]['x'], 5)
++        self.assertEqual(request.form['a'][0].x, 5)
++        self.assertEqual(request.form['a'][0]['y'], 51)
++        self.assertEqual(request.form['a'][0].y, 51)
++        self.assertEqual(request.form['a'][1]['x'], 6)
++        self.assertEqual(request.form['a'][1].x, 6)
++        self.assertEqual(request.form['a'][1]['y'], 61)
++        self.assertEqual(request.form['a'][1].y, 61)
++        self.assertEqual(str(request.form['a']),
+             "[{x: 5, y: 51}, {x: 6, y: 61}]")
+-        self.assertEqual(repr(request.form[u'a']),
++        self.assertEqual(repr(request.form['a']),
+             "[{x: 5, y: 51}, {x: 6, y: 61}]")
+ 
+     def testFormListRecordTypes(self):
+         extra = {'QUERY_STRING':'a.x:list:record=5&a.x:list:record=6&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        keys = request.form.keys()
++        keys = list(request.form.keys())
+         keys.sort()
+-        self.assertEqual(keys, [u'a',u'b'])
+-        self.assertEqual(request.form[u'b'], u'1')
+-        self.assertEqual(request.form[u'a'].keys(), [u'x'])
+-        self.assertEqual(request.form[u'a'][u'x'], [u'5',u'6'])
+-        self.assertEqual(request.form[u'a'].x, [u'5',u'6'])
+-        self.assertEqual(str(request.form[u'a']), "{x: [u'5', u'6']}")
+-        self.assertEqual(repr(request.form[u'a']), "{x: [u'5', u'6']}")
++        self.assertEqual(keys, ['a','b'])
++        self.assertEqual(request.form['b'], '1')
++        self.assertEqual(list(request.form['a'].keys()), ['x'])
++        self.assertEqual(request.form['a']['x'], ['5','6'])
++        self.assertEqual(request.form['a'].x, ['5','6'])
++        self.assertEqual(str(request.form['a']), "{x: [u'5', u'6']}")
++        self.assertEqual(repr(request.form['a']), "{x: [u'5', u'6']}")
+ 
+     def testFormListTypes2(self):
+         extra = {'QUERY_STRING':'a=5&a=6&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a':[u'5',u'6'], u'b':u'1'})
++        self.assertEqual(request.form, {'a':['5','6'], 'b':'1'})
+ 
+     def testFormIntTypes(self):
+         extra = {'QUERY_STRING':'a:int=5&b:int=-5&c:int=0&d:int=-0'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a': 5, u'b': -5, u'c': 0, u'd': 0})
++        self.assertEqual(request.form, {'a': 5, 'b': -5, 'c': 0, 'd': 0})
+ 
+         extra = {'QUERY_STRING':'a:int='}
+         request = self._createRequest(extra)
+@@ -394,7 +394,7 @@ class BrowserTests(HTTPTests):
+         extra = {'QUERY_STRING':'a:float=5&b:float=-5.01&c:float=0'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a': 5.0, u'b': -5.01, u'c': 0.0})
++        self.assertEqual(request.form, {'a': 5.0, 'b': -5.01, 'c': 0.0})
+ 
+         extra = {'QUERY_STRING':'a:float='}
+         request = self._createRequest(extra)
+@@ -408,7 +408,7 @@ class BrowserTests(HTTPTests):
+         extra = {'QUERY_STRING':'a:long=99999999999999&b:long=0L'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a': 99999999999999, u'b': 0})
++        self.assertEqual(request.form, {'a': 99999999999999, 'b': 0})
+ 
+         extra = {'QUERY_STRING':'a:long='}
+         request = self._createRequest(extra)
+@@ -422,27 +422,27 @@ class BrowserTests(HTTPTests):
+         extra = {'QUERY_STRING':'a:tokens=a%20b%20c%20d&b:tokens='}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a': [u'a', u'b', u'c', u'd'],
+-                         u'b': []})
++        self.assertEqual(request.form, {'a': ['a', 'b', 'c', 'd'],
++                         'b': []})
+ 
+     def testFormStringTypes(self):
+         extra = {'QUERY_STRING':'a:string=test&b:string='}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a': u'test', u'b': u''})
++        self.assertEqual(request.form, {'a': 'test', 'b': ''})
+ 
+     def testFormLinesTypes(self):
+         extra = {'QUERY_STRING':'a:lines=a%0ab%0ac%0ad&b:lines='}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a': [u'a', u'b', u'c', u'd'],
+-                         u'b': []})
++        self.assertEqual(request.form, {'a': ['a', 'b', 'c', 'd'],
++                         'b': []})
+ 
+     def testFormTextTypes(self):
+         extra = {'QUERY_STRING':'a:text=a%0a%0db%0d%0ac%0dd%0ae&b:text='}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a': u'a\nb\nc\nd\ne', u'b': u''})
++        self.assertEqual(request.form, {'a': 'a\nb\nc\nd\ne', 'b': ''})
+ 
+     def testFormRequiredTypes(self):
+         extra = {'QUERY_STRING':'a:required=%20'}
+@@ -453,33 +453,33 @@ class BrowserTests(HTTPTests):
+         extra = {'QUERY_STRING':'a:boolean=&b:boolean=1&c:boolean=%20'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a': False, u'b': True, u'c': True})
++        self.assertEqual(request.form, {'a': False, 'b': True, 'c': True})
+ 
+     def testFormDefaults(self):
+         extra = {'QUERY_STRING':'a:default=10&a=6&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a':u'6', u'b':u'1'})
++        self.assertEqual(request.form, {'a':'6', 'b':'1'})
+ 
+     def testFormDefaults2(self):
+         extra = {'QUERY_STRING':'a:default=10&b=1'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a':u'10', u'b':u'1'})
++        self.assertEqual(request.form, {'a':'10', 'b':'1'})
+ 
+     def testFormFieldName(self):
+         extra = {'QUERY_STRING':'c+%2B%2F%3D%26c%3Aint=6',
+                  'PATH_INFO': '/folder/item3/'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'c +/=&c': 6})
++        self.assertEqual(request.form, {'c +/=&c': 6})
+ 
+     def testFormFieldValue(self):
+         extra = {'QUERY_STRING':'a=b+%2B%2F%3D%26b%3Aint',
+                  'PATH_INFO': '/folder/item3/'}
+         request = self._createRequest(extra)
+         publish(request)
+-        self.assertEqual(request.form, {u'a':u'b +/=&b:int'})
++        self.assertEqual(request.form, {'a':'b +/=&b:int'})
+ 
+     def testInterface(self):
+         request = self._createRequest()
+@@ -506,7 +506,7 @@ class BrowserTests(HTTPTests):
+         request = self._createRequest(extra)
+         publish(request)
+         self.assertEqual(request.headers.get('HTTP_REFERER'), 'http://localhost/')
+-        self.assertEqual(request.form, {u'HTTP_REFERER': u'peter'})
++        self.assertEqual(request.form, {'HTTP_REFERER': 'peter'})
+ 
+ 
+     def test_post_body_not_consumed_unnecessarily(self):
+--- src/zope/publisher/tests/test_http.py.orig	2012-07-02 06:19:44 UTC
++++ src/zope/publisher/tests/test_http.py
+@@ -17,8 +17,8 @@
+ import sys
+ import tempfile
+ import unittest
+-from cStringIO import StringIO
+-from Cookie import CookieError
++from io import StringIO
++from http.cookies import CookieError
+ from doctest import DocFileSuite
+ 
+ import zope.event
+@@ -128,19 +128,19 @@ class HTTPInputStreamTests(unittest.TestCase):
+ 
+         # HTTPInputStream understands both CONTENT_LENGTH...
+         stream = HTTPInputStream(StringIO(data), {'CONTENT_LENGTH': '100000'})
+-        self.assert_(isinstance(stream.getCacheStream(), TempFileType))
++        self.assertTrue(isinstance(stream.getCacheStream(), TempFileType))
+ 
+         # ... and HTTP_CONTENT_LENGTH.
+         stream = HTTPInputStream(StringIO(data), {'HTTP_CONTENT_LENGTH':
+                                                   '100000'})
+-        self.assert_(isinstance(stream.getCacheStream(), TempFileType))
++        self.assertTrue(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'})
+-        self.assert_(isinstance(stream.getCacheStream(), TempFileType))
++        self.assertTrue(isinstance(stream.getCacheStream(), TempFileType))
+ 
+         # In fact, HTTPInputStream can be instantiated with both an
+         # empty CONTENT_LENGTH and an empty HTTP_CONTENT_LENGTH:
+@@ -165,7 +165,7 @@ class HTTPInputStreamTests(unittest.TestCase):
+                 return 'a'*size
+ 
+         stream = HTTPInputStream(NonClosingStream(), {'CONTENT_LENGTH': '10'})
+-        self.assertEquals(stream.getCacheStream().read(), 'aaaaaaaaaa')
++        self.assertEqual(stream.getCacheStream().read(), 'aaaaaaaaaa')
+         stream = HTTPInputStream(NonClosingStream(), {})
+         self.assertRaises(ServerHung, stream.getCacheStream)
+ 
+@@ -194,7 +194,7 @@ class HTTPTests(unittest.TestCase):
+         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()
+@@ -252,7 +252,7 @@ class HTTPTests(unittest.TestCase):
+ 
+     def testTraversalToItem(self):
+         res = self._publisherResults()
+-        self.failUnlessEqual(
++        self.assertEqual(
+             res,
+             "Status: 200 Ok\r\n"
+             "Content-Length: 6\r\n"
+@@ -266,27 +266,27 @@ class HTTPTests(unittest.TestCase):
+ 
+         request = self._createRequest(env, '')
+         location = request.response.redirect('http://foobar.com/redirected')
+-        self.assertEquals(location, 'http://foobar.com/redirected')
+-        self.assertEquals(request.response.getStatus(), 302)
+-        self.assertEquals(request.response.getHeader('location'), location)
++        self.assertEqual(location, 'http://foobar.com/redirected')
++        self.assertEqual(request.response.getStatus(), 302)
++        self.assertEqual(request.response.getHeader('location'), location)
+ 
+         # test HTTP/1.1
+         env = {'SERVER_PROTOCOL':'HTTP/1.1'}
+ 
+         request = self._createRequest(env, '')
+         location = request.response.redirect('http://foobar.com/redirected')
+-        self.assertEquals(request.response.getStatus(), 303)
++        self.assertEqual(request.response.getStatus(), 303)
+ 
+         # test explicit status
+         request = self._createRequest(env, '')
+         request.response.redirect('http://foobar.com/explicit', 304)
+-        self.assertEquals(request.response.getStatus(), 304)
++        self.assertEqual(request.response.getStatus(), 304)
+ 
+         # test non-string location, like URLGetter
+         request = self._createRequest(env, '')
+         request.response.redirect(request.URL)
+-        self.assertEquals(request.response.getStatus(), 303)
+-        self.assertEquals(request.response.getHeader('location'),
++        self.assertEqual(request.response.getStatus(), 303)
++        self.assertEqual(request.response.getHeader('location'),
+                           str(request.URL))
+ 
+     def testUntrustedRedirect(self):
+@@ -301,81 +301,81 @@ class HTTPTests(unittest.TestCase):
+         # host. They aren't really allowed per RFC but the response object
+         # supports them and people are probably using them.
+         location = request.response.redirect('/foo', trusted=False)
+-        self.assertEquals('/foo', location)
++        self.assertEqual('/foo', location)
+ 
+         # If we pass `trusted` for the redirect, we can redirect the browser
+         # anywhere we want, though.
+         location = request.response.redirect(
+             'http://my-friends.com', trusted=True)
+-        self.assertEquals('http://my-friends.com', location)
++        self.assertEqual('http://my-friends.com', location)
+ 
+         # We can redirect to our own full server URL, with or without a port
+         # being specified. Let's explicitly set a host name to test this is
+         # this is how virtual hosting works:
+         request.setApplicationServer('example.com')
+         location = request.response.redirect('http://example.com')
+-        self.assertEquals('http://example.com', location)
++        self.assertEqual('http://example.com', location)
+ 
+         request.setApplicationServer('example.com', port=8080)
+         location = request.response.redirect('http://example.com:8080')
+-        self.assertEquals('http://example.com:8080', location)
++        self.assertEqual('http://example.com:8080', location)
+ 
+         # The default port for HTTP and HTTPS may be omitted:
+         request.setApplicationServer('example.com')
+         location = request.response.redirect('http://example.com:80')
+-        self.assertEquals('http://example.com:80', location)
++        self.assertEqual('http://example.com:80', location)
+ 
+         request.setApplicationServer('example.com', port=80)
+         location = request.response.redirect('http://example.com')
+-        self.assertEquals('http://example.com', location)
++        self.assertEqual('http://example.com', location)
+ 
+         request.setApplicationServer('example.com', 'https')
+         location = request.response.redirect('https://example.com:443')
+-        self.assertEquals('https://example.com:443', location)
++        self.assertEqual('https://example.com:443', location)
+ 
+         request.setApplicationServer('example.com', 'https', 443)
+         location = request.response.redirect('https://example.com')
+-        self.assertEquals('https://example.com', location)
++        self.assertEqual('https://example.com', location)
+ 
+     def testUnregisteredStatus(self):
+         # verify we can set the status to an unregistered int value
+         request = self._createRequest({}, '')
+         request.response.setStatus(289)
+-        self.assertEquals(request.response.getStatus(), 289)
++        self.assertEqual(request.response.getStatus(), 289)
+ 
+     def testRequestEnvironment(self):
+         req = self._createRequest()
+         publish(req, handle_errors=0) # Force expansion of URL variables
+ 
+-        self.assertEquals(str(req.URL), 'http://foobar.com/folder/item')
+-        self.assertEquals(req.URL['-1'], 'http://foobar.com/folder')
+-        self.assertEquals(req.URL['-2'], 'http://foobar.com')
++        self.assertEqual(str(req.URL), 'http://foobar.com/folder/item')
++        self.assertEqual(req.URL['-1'], 'http://foobar.com/folder')
++        self.assertEqual(req.URL['-2'], 'http://foobar.com')
+         self.assertRaises(KeyError, req.URL.__getitem__, '-3')
+ 
+-        self.assertEquals(req.URL['0'], 'http://foobar.com')
+-        self.assertEquals(req.URL['1'], 'http://foobar.com/folder')
+-        self.assertEquals(req.URL['2'], 'http://foobar.com/folder/item')
++        self.assertEqual(req.URL['0'], 'http://foobar.com')
++        self.assertEqual(req.URL['1'], 'http://foobar.com/folder')
++        self.assertEqual(req.URL['2'], 'http://foobar.com/folder/item')
+         self.assertRaises(KeyError, req.URL.__getitem__, '3')
+ 
+-        self.assertEquals(req.URL.get('0'), 'http://foobar.com')
+-        self.assertEquals(req.URL.get('1'), 'http://foobar.com/folder')
+-        self.assertEquals(req.URL.get('2'), 'http://foobar.com/folder/item')
+-        self.assertEquals(req.URL.get('3', 'none'), 'none')
++        self.assertEqual(req.URL.get('0'), 'http://foobar.com')
++        self.assertEqual(req.URL.get('1'), 'http://foobar.com/folder')
++        self.assertEqual(req.URL.get('2'), 'http://foobar.com/folder/item')
++        self.assertEqual(req.URL.get('3', 'none'), 'none')
+ 
+-        self.assertEquals(req['SERVER_URL'], 'http://foobar.com')
+-        self.assertEquals(req['HTTP_HOST'], 'foobar.com')
+-        self.assertEquals(req['PATH_INFO'], '/folder/item')
+-        self.assertEquals(req['CONTENT_LENGTH'], '0')
++        self.assertEqual(req['SERVER_URL'], 'http://foobar.com')
++        self.assertEqual(req['HTTP_HOST'], 'foobar.com')
++        self.assertEqual(req['PATH_INFO'], '/folder/item')
++        self.assertEqual(req['CONTENT_LENGTH'], '0')
+         self.assertRaises(KeyError, req.__getitem__, 'HTTP_AUTHORIZATION')
+-        self.assertEquals(req['GATEWAY_INTERFACE'], 'TestFooInterface/1.0')
+-        self.assertEquals(req['HTTP_OFF_THE_WALL'], "Spam 'n eggs")
++        self.assertEqual(req['GATEWAY_INTERFACE'], 'TestFooInterface/1.0')
++        self.assertEqual(req['HTTP_OFF_THE_WALL'], "Spam 'n eggs")
+ 
+         self.assertRaises(KeyError, req.__getitem__,
+                           'HTTP_WE_DID_NOT_PROVIDE_THIS')
+ 
+     def testRequestLocale(self):
+         eq = self.assertEqual
+-        unless = self.failUnless
++        unless = self.assertTrue
+ 
+         from zope.publisher.browser import BrowserLanguages
+         from zope.publisher.interfaces.http import IHTTPRequest
+@@ -448,17 +448,17 @@ class HTTPTests(unittest.TestCase):
+         }
+         req = self._createRequest(extra_env=cookies)
+ 
+-        self.assertEquals(req.cookies[u'foo'], u'bar')
+-        self.assertEquals(req[u'foo'], u'bar')
++        self.assertEqual(req.cookies['foo'], 'bar')
++        self.assertEqual(req['foo'], 'bar')
+ 
+-        self.assertEquals(req.cookies[u'spam'], u'eggs')
+-        self.assertEquals(req[u'spam'], u'eggs')
++        self.assertEqual(req.cookies['spam'], 'eggs')
++        self.assertEqual(req['spam'], 'eggs')
+ 
+-        self.assertEquals(req.cookies[u'this'], u'Should be accepted')
+-        self.assertEquals(req[u'this'], u'Should be accepted')
++        self.assertEqual(req.cookies['this'], 'Should be accepted')
++        self.assertEqual(req['this'], 'Should be accepted')
+ 
+         # Reserved key
+-        self.failIf(req.cookies.has_key('path'))
++        self.assertFalse('path' in req.cookies)
+ 
+     def testCookieErrorToLog(self):
+         cookies = {
+@@ -467,23 +467,23 @@ class HTTPTests(unittest.TestCase):
+         }
+         req = self._createRequest(extra_env=cookies)
+ 
+-        self.failIf(req.cookies.has_key('foo'))
+-        self.failIf(req.has_key('foo'))
++        self.assertFalse('foo' in req.cookies)
++        self.assertFalse('foo' in req)
+ 
+-        self.failIf(req.cookies.has_key('spam'))
+-        self.failIf(req.has_key('spam'))
++        self.assertFalse('spam' in req.cookies)
++        self.assertFalse('spam' in req)
+ 
+-        self.failIf(req.cookies.has_key('ldap/OU'))
+-        self.failIf(req.has_key('ldap/OU'))
++        self.assertFalse('ldap/OU' in req.cookies)
++        self.assertFalse('ldap/OU' in req)
+ 
+         # Reserved key
+-        self.failIf(req.cookies.has_key('path'))
++        self.assertFalse('path' in req.cookies)
+ 
+     def testCookiesUnicode(self):
+         # Cookie values are assumed to be UTF-8 encoded
+         cookies = {'HTTP_COOKIE': r'key="\342\230\243";'}
+         req = self._createRequest(extra_env=cookies)
+-        self.assertEquals(req.cookies[u'key'], u'\N{BIOHAZARD SIGN}')
++        self.assertEqual(req.cookies['key'], '\N{BIOHAZARD SIGN}')
+ 
+     def testHeaders(self):
+         headers = {
+@@ -491,13 +491,13 @@ class HTTPTests(unittest.TestCase):
+             'Another-Test': 'another',
+         }
+         req = self._createRequest(extra_env=headers)
+-        self.assertEquals(req.headers[u'TEST_HEADER'], u'test')
+-        self.assertEquals(req.headers[u'TEST-HEADER'], u'test')
+-        self.assertEquals(req.headers[u'test_header'], u'test')
+-        self.assertEquals(req.getHeader('TEST_HEADER', literal=True), u'test')
+-        self.assertEquals(req.getHeader('TEST-HEADER', literal=True), None)
+-        self.assertEquals(req.getHeader('test_header', literal=True), None)
+-        self.assertEquals(req.getHeader('Another-Test', literal=True),
*** 549 LINES SKIPPED ***