From d2bbf339c9d505f495d3fccf7543d53242655744 Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Wed, 11 Sep 2019 08:33:47 +0200 Subject: [PATCH] Drop Python 2 support Part 1 (#699) * Grep for `2.7` and remove places for Python 2 support. Additionally removed also a bit of Zope 2.7 support code. * Drop usage of code referencing `PY2`. --- docs/INSTALL.rst | 13 +------ docs/operation.rst | 2 +- docs/zope4/news.rst | 11 +++--- src/App/Management.py | 17 +++------ src/OFS/CopySupport.py | 10 +---- src/OFS/DTMLDocument.py | 4 -- src/OFS/DTMLMethod.py | 7 ---- src/OFS/Image.py | 24 ++---------- src/OFS/ObjectManager.py | 21 +++++----- src/OFS/PropertyManager.py | 18 ++++----- src/OFS/PropertySheets.py | 32 ++++++++-------- src/OFS/SimpleItem.py | 16 ++------ src/OFS/Uninstalled.py | 8 +--- src/OFS/role.py | 10 ++--- src/OFS/tests/testFileAndImage.py | 1 - src/OFS/tests/testFindSupport.py | 2 - src/OFS/tests/testObjectManager.py | 38 ++----------------- src/Products/Five/browser/adding.py | 16 -------- src/Products/Five/viewlet/viewlet.py | 7 +--- .../tests/test_persistenttemplate.py | 13 ++----- src/Testing/ZopeTestCase/ZopeLite.py | 5 --- src/Testing/ZopeTestCase/functional.py | 4 -- src/Testing/ZopeTestCase/testZODBCompat.py | 24 ++++-------- src/ZPublisher/BaseResponse.py | 5 --- src/ZPublisher/Converters.py | 24 +++++------- src/ZPublisher/HTTPRequest.py | 11 ------ src/ZPublisher/HTTPResponse.py | 34 +++-------------- src/ZPublisher/tests/testHTTPRequest.py | 11 +----- src/ZPublisher/tests/test_Converters.py | 4 -- src/ZPublisher/tests/test_mapply.py | 25 ------------ src/ZPublisher/tests/test_utils.py | 7 +--- src/ZTUtils/Zope.py | 13 ++----- src/ZTUtils/tests/testZope.py | 26 +++---------- src/Zope2/App/tests/test_safe_formatter.py | 9 ----- src/Zope2/Startup/datatypes.py | 7 ---- src/Zope2/Startup/starter.py | 7 +--- src/Zope2/Startup/tests/test_serve.py | 7 +--- src/Zope2/Startup/tests/test_starter.py | 23 +---------- 38 files changed, 107 insertions(+), 409 deletions(-) diff --git a/docs/INSTALL.rst b/docs/INSTALL.rst index d4f6409e94..6c311ed99a 100644 --- a/docs/INSTALL.rst +++ b/docs/INSTALL.rst @@ -16,8 +16,7 @@ available: - A supported version of Python, including the development support if installed from system-level packages. Supported versions include: - * 2.7 - * 3.5 - 3.8 + * 3.5 up to 3.8 - Zope needs the Python ``zlib`` module to be importable. If you are building your own Python from source, please be sure that you have the @@ -72,11 +71,6 @@ Built-in standard buildout configuration $ bin/pip install -U pip zc.buildout $ bin/buildout -.. note:: - - When using Python 2.7 instead of calling ``python3.7 -m venv .`` you have to - install `virtualenv` and then call ``python2.7 -m virtualenv .``. - Custom buildout configurations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -175,11 +169,6 @@ version you find on https://zopefoundation.github.io/Zope/: $ bin/pip install Zope==4.1 \ -c https://zopefoundation.github.io/Zope/releases/4.1/constraints.txt -.. note:: - - When using Python 2.7 instead of calling ``python3.7 -m venv zope`` you have - to install `virtualenv` and then call ``python2.7 -m virtualenv zope``. - You can also install Zope using a single requirements file. Note that this installation method might install packages that are not actually needed (i. e. more than are listed in the ``install_requires`` section of ``setup.py``): diff --git a/docs/operation.rst b/docs/operation.rst index 0ac36bc435..0fb6ec4fbc 100644 --- a/docs/operation.rst +++ b/docs/operation.rst @@ -401,7 +401,7 @@ done. Troubleshooting --------------- -- This version of Zope requires Python 2.7 or Python 3.5 and later. +- This version of Zope requires Python 3.5 and later. It will *not* run with any version of PyPy. - To build Python extensions you need to have Python configuration diff --git a/docs/zope4/news.rst b/docs/zope4/news.rst index 6dcb53c30e..06e9e91a96 100644 --- a/docs/zope4/news.rst +++ b/docs/zope4/news.rst @@ -29,15 +29,14 @@ found in this release. Extended Python version support ------------------------------- -Zope 4 supports Python 2.7 and Python 3.5 up to Python 3.8. +Zope 5 supports Python 3.5 up to Python 3.8. The Python 3 support currently covers the core dependencies shipped -with Zope and is limited to the new WSGI based publisher. The new -external ZServer project is currently limited to Python 2.7 compatibility -and likely to stay that way. +with Zope and is limited to the new WSGI based publisher. -Migrating an existing ZODB to Python 3 is not an automated process. Please -consult :ref:`zope4zodbmigration` for details. +Migrating an existing ZODB to Python 3 is not an automated process. You have +to update to Zope 4 first, see +`Zope 4 migration `_. WSGI as the new default server type diff --git a/src/App/Management.py b/src/App/Management.py index a405d007fc..4389ece2ea 100644 --- a/src/App/Management.py +++ b/src/App/Management.py @@ -13,6 +13,7 @@ """Standard management interface support """ +import html import itertools import six @@ -32,12 +33,6 @@ from zope.interface import implementer -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - - class Tabs(Base): """Mix-in provides management folder tab support.""" @@ -99,7 +94,7 @@ def tabs_path_default(self, REQUEST): steps = REQUEST._steps[:-1] script = REQUEST['BASEPATH1'] linkpat = '{}/manage_workspace' - yield {'url': linkpat.format(escape(script, True)), + yield {'url': linkpat.format(html.escape(script, True)), 'title': 'Root', 'last': not bool(steps)} if not steps: @@ -107,12 +102,12 @@ def tabs_path_default(self, REQUEST): last = steps.pop() for step in steps: script = '%s/%s' % (script, step) - yield {'url': linkpat.format(escape(script, True)), - 'title': escape(unquote(step)), + yield {'url': linkpat.format(html.escape(script, True)), + 'title': html.escape(unquote(step)), 'last': False} script = '%s/%s' % (script, last) - yield {'url': linkpat.format(escape(script, True)), - 'title': escape(unquote(last)), + yield {'url': linkpat.format(html.escape(script, True)), + 'title': html.escape(unquote(last)), 'last': True} def tabs_path_info(self, script, path): diff --git a/src/OFS/CopySupport.py b/src/OFS/CopySupport.py index 09003eccdd..a108e8a82d 100644 --- a/src/OFS/CopySupport.py +++ b/src/OFS/CopySupport.py @@ -671,10 +671,7 @@ def _cb_encode(d): json_bytes = dumps(d).encode('utf-8') squashed_bytes = compress(json_bytes, 2) # -> bytes w/ useful encoding # quote for embeding in cookie - if six.PY2: - return quote(squashed_bytes) - else: - return quote(squashed_bytes.decode('latin-1')) + return quote(squashed_bytes.decode('latin-1')) def _cb_decode(s, maxsize=8192): @@ -686,10 +683,7 @@ def _cb_decode(s, maxsize=8192): Return a list of text IDs. """ dec = decompressobj() - if six.PY2: - squashed = unquote(s) - else: - squashed = unquote(s).encode('latin-1') + squashed = unquote(s).encode('latin-1') data = dec.decompress(squashed, maxsize) if dec.unconsumed_tail: raise ValueError diff --git a/src/OFS/DTMLDocument.py b/src/OFS/DTMLDocument.py index fda8103747..2810d77076 100644 --- a/src/OFS/DTMLDocument.py +++ b/src/OFS/DTMLDocument.py @@ -13,7 +13,6 @@ """DTML Document objects. """ -import six from six.moves.urllib.parse import quote from AccessControl import getSecurityManager @@ -103,9 +102,6 @@ def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw): c = self.content_type else: encoding = getattr(self, 'encoding', default_encoding) - if six.PY2 and not isinstance(r, six.text_type): - # Prevent double-encoding edge cases under Python 2 - r = r.decode(encoding) c, e = guess_content_type(self.getId(), r.encode(encoding)) RESPONSE.setHeader('Content-Type', c) result = decapitate(r, RESPONSE) diff --git a/src/OFS/DTMLMethod.py b/src/OFS/DTMLMethod.py index 8b6b0366e2..b8b1d1ee4f 100644 --- a/src/OFS/DTMLMethod.py +++ b/src/OFS/DTMLMethod.py @@ -14,10 +14,8 @@ """ import re -from six import PY2 from six import PY3 from six import binary_type -from six import text_type from six.moves.urllib.parse import quote from AccessControl import getSecurityManager @@ -190,9 +188,6 @@ def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw): c = self.content_type else: encoding = getattr(self, 'encoding', default_encoding) - if PY2 and not isinstance(r, text_type): - # Prevent double-encoding edge cases under Python 2 - r = r.decode(encoding) c, e = guess_content_type(self.getId(), r.encode(encoding)) RESPONSE.setHeader('Content-Type', c) result = decapitate(r, RESPONSE) @@ -430,8 +425,6 @@ def safe_file_data(data): data = data.read() if PY3 and isinstance(data, binary_type): data = data.decode('utf-8') - if PY2 and isinstance(data, text_type): - data = data.encode('utf-8') return data diff --git a/src/OFS/Image.py b/src/OFS/Image.py index b7013af626..8eb54d802f 100644 --- a/src/OFS/Image.py +++ b/src/OFS/Image.py @@ -13,11 +13,11 @@ """Image object """ +import html import struct from email.generator import _make_boundary from io import BytesIO -from six import PY2 from six import binary_type from six import text_type @@ -49,12 +49,6 @@ from ZPublisher.HTTPRequest import FileUpload -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - - manage_addFileForm = DTMLFile( 'dtml/imageAdd', globals(), @@ -669,10 +663,7 @@ def __bytes__(self): return bytes(self.data) def __str__(self): - if PY2: - return str(self.data) - else: - return self.data.decode(self._get_encoding()) + return self.data.decode(self._get_encoding()) def __bool__(self): return True @@ -944,11 +935,11 @@ def tag( if alt is None: alt = getattr(self, 'alt', '') - result = '%s alt="%s"' % (result, escape(alt, True)) + result = '%s alt="%s"' % (result, html.escape(alt, True)) if title is None: title = getattr(self, 'title', '') - result = '%s title="%s"' % (result, escape(title, True)) + result = '%s title="%s"' % (result, html.escape(title, True)) if height: result = '%s height="%s"' % (result, height) @@ -989,10 +980,6 @@ class Pdata(Persistent, Implicit): def __init__(self, data): self.data = data - if PY2: - def __getslice__(self, i, j): - return self.data[i:j] - def __getitem__(self, key): return self.data[key] @@ -1012,6 +999,3 @@ def __bytes__(self): _next = self.next return b''.join(r) - - if PY2: - __str__ = __bytes__ diff --git a/src/OFS/ObjectManager.py b/src/OFS/ObjectManager.py index 2423d6fbb8..289912c27b 100644 --- a/src/OFS/ObjectManager.py +++ b/src/OFS/ObjectManager.py @@ -13,6 +13,7 @@ """Object Manager """ +import html import os import re from io import BytesIO @@ -63,12 +64,6 @@ from zope.lifecycleevent import ObjectRemovedEvent -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - - # Constants: __replaceable__ flags: NOT_REPLACEABLE = 0 REPLACEABLE = 1 @@ -94,12 +89,12 @@ def checkValidId(self, id, allow_dup=0): # set to false before the object is added. if not id or not isinstance(id, str): if isinstance(id, text_type): - id = escape(id, True) + id = html.escape(id, True) raise BadRequest('Empty or invalid id specified', id) if bad_id(id) is not None: raise BadRequest( ('The id "%s" contains characters ' - 'illegal in URLs.' % escape(id, True))) + 'illegal in URLs.' % html.escape(id, True))) if id in ('.', '..'): raise BadRequest( 'The id "%s" is invalid because it is not traversable.' % id) @@ -557,7 +552,8 @@ def manage_delObjects(self, ids=[], REQUEST=None): pass if v is self: - raise BadRequest('%s does not exist' % escape(ids[-1], True)) + raise BadRequest('%s does not exist' % + html.escape(ids[-1], True)) self._delObject(id) del ids[-1] if REQUEST is not None: @@ -642,14 +638,17 @@ def manage_importObject(self, file, REQUEST=None, set_owner=1, """Import an object from a file""" dirname, file = os.path.split(file) if dirname: - raise BadRequest('Invalid file name %s' % escape(file, True)) + raise BadRequest('Invalid file name %s' % html.escape(file, True)) for impath in self._getImportPaths(): filepath = os.path.join(impath, 'import', file) if os.path.exists(filepath): break else: - raise BadRequest('File does not exist: %s' % escape(file, True)) + raise BadRequest( + 'File does not exist: %s' % + html.escape( + file, True)) imported = self._importObjectFromFile( filepath, verify=bool(REQUEST), set_owner=set_owner, diff --git a/src/OFS/PropertyManager.py b/src/OFS/PropertyManager.py index ca001527b6..a89b841bc9 100644 --- a/src/OFS/PropertyManager.py +++ b/src/OFS/PropertyManager.py @@ -13,6 +13,8 @@ """Property management """ +import html + import six from AccessControl.class_init import InitializeClass @@ -30,12 +32,6 @@ from ZPublisher.Converters import type_converters -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - - @implementer(IPropertyManager) class PropertyManager(Base): """ @@ -138,7 +134,7 @@ def valid_property_id(self, id): id[:3] == 'aq_' or \ ' ' in id or \ hasattr(aq_base(self), id) or \ - escape(id, True) != id: + html.escape(id, True) != id: return 0 return 1 @@ -215,7 +211,7 @@ def _updateProperty(self, id, value): self._wrapperCheck(value) if not self.hasProperty(id): raise BadRequest( - 'The property %s does not exist' % escape(id, True)) + 'The property %s does not exist' % html.escape(id, True)) if isinstance(value, (six.string_types, six.binary_type)): proptype = self.getPropertyType(id) or 'string' if proptype in type_converters: @@ -225,7 +221,7 @@ def _updateProperty(self, id, value): def _delProperty(self, id): if not self.hasProperty(id): raise ValueError( - 'The property %s does not exist' % escape(id, True)) + 'The property %s does not exist' % html.escape(id, True)) self._delPropValue(id) self._properties = tuple(i for i in self._properties if i['id'] != id) @@ -339,7 +335,7 @@ def manage_changeProperties(self, REQUEST=None, **kw): if self.hasProperty(name): if 'w' not in propdict[name].get('mode', 'wd'): raise BadRequest( - '%s cannot be changed' % escape(name, True)) + '%s cannot be changed' % html.escape(name, True)) self._updateProperty(name, value) if REQUEST: @@ -385,7 +381,7 @@ def manage_delProperties(self, ids=None, REQUEST=None): if not hasattr(aq_base(self), id): raise BadRequest( ('The property %s ' - 'does not exist' % escape(id, True))) + 'does not exist' % html.escape(id, True))) if ('d' not in propdict[id].get('mode', 'wd')) or (id in nd): raise BadRequest('Cannot delete %s' % id) self._delProperty(id) diff --git a/src/OFS/PropertySheets.py b/src/OFS/PropertySheets.py index f9b84815d3..d346d5b36a 100644 --- a/src/OFS/PropertySheets.py +++ b/src/OFS/PropertySheets.py @@ -13,6 +13,8 @@ """Property sheets """ +import html + import six from AccessControl.class_init import InitializeClass @@ -32,12 +34,6 @@ from ZPublisher.Converters import type_converters -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - - class Virtual(object): """A virtual propertysheet stores it's properties in it's instance.""" @@ -160,7 +156,7 @@ def p_self(self): def valid_property_id(self, id): if not id or id[:1] == '_' or (id[:3] == 'aq_') \ - or (' ' in id) or escape(id, True) != id: + or (' ' in id) or html.escape(id, True) != id: return 0 return 1 @@ -202,7 +198,10 @@ def _setProperty(self, id, value, type='string', meta=None): # systems. self._wrapperCheck(value) if not self.valid_property_id(id): - raise BadRequest('Invalid property id, %s.' % escape(id, True)) + raise BadRequest( + 'Invalid property id, %s.' % + html.escape( + id, True)) if not self.property_extensible_schema__(): raise BadRequest( @@ -213,7 +212,7 @@ def _setProperty(self, id, value, type='string', meta=None): if not (id == 'title' and id not in self.__dict__): raise BadRequest( 'Invalid property id, %s. It is in use.' % - escape(id, True)) + html.escape(id, True)) if meta is None: meta = {} prop = {'id': id, 'type': type, 'meta': meta} @@ -241,10 +240,10 @@ def _updateProperty(self, id, value, meta=None): self._wrapperCheck(value) if not self.hasProperty(id): raise BadRequest('The property %s does not exist.' % - escape(id, True)) + html.escape(id, True)) propinfo = self.propertyInfo(id) if 'w' not in propinfo.get('mode', 'wd'): - raise BadRequest('%s cannot be changed.' % escape(id, True)) + raise BadRequest('%s cannot be changed.' % html.escape(id, True)) if isinstance(value, (six.string_types, six.binary_type)): proptype = propinfo.get('type', 'string') if proptype in type_converters: @@ -267,14 +266,14 @@ def _delProperty(self, id): # given id does not exist, a ValueError is raised. if not self.hasProperty(id): raise BadRequest('The property %s does not exist.' % - escape(id, True)) + html.escape(id, True)) vself = self.v_self() if hasattr(vself, '_reserved_names'): nd = vself._reserved_names else: nd = () if ('d' not in self.propertyInfo(id).get('mode', 'wd')) or (id in nd): - raise BadRequest('%s cannot be deleted.' % escape(id, True)) + raise BadRequest('%s cannot be deleted.' % html.escape(id, True)) delattr(vself, id) pself = self.p_self() pself._properties = tuple( @@ -302,7 +301,10 @@ def propertyInfo(self, id): for p in self._propertyMap(): if p['id'] == id: return p - raise ValueError('The property %s does not exist.' % escape(id, True)) + raise ValueError( + 'The property %s does not exist.' % + html.escape( + id, True)) def _propertyMap(self): """Return a tuple of mappings, giving meta-data for properties.""" @@ -366,7 +368,7 @@ def manage_changeProperties(self, REQUEST=None, **kw): if self.hasProperty(name): if 'w' not in propdict[name].get('mode', 'wd'): raise BadRequest('%s cannot be changed' % - escape(name, True)) + html.escape(name, True)) self._updateProperty(name, value) message = 'Your changes have been saved.' return self.manage(self, REQUEST, manage_tabs_message=message) diff --git a/src/OFS/SimpleItem.py b/src/OFS/SimpleItem.py index 08a989aa67..e79df0159b 100644 --- a/src/OFS/SimpleItem.py +++ b/src/OFS/SimpleItem.py @@ -179,19 +179,11 @@ def title_and_id(self): title = title() id = self.getId() # Make sure we don't blindly concatenate encoded and unencoded data - # This may happen under Python 2 where the id is encoded but the - # title is unencoded. if title and type(id) is not type(title): - if six.PY2: - if isinstance(id, six.text_type): - id = id.encode(default_encoding) - if isinstance(title, six.text_type): - title = title.encode(default_encoding) - else: - if isinstance(id, six.binary_type): - id = id.decode(default_encoding) - if isinstance(title, six.binary_type): - title = title.decode(default_encoding) + if isinstance(id, six.binary_type): + id = id.decode(default_encoding) + if isinstance(title, six.binary_type): + title = title.decode(default_encoding) return title and ("%s (%s)" % (title, id)) or id def this(self): diff --git a/src/OFS/Uninstalled.py b/src/OFS/Uninstalled.py index 072f0874fe..33d8c304d6 100644 --- a/src/OFS/Uninstalled.py +++ b/src/OFS/Uninstalled.py @@ -13,6 +13,7 @@ """ Objects for packages that have been uninstalled. """ +import html from logging import getLogger from six import exec_ @@ -27,11 +28,6 @@ from ZODB.broken import persistentBroken -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - broken_klasses = {} broken_klasses_lock = allocate_lock() LOG = getLogger('OFS.Uninstalled') @@ -50,7 +46,7 @@ class BrokenClass(ZODB_Broken, Explicit, Item, Overridable): def __getattr__(self, name): if name[:3] == '_p_': return BrokenClass.inheritedAttribute('__getattr__')(self, name) - raise AttributeError(escape(name, True)) + raise AttributeError(html.escape(name, True)) manage = DTMLFile('dtml/brokenEdit', globals()) manage_main = DTMLFile('dtml/brokenEdit', globals()) diff --git a/src/OFS/role.py b/src/OFS/role.py index 45464d45de..a46ca9a001 100644 --- a/src/OFS/role.py +++ b/src/OFS/role.py @@ -13,6 +13,8 @@ """Role manager """ +import html + from AccessControl import ClassSecurityInfo from AccessControl.class_init import InitializeClass from AccessControl.Permission import Permission @@ -25,12 +27,6 @@ from zExceptions import BadRequest -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - - class RoleManager(BaseRoleManager): """An object that has configurable permissions""" @@ -143,7 +139,7 @@ def manage_changePermissions(self, REQUEST): if fails: raise BadRequest('Some permissions had errors: ' - + escape(', '.join(fails), True)) + + html.escape(', '.join(fails), True)) if REQUEST is not None: return self.manage_access(REQUEST) diff --git a/src/OFS/tests/testFileAndImage.py b/src/OFS/tests/testFileAndImage.py index 7958e3abaa..935f96c8a2 100644 --- a/src/OFS/tests/testFileAndImage.py +++ b/src/OFS/tests/testFileAndImage.py @@ -360,7 +360,6 @@ def test_Image__manage_main__1(self): text = self.browser.getControl(name='filedata:text').value self.assertEqual(text, 'hällo') - @unittest.skipIf(six.PY2, "feature not supported on Python 2") def test_Image__manage_main__3(self): """It shows an error message if the file content cannot be decoded.""" self.app.file.update_data(u'hällo'.encode('latin-1')) diff --git a/src/OFS/tests/testFindSupport.py b/src/OFS/tests/testFindSupport.py index 7432a4ed25..850a968187 100644 --- a/src/OFS/tests/testFindSupport.py +++ b/src/OFS/tests/testFindSupport.py @@ -65,7 +65,6 @@ def test_find_text(self): self.assertEqual(len(res), 2) self.assertEqual(set([x[0] for x in res]), set(['doc1', 'doc2'])) - @unittest.skipIf(six.PY2, 'Not applicable under Python 2') def test_find_text_nonascii(self): # Make sure ZopeFind can handle text and encoded text (binary) data unencoded = u'\xfcml\xe4\xfct' @@ -77,7 +76,6 @@ def test_find_text_nonascii(self): self.assertEqual(len(res), 2) self.assertEqual(set([x[0] for x in res]), set(['text', 'bytes'])) - @unittest.skipIf(six.PY2, 'Not applicable under Python 2') def test_find_text_nondecodable(self): # Make sure ZopeFind does not crash searching text in nondecodable data encoded = b'\xf6' diff --git a/src/OFS/tests/testObjectManager.py b/src/OFS/tests/testObjectManager.py index c011b8a160..76a0b0735c 100644 --- a/src/OFS/tests/testObjectManager.py +++ b/src/OFS/tests/testObjectManager.py @@ -3,7 +3,6 @@ import unittest from logging import getLogger -from six import PY2 from six.moves.urllib.parse import quote from AccessControl.owner import EmergencyUserCannotOwn @@ -436,10 +435,7 @@ def test_iterator(self): om['2'] = si2 iterator = iter(om) self.assertTrue(hasattr(iterator, '__iter__')) - if PY2: - self.assertTrue(hasattr(iterator, 'next')) - else: - self.assertTrue(hasattr(iterator, '__next__')) + self.assertTrue(hasattr(iterator, '__next__')) result = [i for i in iterator] self.assertTrue('1' in result) self.assertTrue('2' in result) @@ -580,42 +576,16 @@ def test_empty_string(self): self.assertEqual(str(e), "('Empty or invalid id specified', '')") - @unittest.skipUnless(PY2, 'Python 3 cannot handle bytestrings here.') - def test_unicode_py2(self): - e = self.assertBadRequest(u'abc☃') - self.assertEqual( - str(e), "('Empty or invalid id specified', u'abc\\u2603')") - - @unittest.skipIf(PY2, 'Python 2 cannot handle unicode / text here.') - def test_unicode_py3(self): + def test_unicode(self): self._callFUT(self._makeContainer(), u'abc☃') - @unittest.skipUnless(PY2, 'Python 3 cannot handle bytestrings here.') - def test_encoded_unicode_py2(self): - self._callFUT(self._makeContainer(), u'abcö'.encode('utf-8')) - - @unittest.skipIf(PY2, 'Python 2 cannot handle unicode / text here.') - def test_encoded_unicode_py3(self): + def test_encoded_unicode(self): e = self.assertBadRequest(u'abcö'.encode('utf-8')) self.assertEqual(str(e), "('Empty or invalid id specified', " "b'abc\\xc3\\xb6')") - @unittest.skipUnless(PY2, 'Python 3 cannot handle bytestrings here.') - def test_unprintable_characters_py2(self): - # We do not allow the first 31 ASCII characters. \x00-\x19 - # We do not allow the DEL character. \x7f - e = self.assertBadRequest('abc\x10') - self.assertEqual(str(e), - 'The id "abc\x10" contains characters illegal' - ' in URLs.') - e = self.assertBadRequest('abc\x7f') - self.assertEqual(str(e), - 'The id "abc\x7f" contains characters illegal' - ' in URLs.') - - @unittest.skipIf(PY2, 'Python 2 cannot handle unicode / text here.') - def test_unprintable_characters_py3(self): + def test_unprintable_characters(self): # We do not allow the first 31 ASCII characters. \x00-\x19 # We do not allow the DEL character. \x7f e = self.assertBadRequest(u'abc\x10') diff --git a/src/Products/Five/browser/adding.py b/src/Products/Five/browser/adding.py index 407d6022ec..422f2d55af 100644 --- a/src/Products/Five/browser/adding.py +++ b/src/Products/Five/browser/adding.py @@ -21,8 +21,6 @@ import operator -from six import PY2 - from OFS.SimpleItem import SimpleItem from Products.Five import BrowserView from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile @@ -209,14 +207,6 @@ def __init__(self, context): self.context = context def checkName(self, name, object): - if PY2: - # ObjectManager can only deal with ASCII names. Specially - # ObjectManager._checkId can only deal with strings. - try: - name = name.encode('ascii') - except UnicodeDecodeError: - raise UserError("Id must contain only ASCII characters.") - try: self.context._checkId(name, allow_dup=False) except BadRequest as e: @@ -226,12 +216,6 @@ def checkName(self, name, object): def chooseName(self, name, object): if not name: name = object.__class__.__name__ - else: - if PY2: - try: - name = name.encode('ascii') - except UnicodeDecodeError: - raise UserError("Id must contain only ASCII characters.") dot = name.rfind('.') if dot >= 0: diff --git a/src/Products/Five/viewlet/viewlet.py b/src/Products/Five/viewlet/viewlet.py index 459c44243f..37c47a5170 100644 --- a/src/Products/Five/viewlet/viewlet.py +++ b/src/Products/Five/viewlet/viewlet.py @@ -16,8 +16,6 @@ import os -import six - import zope.viewlet.viewlet from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile @@ -32,10 +30,7 @@ class SimpleAttributeViewlet(zope.viewlet.viewlet.SimpleAttributeViewlet): class simple(zope.viewlet.viewlet.simple): # We need to ensure that the proper __init__ is called. - if six.PY2: - __init__ = ViewletBase.__init__.__func__ - else: - __init__ = ViewletBase.__init__ + __init__ = ViewletBase.__init__ def SimpleViewletClass(template, bases=(), attributes=None, name=u''): diff --git a/src/Products/PageTemplates/tests/test_persistenttemplate.py b/src/Products/PageTemplates/tests/test_persistenttemplate.py index e936425331..83400e7425 100644 --- a/src/Products/PageTemplates/tests/test_persistenttemplate.py +++ b/src/Products/PageTemplates/tests/test_persistenttemplate.py @@ -1,3 +1,4 @@ +import html import io import re import unittest @@ -7,12 +8,6 @@ from Testing.ZopeTestCase import ZopeTestCase -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - - macro_outer = """ @@ -128,7 +123,7 @@ def test_simple(self): result = template().strip() self.assertEqual(result, u'Hello, World') editable_text = get_editable_content(template) - self.assertEqual(editable_text, escape(simple_i18n, False)) + self.assertEqual(editable_text, html.escape(simple_i18n, False)) def test_escape_on_edit(self): # check that escapable chars can round-trip intact. @@ -136,7 +131,7 @@ def test_escape_on_edit(self): template = self._makeOne('foo', source) self.assertEqual(template(), source) # nothing to render editable_text = get_editable_content(template) - self.assertEqual(editable_text, escape(source, False)) + self.assertEqual(editable_text, html.escape(source, False)) def test_macro_with_i18n(self): self._makeOne('macro_outer', macro_outer) @@ -221,7 +216,7 @@ def test_edit_with_errors(self): editable_text = get_editable_content(template) # and the errors should be in an xml comment at the start of # the editable text - error_prefix = escape( + error_prefix = html.escape( '\n'.format( '\n '.join(template._v_errors) ), diff --git a/src/Testing/ZopeTestCase/ZopeLite.py b/src/Testing/ZopeTestCase/ZopeLite.py index 19f3610189..40425245e1 100644 --- a/src/Testing/ZopeTestCase/ZopeLite.py +++ b/src/Testing/ZopeTestCase/ZopeLite.py @@ -27,7 +27,6 @@ import sys import time -from six import PY2 from six import exec_ import App.ProductContext # NOQA @@ -55,10 +54,6 @@ # Allow code to tell it is run by the test framework os.environ['ZOPETESTCASE'] = '1' -# Increase performance on MP hardware -if PY2: - sys.setcheckinterval(2500) - # Always shut up _quiet = True diff --git a/src/Testing/ZopeTestCase/functional.py b/src/Testing/ZopeTestCase/functional.py index 24e6fbbcf7..0ced9acfcd 100644 --- a/src/Testing/ZopeTestCase/functional.py +++ b/src/Testing/ZopeTestCase/functional.py @@ -18,8 +18,6 @@ import sys from functools import partial -from six import PY2 - import transaction from Testing.ZopeTestCase import interfaces from Testing.ZopeTestCase import sandbox @@ -176,8 +174,6 @@ def getCookie(self, name): return self.cookies.get(name) def _decode(self, data): - if PY2: - return data # This is a hack. This method is called to print a response # as part of a doctest. But if that response contains an # actual binary body, like a GIF image, there's no good diff --git a/src/Testing/ZopeTestCase/testZODBCompat.py b/src/Testing/ZopeTestCase/testZODBCompat.py index 8160c70460..a879d4606e 100644 --- a/src/Testing/ZopeTestCase/testZODBCompat.py +++ b/src/Testing/ZopeTestCase/testZODBCompat.py @@ -139,23 +139,13 @@ def afterClear(self): os.rmdir(self.import_dir) except OSError: pass - try: - import App.config - except ImportError: - # Restore builtins - builtins = getattr(__builtins__, '__dict__', __builtins__) - if hasattr(self, '_ih'): - builtins['INSTANCE_HOME'] = self._ih - if hasattr(self, '_ch'): - builtins['CLIENT_HOME'] = self._ch - else: - # Zope >= 2.7 - config = App.config.getConfiguration() - if hasattr(self, '_ih'): - config.instancehome = self._ih - if hasattr(self, '_ch'): - config.clienthome = self._ch - App.config.setConfiguration(config) + import App.config + config = App.config.getConfiguration() + if hasattr(self, '_ih'): + config.instancehome = self._ih + if hasattr(self, '_ch'): + config.clienthome = self._ch + App.config.setConfiguration(config) class TestAttributesOfCleanObjects(ZopeTestCase.ZopeTestCase): diff --git a/src/ZPublisher/BaseResponse.py b/src/ZPublisher/BaseResponse.py index 346f71174f..ea29993c1f 100644 --- a/src/ZPublisher/BaseResponse.py +++ b/src/ZPublisher/BaseResponse.py @@ -13,7 +13,6 @@ '''CGI Response Output formatter ''' -from six import PY2 from six import text_type from zExceptions import BadRequest @@ -109,10 +108,6 @@ def getBody(self): def __bytes__(self): return bytes(self.body) - if PY2: - def __str__(self): - return str(self.body) - def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self.body) diff --git a/src/ZPublisher/Converters.py b/src/ZPublisher/Converters.py index 883e94b26e..075dd3ed4c 100644 --- a/src/ZPublisher/Converters.py +++ b/src/ZPublisher/Converters.py @@ -11,9 +11,9 @@ # ############################################################################## +import html import re -import six from six import binary_type from six import text_type @@ -21,11 +21,6 @@ from DateTime.interfaces import SyntaxError -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - # This may get overwritten during configuration default_encoding = 'utf-8' @@ -37,9 +32,7 @@ def field2string(v): """ if hasattr(v, 'read'): return v.read() - elif six.PY2 and isinstance(v, text_type): - return v.encode(default_encoding) - elif six.PY3 and isinstance(v, binary_type): + elif isinstance(v, binary_type): return v.decode(default_encoding) else: return str(v) @@ -93,7 +86,7 @@ def field2int(v): return int(v) except ValueError: raise ValueError( - "An integer was expected in the value %r" % escape( + "An integer was expected in the value %r" % html.escape( v, quote=True ) ) @@ -110,7 +103,7 @@ def field2float(v): except ValueError: raise ValueError( "A floating-point number was expected in the value %r" % - escape(v, True) + html.escape(v, True) ) raise ValueError( 'Empty entry when floating-point number expected') @@ -128,8 +121,9 @@ def field2long(v): return int(v) except ValueError: raise ValueError( - "A long integer was expected in the value %r" % escape(v, True) - ) + "A long integer was expected in the value %r" % + html.escape( + v, True)) raise ValueError('Empty entry when integer expected') @@ -152,7 +146,7 @@ def field2date(v): try: v = DateTime(v) except SyntaxError: - raise SyntaxError("Invalid DateTime " + escape(repr(v), True)) + raise SyntaxError("Invalid DateTime " + html.escape(repr(v), True)) return v @@ -161,7 +155,7 @@ def field2date_international(v): try: v = DateTime(v, datefmt="international") except SyntaxError: - raise SyntaxError("Invalid DateTime " + escape(repr(v))) + raise SyntaxError("Invalid DateTime " + html.escape(repr(v))) return v diff --git a/src/ZPublisher/HTTPRequest.py b/src/ZPublisher/HTTPRequest.py index 2336f54944..7b968f2b1f 100644 --- a/src/ZPublisher/HTTPRequest.py +++ b/src/ZPublisher/HTTPRequest.py @@ -22,7 +22,6 @@ from cgi import FieldStorage from copy import deepcopy -from six import PY2 from six import PY3 from six import binary_type from six import string_types @@ -1699,16 +1698,6 @@ def __bool__(self): def __next__(self): return self.file.__next__() - if PY2: - def __nonzero__(self): - return self.__bool__() - - def next(self): - return self.file.next() - - def xreadlines(self): - return self - QPARMRE = re.compile( '([\x00- ]*([^\x00- ;,="]+)="([^"]*)"([\x00- ]*[;,])?[\x00- ]*)') diff --git a/src/ZPublisher/HTTPResponse.py b/src/ZPublisher/HTTPResponse.py index 26d148f44a..638f4e496a 100644 --- a/src/ZPublisher/HTTPResponse.py +++ b/src/ZPublisher/HTTPResponse.py @@ -12,6 +12,7 @@ ############################################################################## """ CGI Response Output formatter """ +import html import os import re import struct @@ -20,8 +21,6 @@ import zlib from io import BytesIO -from six import PY2 -from six import PY3 from six import binary_type from six import class_types from six import reraise @@ -45,11 +44,6 @@ from ZPublisher.Iterators import IUnboundStreamIterator -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - if sys.version_info >= (3, ): from io import IOBase else: @@ -207,9 +201,7 @@ def redirect(self, location, status=302, lock=0): status = location.getStatus() location = location.headers['Location'] - if PY2 and isinstance(location, text_type): - location = location.encode(self.charset) - elif PY3 and isinstance(location, binary_type): + if isinstance(location, binary_type): location = location.decode(self.charset) # To be entirely correct, we must make sure that all non-ASCII @@ -289,10 +281,6 @@ def setCookie(self, name, value, quoted=True, **kw): `value` may be text or bytes. The default encoding of respective python version is used. """ - if PY2: - name = str(name) - value = str(value) - cookies = self.cookies if name in cookies: cookie = cookies[name] @@ -316,10 +304,6 @@ def appendCookie(self, name, value): `value` may be text or bytes. The default encoding of respective python version is used. """ - if PY2: - name = str(name) - value = str(value) - cookies = self.cookies if name in cookies: cookie = cookies[name] @@ -343,9 +327,6 @@ def expireCookie(self, name, **kw): `name` has to be text in Python 3. """ - if PY2: - name = str(name) - d = kw.copy() if 'value' in d: d.pop('value') @@ -457,7 +438,7 @@ def insertBase(self): ibase = base_re_search(text) if ibase is None: text = (text[:index] + '\n\n' + + html.escape(self.base, True) + '" />\n' + text[index:]) self.text = text self.setHeader('content-length', len(self.body)) @@ -761,12 +742,9 @@ def __bytes__(self): chunks.append(body) return b'\r\n'.join(chunks) - if PY2: - __str__ = __bytes__ - # deprecated def quoteHTML(self, text): - return escape(text, 1) + return html.escape(text, 1) def _traceback(self, t, v, tb, as_html=1): tb = format_exception(t, v, tb, as_html=as_html) @@ -803,7 +781,7 @@ def notFoundError(self, entry='Unknown'): "Resource not found", ("Sorry, the requested resource does not exist." "

Check the URL and try again.

" - "

Resource: " + escape(entry) + "

"))) + "

Resource: " + html.escape(entry) + "

"))) # If a resource is forbidden, why reveal that it exists? forbiddenError = notFoundError @@ -967,7 +945,7 @@ def notFoundError(self, entry='Unknown'): exc.detail = ( 'Sorry, the requested resource does not exist.' '

Check the URL and try again.

' - '

Resource: %s

' % escape(entry, True)) + '

Resource: %s

' % html.escape(entry, True)) raise exc # If a resource is forbidden, why reveal that it exists? diff --git a/src/ZPublisher/tests/testHTTPRequest.py b/src/ZPublisher/tests/testHTTPRequest.py index 94ec860d0e..7a4986fdc3 100644 --- a/src/ZPublisher/tests/testHTTPRequest.py +++ b/src/ZPublisher/tests/testHTTPRequest.py @@ -16,8 +16,6 @@ from contextlib import contextmanager from io import BytesIO -from six import PY2 - from AccessControl.tainted import should_be_tainted from zExceptions import NotFound from zope.component import getGlobalSiteManager @@ -304,13 +302,8 @@ def test_processInputs_w_simple_marshalling(self): self._onlyTaintedformHoldsTaintedStrings(req) def test_processInputs_w_unicode_conversions(self): - # This tests native strings, which mean something different - # under Python 2 / 3. - if PY2: - reg_char = '\xc2\xae' - else: - reg_char = '\xae' - + # This tests native strings. + reg_char = '\xae' inputs = (('ustring:ustring:utf8', 'test' + reg_char), ('utext:utext:utf8', 'test' + reg_char + '\ntest' + reg_char + '\n'), diff --git a/src/ZPublisher/tests/test_Converters.py b/src/ZPublisher/tests/test_Converters.py index add58de7b7..a86817cb50 100644 --- a/src/ZPublisher/tests/test_Converters.py +++ b/src/ZPublisher/tests/test_Converters.py @@ -13,7 +13,6 @@ import unittest -from six import PY2 from six import PY3 from six import text_type @@ -215,9 +214,6 @@ def test_field2text_with_string_with_newlines(self): if PY3: expected = 'abc\ndef\nghi' self.assertEqual(field2text(to_convert), expected) - if PY2: - expected = b'abc\ndef\nghi' - self.assertEqual(field2text(to_convert), expected) def test_field2ulines_with_list(self): from ZPublisher.Converters import field2ulines diff --git a/src/ZPublisher/tests/test_mapply.py b/src/ZPublisher/tests/test_mapply.py index d31f6d61b6..7ce1b54bdd 100644 --- a/src/ZPublisher/tests/test_mapply.py +++ b/src/ZPublisher/tests/test_mapply.py @@ -14,8 +14,6 @@ import unittest -from six import PY2 - import Acquisition import ExtensionClass from ZPublisher.mapply import mapply @@ -54,29 +52,6 @@ def __call__(self, b, c=4): v = mapply(cc.compute, (), values) self.assertEqual(v, '334') - @unittest.skipUnless(PY2, 'Testing old-style class.') - def testOldStyleClass(self): - # Testing old-style class behavior. - values = {'a': 2, 'b': 3, 'c': 5} - - class c(object): - a = 3 - - def __call__(self, b, c=4): - return '%d%d%d' % (self.a, b, c) - - compute = __call__ - - cc = c() - - class c2: - """Must be a classic class.""" - - c2inst = c2() - c2inst.__call__ = cc - v = mapply(c2inst, (), values) - self.assertEqual(v, '335') - def testObjectWithCall(self): # Make sure that the __call__ of an object can also be another # callable object. mapply will do the right thing and diff --git a/src/ZPublisher/tests/test_utils.py b/src/ZPublisher/tests/test_utils.py index 018486f932..19fccc4d2f 100644 --- a/src/ZPublisher/tests/test_utils.py +++ b/src/ZPublisher/tests/test_utils.py @@ -15,8 +15,6 @@ import unittest -from six import PY2 - class SafeUnicodeTests(unittest.TestCase): @@ -35,8 +33,5 @@ def test_unicode(self): self.assertEqual(self._makeOne(u'foö'), u'foö') def test_utf_8(self): - if PY2: - self.assertEqual(self._makeOne('test\xc2\xae'), u'test\xae') - else: - self.assertEqual(self._makeOne('test\xc2\xae'), u'test\xc2\xae') + self.assertEqual(self._makeOne('test\xc2\xae'), u'test\xc2\xae') self.assertEqual(self._makeOne(b'test\xc2\xae'), u'test\xae') diff --git a/src/ZTUtils/Zope.py b/src/ZTUtils/Zope.py index 06e31bdfc0..c315dd2dac 100644 --- a/src/ZTUtils/Zope.py +++ b/src/ZTUtils/Zope.py @@ -13,7 +13,8 @@ """Zope-specific versions of ZTUTils classes """ -from six import PY2 +import html + from six import binary_type from six import text_type from six.moves.urllib.parse import quote @@ -31,12 +32,6 @@ from ZTUtils.Tree import encodeExpansion -try: - from html import escape -except ImportError: # PY2 - from cgi import escape - - class LazyFilter(Lazy): # A LazyFilter that checks with the security policy @@ -216,8 +211,6 @@ def make_query(*args, **kwargs): qlist = complex_marshal(list(d.items())) for i in range(len(qlist)): k, m, v = qlist[i] - if PY2 and isinstance(v, text_type): - v = v.encode(_default_encoding()) qlist[i] = '%s%s=%s' % (quote(k), m, quote(str(v))) return '&'.join(qlist) @@ -242,7 +235,7 @@ def make_hidden_input(*args, **kwargs): d.update(kwargs) def hq(x): - return escape(x, quote=True) + return html.escape(x, quote=True) qlist = complex_marshal(list(d.items())) for i in range(len(qlist)): diff --git a/src/ZTUtils/tests/testZope.py b/src/ZTUtils/tests/testZope.py index a14eae8255..bddd2e37e8 100644 --- a/src/ZTUtils/tests/testZope.py +++ b/src/ZTUtils/tests/testZope.py @@ -1,6 +1,5 @@ import unittest -from six import PY2 from six.moves.urllib.parse import quote from DateTime import DateTime @@ -28,10 +27,7 @@ def testMarshalDate(self): self.assertEqual(simple_marshal(DateTime()), ":date") def testMarshalUnicode(self): - if PY2: - arg_type = ':utf8:ustring' - else: - arg_type = '' + arg_type = '' self.assertEqual(simple_marshal(u'unic\xF3de'), arg_type) def testMarshallLists(self): @@ -39,10 +35,7 @@ def testMarshallLists(self): test_date = DateTime() list_ = [1, test_date, 'str', u'unic\xF3de'] result = complex_marshal([('list', list_), ]) - if PY2: - arg4_type = ':utf8:ustring:list' - else: - arg4_type = ':list' + arg4_type = ':list' self.assertEqual(result, [('list', ':int:list', 1), ('list', ':date:list', test_date), @@ -57,10 +50,7 @@ def testMarshallRecords(self): 'arg3': 'str', 'arg4': u'unic\xF3de', } result = complex_marshal([('record', record), ]) - if PY2: - arg4_type = ':utf8:ustring:record' - else: - arg4_type = ':record' + arg4_type = ':record' self.assertEqual( set(result), set([('record.arg1', ':int:record', 1), @@ -73,10 +63,7 @@ def testMarshallListsInRecords(self): test_date = DateTime() record = {'arg1': [1, test_date, 'str', u'unic\xF3de'], 'arg2': 1} result = complex_marshal([('record', record), ]) - if PY2: - arg1_type = ':utf8:ustring:list:record' - else: - arg1_type = ':list:record' + arg1_type = ':list:record' self.assertEqual( set(result), set([('record.arg1', ':int:list:record', 1), @@ -116,10 +103,7 @@ def testMakeQueryUnicode(self): https://github.com/zopefoundation/Zope/issues/15 ''' query = make_query(search_text=u'unic\xF3de') - if PY2: - arg_type = 'search_text:utf8:ustring=' - else: - arg_type = 'search_text=' + arg_type = 'search_text=' self.assertEqual(arg_type + 'unic%C3%B3de', query) def testMakeHiddenInput(self): diff --git a/src/Zope2/App/tests/test_safe_formatter.py b/src/Zope2/App/tests/test_safe_formatter.py index 8633b2db98..4051e2864d 100644 --- a/src/Zope2/App/tests/test_safe_formatter.py +++ b/src/Zope2/App/tests/test_safe_formatter.py @@ -4,15 +4,6 @@ from zExceptions import Unauthorized -try: - from html import escape - import functools - # We do not want escaped " and ', as PageTemplate neither does it: - escape = functools.partial(escape, quote=False) -except ImportError: # PY2 - from cgi import escape - - BAD_ATTR_STR = """

""" diff --git a/src/Zope2/Startup/datatypes.py b/src/Zope2/Startup/datatypes.py index 9a23f8ab4c..36c17e925e 100644 --- a/src/Zope2/Startup/datatypes.py +++ b/src/Zope2/Startup/datatypes.py @@ -17,8 +17,6 @@ import os import traceback -from six import PY2 -from six import text_type from six.moves import UserDict from ZODB.config import ZODBDatabase @@ -155,8 +153,6 @@ def getName(self): def computeMountPaths(self): mps = [] for part in self.config.mount_points: - if PY2 and isinstance(part, text_type): - part = part.encode() real_root = None if ':' in part: # 'virtual_path:real_path' @@ -195,9 +191,6 @@ def default_zpublisher_encoding(value): # so a module-level call to getConfiguration in any of them # results in getting config data structure without the necessary # value in it. - if PY2: - # unicode is not acceptable as encoding in HTTP headers: - value = str(value) from ZPublisher import Converters, HTTPRequest, HTTPResponse Converters.default_encoding = value HTTPRequest.default_encoding = value diff --git a/src/Zope2/Startup/starter.py b/src/Zope2/Startup/starter.py index c0443c2749..75b8b68455 100644 --- a/src/Zope2/Startup/starter.py +++ b/src/Zope2/Startup/starter.py @@ -15,9 +15,6 @@ import codecs import locale import logging -import sys - -from six import PY2 from ZConfig import ConfigurationError from Zope2.Startup.handlers import _name_to_ips @@ -49,9 +46,7 @@ def setConfiguration(self, cfg): def setupInterpreter(self): # make changes to the python interpreter environment - if PY2: - # Check interval is gone in supported Python 3 versions. - sys.setcheckinterval(self.cfg.python_check_interval) + pass def setupLocale(self): # set a locale if one has been specified in the config, else read from diff --git a/src/Zope2/Startup/tests/test_serve.py b/src/Zope2/Startup/tests/test_serve.py index 34fb86ba7c..edd52fd013 100644 --- a/src/Zope2/Startup/tests/test_serve.py +++ b/src/Zope2/Startup/tests/test_serve.py @@ -16,8 +16,6 @@ import sys import unittest -import six - class TestFunctions(unittest.TestCase): @@ -51,10 +49,7 @@ def _makeOne(self, argv=[], quiet=False): return ServeCommand(argv, quiet=quiet) def _getFileLike(self): - if six.PY2: - return io.BytesIO() - else: - return io.StringIO() + return io.StringIO() def test_defaults(self): srv = self._makeOne() diff --git a/src/Zope2/Startup/tests/test_starter.py b/src/Zope2/Startup/tests/test_starter.py index c2fa23a928..b9e41df87a 100644 --- a/src/Zope2/Startup/tests/test_starter.py +++ b/src/Zope2/Startup/tests/test_starter.py @@ -15,12 +15,9 @@ import io import os import shutil -import sys import tempfile import unittest -import six - import ZConfig from Zope2.Startup import get_wsgi_starter from Zope2.Startup.options import ZopeWSGIOptions @@ -56,10 +53,7 @@ def load_config_text(self, text): # of the directory is checked. This handles this in a # platform-independent way. text = text.replace("<>", self.TEMPNAME) - if six.PY2: - sio = io.BytesIO(text) - else: - sio = io.StringIO(text) + sio = io.StringIO(text) try: os.mkdir(self.TEMPNAME) @@ -107,18 +101,3 @@ def testSetupConflictRetries(self): max-conflict-retries 25""") root_wsgi_handler(conf) self.assertEqual(HTTPRequest.retry_max_count, 25) - - @unittest.skipUnless(six.PY2, 'Python 2 specific checkinterval test.') - def testConfigureInterpreter(self): - oldcheckinterval = sys.getcheckinterval() - newcheckinterval = oldcheckinterval + 1 - conf = self.load_config_text(""" - instancehome <> - python-check-interval %d - """ % newcheckinterval) - try: - starter = self.get_starter(conf) - starter.setupInterpreter() - self.assertEqual(sys.getcheckinterval(), newcheckinterval) - finally: - sys.setcheckinterval(oldcheckinterval)