From 6b0e4625da2c53a1e3fdb4857fc7c6ba6ce562cf Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 31 Oct 2018 01:36:26 -0500 Subject: initial work to remove py2 from the codebase --- src/pyramid/compat.py | 302 ++++++++++-------------------------------- src/pyramid/i18n.py | 15 +-- src/pyramid/interfaces.py | 15 --- src/pyramid/request.py | 4 +- src/pyramid/scripts/pserve.py | 23 ++-- src/pyramid/session.py | 8 +- src/pyramid/testing.py | 4 +- src/pyramid/traversal.py | 61 +++------ src/pyramid/urldispatch.py | 12 +- src/pyramid/util.py | 13 +- 10 files changed, 109 insertions(+), 348 deletions(-) (limited to 'src') diff --git a/src/pyramid/compat.py b/src/pyramid/compat.py index 31832c874..77e9bea98 100644 --- a/src/pyramid/compat.py +++ b/src/pyramid/compat.py @@ -13,34 +13,15 @@ except BaseException: # pragma: no cover __pypy__ = None PYPY = False -try: - import cPickle as pickle -except ImportError: # pragma: no cover - import pickle - -try: - from functools import lru_cache -except ImportError: - from repoze.lru import lru_cache - -# PY3 is left as bw-compat but PY2 should be used for most checks. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -if PY2: - string_types = (basestring,) - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - long = long -else: - string_types = (str,) - integer_types = (int,) - class_types = (type,) - text_type = str - binary_type = bytes - long = int +from functools import lru_cache +import pickle + +string_types = (str,) +integer_types = (int,) +class_types = (type,) +text_type = str +binary_type = bytes +long = int def text_(s, encoding='latin-1', errors='strict'): @@ -59,236 +40,105 @@ def bytes_(s, encoding='latin-1', errors='strict'): return s -if PY2: - - def ascii_native_(s): - if isinstance(s, text_type): - s = s.encode('ascii') - return str(s) - - -else: - - def ascii_native_(s): - if isinstance(s, text_type): - s = s.encode('ascii') - return str(s, 'ascii', 'strict') - - -ascii_native_.__doc__ = """ -Python 3: If ``s`` is an instance of ``text_type``, return -``s.encode('ascii')``, otherwise return ``str(s, 'ascii', 'strict')`` - -Python 2: If ``s`` is an instance of ``text_type``, return -``s.encode('ascii')``, otherwise return ``str(s)`` -""" - - -if PY2: - - def native_(s, encoding='latin-1', errors='strict'): - """ If ``s`` is an instance of ``text_type``, return - ``s.encode(encoding, errors)``, otherwise return ``str(s)``""" - if isinstance(s, text_type): - return s.encode(encoding, errors) - return str(s) - - -else: - - def native_(s, encoding='latin-1', errors='strict'): - """ If ``s`` is an instance of ``text_type``, return - ``s``, otherwise return ``str(s, encoding, errors)``""" - if isinstance(s, text_type): - return s - return str(s, encoding, errors) - - -native_.__doc__ = """ -Python 3: If ``s`` is an instance of ``text_type``, return ``s``, otherwise -return ``str(s, encoding, errors)`` - -Python 2: If ``s`` is an instance of ``text_type``, return -``s.encode(encoding, errors)``, otherwise return ``str(s)`` -""" - -if PY2: - import urlparse - from urllib import quote as url_quote - from urllib import quote_plus as url_quote_plus - from urllib import unquote as url_unquote - from urllib import urlencode as url_encode - from urllib2 import urlopen as url_open - - def url_unquote_text( - v, encoding='utf-8', errors='replace' - ): # pragma: no cover - v = url_unquote(v) - return v.decode(encoding, errors) - - def url_unquote_native( - v, encoding='utf-8', errors='replace' - ): # pragma: no cover - return native_(url_unquote_text(v, encoding, errors)) - - -else: - from urllib import parse - - urlparse = parse - from urllib.parse import quote as url_quote - from urllib.parse import quote_plus as url_quote_plus - from urllib.parse import unquote as url_unquote - from urllib.parse import urlencode as url_encode - from urllib.request import urlopen as url_open - - url_unquote_text = url_unquote - url_unquote_native = url_unquote - - -if PY2: # pragma: no cover - - def exec_(code, globs=None, locs=None): - """Execute code in a namespace.""" - if globs is None: - frame = sys._getframe(1) - globs = frame.f_globals - if locs is None: - locs = frame.f_locals - del frame - elif locs is None: - locs = globs - exec("""exec code in globs, locs""") - - exec_( - """def reraise(tp, value, tb=None): - raise tp, value, tb -""" - ) +def ascii_native_(s): + """ + If ``s`` is an instance of ``text_type``, return + ``s.encode('ascii')``, otherwise return ``str(s, 'ascii', 'strict')`` + """ + if isinstance(s, text_type): + s = s.encode('ascii') + return str(s, 'ascii', 'strict') -else: # pragma: no cover - import builtins - exec_ = getattr(builtins, "exec") +def native_(s, encoding='latin-1', errors='strict'): + """ If ``s`` is an instance of ``text_type``, return + ``s``, otherwise return ``str(s, encoding, errors)`` + """ + if isinstance(s, text_type): + return s + return str(s, encoding, errors) - def reraise(tp, value, tb=None): - if value is None: - value = tp - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - del builtins +from urllib import parse +urlparse = parse +from urllib.parse import quote as url_quote +from urllib.parse import quote_plus as url_quote_plus +from urllib.parse import unquote as url_unquote +from urllib.parse import urlencode as url_encode +from urllib.request import urlopen as url_open -if PY2: # pragma: no cover +url_unquote_text = url_unquote +url_unquote_native = url_unquote - def iteritems_(d): - return d.iteritems() - def itervalues_(d): - return d.itervalues() +import builtins - def iterkeys_(d): - return d.iterkeys() +exec_ = getattr(builtins, "exec") -else: # pragma: no cover +def reraise(tp, value, tb=None): + if value is None: + value = tp + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value - def iteritems_(d): - return d.items() - def itervalues_(d): - return d.values() +del builtins - def iterkeys_(d): - return d.keys() +def iteritems_(d): + return d.items() -if PY2: - map_ = map -else: - def map_(*arg): - return list(map(*arg)) +def itervalues_(d): + return d.values() -if PY2: +def iterkeys_(d): + return d.keys() - def is_nonstr_iter(v): - return hasattr(v, '__iter__') +def map_(*arg): + return list(map(*arg)) -else: - def is_nonstr_iter(v): - if isinstance(v, str): - return False - return hasattr(v, '__iter__') +def is_nonstr_iter(v): + if isinstance(v, str): + return False + return hasattr(v, '__iter__') -if PY2: - im_func = 'im_func' - im_self = 'im_self' -else: - im_func = '__func__' - im_self = '__self__' +im_func = '__func__' +im_self = '__self__' -try: - import configparser -except ImportError: - import ConfigParser as configparser +import configparser -try: - from http.cookies import SimpleCookie -except ImportError: - from Cookie import SimpleCookie +from http.cookies import SimpleCookie -if PY2: - from cgi import escape -else: - from html import escape +from html import escape -if PY2: - input_ = raw_input -else: - input_ = input +input_ = input -if PY2: - from io import BytesIO as NativeIO -else: - from io import StringIO as NativeIO +from io import StringIO as NativeIO # "json" is not an API; it's here to support older pyramid_debugtoolbar # versions which attempt to import it import json -if PY2: - - def decode_path_info(path): - return path.decode('utf-8') +# see PEP 3333 for why we encode WSGI PATH_INFO to latin-1 before +# decoding it to utf-8 +def decode_path_info(path): + return path.encode('latin-1').decode('utf-8') -else: - # see PEP 3333 for why we encode WSGI PATH_INFO to latin-1 before - # decoding it to utf-8 - def decode_path_info(path): - return path.encode('latin-1').decode('utf-8') +# see PEP 3333 for why we decode the path to latin-1 +from urllib.parse import unquote_to_bytes -if PY2: - from urlparse import unquote as unquote_to_bytes - - def unquote_bytes_to_wsgi(bytestring): - return unquote_to_bytes(bytestring) - - -else: - # see PEP 3333 for why we decode the path to latin-1 - from urllib.parse import unquote_to_bytes - - def unquote_bytes_to_wsgi(bytestring): - return unquote_to_bytes(bytestring).decode('latin-1') +def unquote_bytes_to_wsgi(bytestring): + return unquote_to_bytes(bytestring).decode('latin-1') def is_bound_method(ob): @@ -296,15 +146,9 @@ def is_bound_method(ob): # support annotations and keyword-only arguments in PY3 -if PY2: - from inspect import getargspec -else: - from inspect import getfullargspec as getargspec +from inspect import getfullargspec as getargspec -if PY2: - from itertools import izip_longest as zip_longest -else: - from itertools import zip_longest +from itertools import zip_longest def is_unbound_method(fn): @@ -318,9 +162,7 @@ def is_unbound_method(fn): spec = getargspec(fn) has_self = len(spec.args) > 0 and spec.args[0] == 'self' - if PY2 and inspect.ismethod(fn): - return True - elif inspect.isfunction(fn) and has_self: + if inspect.isfunction(fn) and has_self: return True return False diff --git a/src/pyramid/i18n.py b/src/pyramid/i18n.py index e99a29aab..45f528852 100644 --- a/src/pyramid/i18n.py +++ b/src/pyramid/i18n.py @@ -8,7 +8,6 @@ from translationstring import ( TranslationStringFactory, # API ) -from pyramid.compat import PY2 from pyramid.decorator import reify from pyramid.interfaces import ( @@ -353,10 +352,7 @@ class Translations(gettext.GNUTranslations, object): """Like ``ugettext()``, but look the message up in the specified domain. """ - if PY2: - return self._domains.get(domain, self).ugettext(message) - else: - return self._domains.get(domain, self).gettext(message) + return self._domains.get(domain, self).gettext(message) def dngettext(self, domain, singular, plural, num): """Like ``ngettext()``, but look the message up in the specified @@ -374,14 +370,7 @@ class Translations(gettext.GNUTranslations, object): """Like ``ungettext()`` but look the message up in the specified domain. """ - if PY2: - return self._domains.get(domain, self).ungettext( - singular, plural, num - ) - else: - return self._domains.get(domain, self).ngettext( - singular, plural, num - ) + return self._domains.get(domain, self).ngettext(singular, plural, num) class LocalizerRequestMixin(object): diff --git a/src/pyramid/interfaces.py b/src/pyramid/interfaces.py index 31bcd7e88..f1e238c6b 100644 --- a/src/pyramid/interfaces.py +++ b/src/pyramid/interfaces.py @@ -1,7 +1,5 @@ from zope.interface import Attribute, Interface -from pyramid.compat import PY2 - # public API interfaces @@ -366,19 +364,6 @@ class IDict(Interface): def values(): """ Return a list of values from the dictionary """ - if PY2: - - def iterkeys(): - """ Return an iterator of keys from the dictionary """ - - def iteritems(): - """ Return an iterator of (k,v) pairs from the dictionary """ - - def itervalues(): - """ Return an iterator of values from the dictionary """ - - has_key = __contains__ - def pop(k, default=None): """ Pop the key k from the dictionary and return its value. If k doesn't exist, and default is provided, return the default. If k diff --git a/src/pyramid/request.py b/src/pyramid/request.py index 907b4477f..5ee87ff58 100644 --- a/src/pyramid/request.py +++ b/src/pyramid/request.py @@ -13,7 +13,7 @@ from pyramid.interfaces import ( ISessionFactory, ) -from pyramid.compat import text_, bytes_, native_, iteritems_ +from pyramid.compat import text_, bytes_, native_ from pyramid.decorator import reify from pyramid.i18n import LocalizerRequestMixin @@ -328,7 +328,7 @@ def apply_request_extensions(request, extensions=None): if extensions is None: extensions = request.registry.queryUtility(IRequestExtensions) if extensions is not None: - for name, fn in iteritems_(extensions.methods): + for name, fn in extensions.methods.items(): method = fn.__get__(request, request.__class__) setattr(request, name, method) diff --git a/src/pyramid/scripts/pserve.py b/src/pyramid/scripts/pserve.py index 581479d65..7d68521a4 100644 --- a/src/pyramid/scripts/pserve.py +++ b/src/pyramid/scripts/pserve.py @@ -19,8 +19,6 @@ import webbrowser import hupper -from pyramid.compat import PY2 - from pyramid.scripts.common import get_config_loader from pyramid.scripts.common import parse_vars from pyramid.path import AssetResolver @@ -380,18 +378,15 @@ def cherrypy_server_runner( server = WSGIServer(bind_addr, app, server_name=server_name, **kwargs) if ssl_pem is not None: - if PY2: - server.ssl_certificate = server.ssl_private_key = ssl_pem - else: - # creates wsgiserver.ssl_builtin as side-effect - try: - from cheroot.server import get_ssl_adapter_class - from cheroot.ssl.builtin import BuiltinSSLAdapter - except ImportError: - from cherrypy.wsgiserver import get_ssl_adapter_class - from cherrypy.wsgiserver.ssl_builtin import BuiltinSSLAdapter - get_ssl_adapter_class() - server.ssl_adapter = BuiltinSSLAdapter(ssl_pem, ssl_pem) + # creates wsgiserver.ssl_builtin as side-effect + try: + from cheroot.server import get_ssl_adapter_class + from cheroot.ssl.builtin import BuiltinSSLAdapter + except ImportError: + from cherrypy.wsgiserver import get_ssl_adapter_class + from cherrypy.wsgiserver.ssl_builtin import BuiltinSSLAdapter + get_ssl_adapter_class() + server.ssl_adapter = BuiltinSSLAdapter(ssl_pem, ssl_pem) if protocol_version: server.protocol = protocol_version diff --git a/src/pyramid/session.py b/src/pyramid/session.py index 68e0c506c..e9486ec6d 100644 --- a/src/pyramid/session.py +++ b/src/pyramid/session.py @@ -7,7 +7,7 @@ from zope.interface import implementer from webob.cookies import JSONSerializer, SignedSerializer -from pyramid.compat import pickle, PY2, text_, bytes_, native_ +from pyramid.compat import pickle, text_, bytes_, native_ from pyramid.csrf import check_csrf_origin, check_csrf_token from pyramid.interfaces import ISession @@ -255,12 +255,6 @@ def BaseCookieSessionFactory( __len__ = manage_accessed(dict.__len__) __iter__ = manage_accessed(dict.__iter__) - if PY2: - iteritems = manage_accessed(dict.iteritems) - itervalues = manage_accessed(dict.itervalues) - iterkeys = manage_accessed(dict.iterkeys) - has_key = manage_accessed(dict.has_key) - # modifying dictionary methods clear = manage_changed(dict.clear) update = manage_changed(dict.update) diff --git a/src/pyramid/testing.py b/src/pyramid/testing.py index f700b5a4e..5fe8f8a62 100644 --- a/src/pyramid/testing.py +++ b/src/pyramid/testing.py @@ -8,7 +8,7 @@ from zope.interface import implementer, alsoProvides from pyramid.interfaces import IRequest, ISession -from pyramid.compat import PY3, PYPY, class_types, text_ +from pyramid.compat import PYPY, class_types, text_ from pyramid.config import Configurator from pyramid.decorator import reify @@ -640,8 +640,6 @@ def skip_on(*platforms): # pragma: no cover skip = True if platform == 'pypy' and PYPY: skip = True - if platform == 'py3' and PY3: - skip = True def decorator(func): if isinstance(func, class_types): diff --git a/src/pyramid/traversal.py b/src/pyramid/traversal.py index 338b49083..f46937d73 100644 --- a/src/pyramid/traversal.py +++ b/src/pyramid/traversal.py @@ -9,7 +9,6 @@ from pyramid.interfaces import ( ) from pyramid.compat import ( - PY2, native_, text_, ascii_native_, @@ -580,49 +579,23 @@ the ``safe`` argument to this function. This corresponds to the """ -if PY2: - # special-case on Python 2 for speed? unchecked - def quote_path_segment(segment, safe=PATH_SEGMENT_SAFE): - """ %s """ % quote_path_segment_doc - # The bit of this code that deals with ``_segment_cache`` is an - # optimization: we cache all the computation of URL path segments - # in this module-scope dictionary with the original string (or - # unicode value) as the key, so we can look it up later without - # needing to reencode or re-url-quote it - try: - return _segment_cache[(segment, safe)] - except KeyError: - if ( - segment.__class__ is text_type - ): # isinstance slighly slower (~15%) - result = url_quote(segment.encode('utf-8'), safe) - else: - result = url_quote(str(segment), safe) - # we don't need a lock to mutate _segment_cache, as the below - # will generate exactly one Python bytecode (STORE_SUBSCR) - _segment_cache[(segment, safe)] = result - return result - - -else: - - def quote_path_segment(segment, safe=PATH_SEGMENT_SAFE): - """ %s """ % quote_path_segment_doc - # The bit of this code that deals with ``_segment_cache`` is an - # optimization: we cache all the computation of URL path segments - # in this module-scope dictionary with the original string (or - # unicode value) as the key, so we can look it up later without - # needing to reencode or re-url-quote it - try: - return _segment_cache[(segment, safe)] - except KeyError: - if segment.__class__ not in (text_type, binary_type): - segment = str(segment) - result = url_quote(native_(segment, 'utf-8'), safe) - # we don't need a lock to mutate _segment_cache, as the below - # will generate exactly one Python bytecode (STORE_SUBSCR) - _segment_cache[(segment, safe)] = result - return result +def quote_path_segment(segment, safe=PATH_SEGMENT_SAFE): + """ %s """ % quote_path_segment_doc + # The bit of this code that deals with ``_segment_cache`` is an + # optimization: we cache all the computation of URL path segments + # in this module-scope dictionary with the original string (or + # unicode value) as the key, so we can look it up later without + # needing to reencode or re-url-quote it + try: + return _segment_cache[(segment, safe)] + except KeyError: + if segment.__class__ not in (text_type, binary_type): + segment = str(segment) + result = url_quote(native_(segment, 'utf-8'), safe) + # we don't need a lock to mutate _segment_cache, as the below + # will generate exactly one Python bytecode (STORE_SUBSCR) + _segment_cache[(segment, safe)] = result + return result slash = text_('/') diff --git a/src/pyramid/urldispatch.py b/src/pyramid/urldispatch.py index de8a69d2a..1d3f8d91b 100644 --- a/src/pyramid/urldispatch.py +++ b/src/pyramid/urldispatch.py @@ -4,7 +4,6 @@ from zope.interface import implementer from pyramid.interfaces import IRoutesMapper, IRoute from pyramid.compat import ( - PY2, native_, text_, text_type, @@ -227,14 +226,9 @@ def _compile_route(route): def generator(dict): newdict = {} for k, v in dict.items(): - if PY2: - if v.__class__ is text_type: - # url_quote below needs bytes, not unicode on Py2 - v = v.encode('utf-8') - else: - if v.__class__ is binary_type: - # url_quote below needs a native string, not bytes on Py3 - v = v.decode('utf-8') + if v.__class__ is binary_type: + # url_quote below needs a native string, not bytes on Py3 + v = v.decode('utf-8') if k == remainder: # a stararg argument diff --git a/src/pyramid/util.py b/src/pyramid/util.py index bebf9e7d3..39b67471e 100644 --- a/src/pyramid/util.py +++ b/src/pyramid/util.py @@ -1,11 +1,6 @@ from contextlib import contextmanager import functools - -try: - # py2.7.7+ and py3.3+ have native comparison support - from hmac import compare_digest -except ImportError: # pragma: no cover - compare_digest = None +from hmac import compare_digest import inspect import weakref @@ -19,7 +14,6 @@ from pyramid.compat import ( string_types, bytes_, text_, - PY2, native_, ) @@ -337,10 +331,7 @@ def object_description(object): if isinstance(object, (bool, float, type(None))): return text_(str(object)) if isinstance(object, set): - if PY2: - return shortrepr(object, ')') - else: - return shortrepr(object, '}') + return shortrepr(object, '}') if isinstance(object, tuple): return shortrepr(object, ')') if isinstance(object, list): -- cgit v1.2.3