-
Notifications
You must be signed in to change notification settings - Fork 886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restore compat.py in master/2.X #3443
Closed
Closed
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
201c187
Merge branch 'master' of github.com:Pylons/pyramid
mcdonc 37ffb01
Merge branch 'master' of github.com:Pylons/pyramid
mcdonc 051d121
Merge branch 'master' of github.com:Pylons/pyramid
mcdonc 56fcfb9
Merge branch 'master' of github.com:Pylons/pyramid
mcdonc d067256
restore pyramid.compat as a shim such that add-ons and apps that use …
mcdonc 1d2d2b5
Merge branch 'master' of github.com:Pylons/pyramid
mcdonc 087b291
add compat.rst back
mcdonc b70ecd9
Merge branch 'master' into feature.restore-compat-in-2x
mcdonc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
.. _compat_module: | ||
|
||
:mod:`pyramid.compat` | ||
---------------------- | ||
|
||
The ``pyramid.compat`` module provides platform and version compatibility for | ||
Pyramid and its add-ons across Python platform and version differences. The | ||
origininal intent for this module was that its APIs would be removed from this | ||
module over time as Pyramid ceased to support systems which require | ||
compatibility imports (e.g. Pyramid no longer supports Python 2 past Pyramid | ||
2.X). However, the reality is that it requires almost no effort to continue to | ||
support all the APIs that this module has acccreted over time, and removing any | ||
would require software that depends on them to make "recreational" releases | ||
that serve no real purpose. Therefore, we have decided to keep this module | ||
even though its presence might be considered anachronistic. | ||
|
||
.. automodule:: pyramid.compat | ||
|
||
.. autofunction:: ascii_native_ | ||
|
||
.. attribute:: binary_type | ||
|
||
Binary type for this platform. For Python 3, it's ``bytes``. For | ||
Python 2, it's ``str``. | ||
|
||
.. autofunction:: bytes_ | ||
|
||
.. attribute:: class_types | ||
|
||
Sequence of class types for this platform. For Python 3, it's | ||
``(type,)``. For Python 2, it's ``(type, types.ClassType)``. | ||
|
||
.. attribute:: configparser | ||
|
||
On Python 2, the ``ConfigParser`` module, on Python 3, the | ||
``configparser`` module. | ||
|
||
.. function:: escape(v) | ||
|
||
On Python 2, the ``cgi.escape`` function, on Python 3, the | ||
``html.escape`` function. | ||
|
||
.. function:: exec_(code, globs=None, locs=None) | ||
|
||
Exec code in a compatible way on both Python 2 and 3. | ||
|
||
.. attribute:: im_func | ||
|
||
On Python 2, the string value ``im_func``, on Python 3, the string | ||
value ``__func__``. | ||
|
||
.. function:: input_(v) | ||
|
||
On Python 2, the ``raw_input`` function, on Python 3, the | ||
``input`` function. | ||
|
||
.. attribute:: integer_types | ||
|
||
Sequence of integer types for this platform. For Python 3, it's | ||
``(int,)``. For Python 2, it's ``(int, long)``. | ||
|
||
.. function:: is_nonstr_iter(v) | ||
|
||
Return ``True`` if ``v`` is a non-``str`` iterable on both Python 2 and | ||
Python 3. | ||
|
||
.. function:: iteritems_(d) | ||
|
||
Return ``d.items()`` on Python 3, ``d.iteritems()`` on Python 2. | ||
|
||
.. function:: itervalues_(d) | ||
|
||
Return ``d.values()`` on Python 3, ``d.itervalues()`` on Python 2. | ||
|
||
.. function:: iterkeys_(d) | ||
|
||
Return ``d.keys()`` on Python 3, ``d.iterkeys()`` on Python 2. | ||
|
||
.. attribute:: long | ||
|
||
Long type for this platform. For Python 3, it's ``int``. For | ||
Python 2, it's ``long``. | ||
|
||
.. function:: map_(v) | ||
|
||
Return ``list(map(v))`` on Python 3, ``map(v)`` on Python 2. | ||
|
||
.. attribute:: pickle | ||
|
||
``cPickle`` module if it exists, ``pickle`` module otherwise. | ||
|
||
.. attribute:: PY3 | ||
|
||
``True`` if running on Python 3, ``False`` otherwise. | ||
|
||
.. attribute:: PYPY | ||
|
||
``True`` if running on PyPy, ``False`` otherwise. | ||
|
||
.. function:: reraise(tp, value, tb=None) | ||
|
||
Reraise an exception in a compatible way on both Python 2 and Python 3, | ||
e.g. ``reraise(*sys.exc_info())``. | ||
|
||
.. attribute:: string_types | ||
|
||
Sequence of string types for this platform. For Python 3, it's | ||
``(str,)``. For Python 2, it's ``(basestring,)``. | ||
|
||
.. attribute:: SimpleCookie | ||
|
||
On Python 2, the ``Cookie.SimpleCookie`` class, on Python 3, the | ||
``http.cookies.SimpleCookie`` module. | ||
|
||
.. autofunction:: text_ | ||
|
||
.. attribute:: text_type | ||
|
||
Text type for this platform. For Python 3, it's ``str``. For Python | ||
2, it's ``unicode``. | ||
|
||
.. autofunction:: native_ | ||
|
||
.. attribute:: urlparse | ||
|
||
``urlparse`` module on Python 2, ``urllib.parse`` module on Python 3. | ||
|
||
.. attribute:: url_quote | ||
|
||
``urllib.quote`` function on Python 2, ``urllib.parse.quote`` function | ||
on Python 3. | ||
|
||
.. attribute:: url_quote_plus | ||
|
||
``urllib.quote_plus`` function on Python 2, ``urllib.parse.quote_plus`` | ||
function on Python 3. | ||
|
||
.. attribute:: url_unquote | ||
|
||
``urllib.unquote`` function on Python 2, ``urllib.parse.unquote`` | ||
function on Python 3. | ||
|
||
.. attribute:: url_encode | ||
|
||
``urllib.urlencode`` function on Python 2, ``urllib.parse.urlencode`` | ||
function on Python 3. | ||
|
||
.. attribute:: url_open | ||
|
||
``urllib2.urlopen`` function on Python 2, ``urllib.request.urlopen`` | ||
function on Python 3. | ||
|
||
.. function:: url_unquote_text(v, encoding='utf-8', errors='replace') | ||
|
||
On Python 2, return ``url_unquote(v).decode(encoding(encoding, errors))``; | ||
on Python 3, return the result of ``urllib.parse.unquote``. | ||
|
||
.. function:: url_unquote_native(v, encoding='utf-8', errors='replace') | ||
|
||
On Python 2, return ``native_(url_unquote_text_v, encoding, errors))``; | ||
on Python 3, return the result of ``urllib.parse.unquote``. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
# This is not actually an API and *should not* be used by Pyramid 2.X apps or | ||
# Pyramid 2.X itself. But many apps in the wild depend on this stuff, and it's | ||
# just more pragmatic to just leave it here, even though we no longer support | ||
# Python 2. | ||
|
||
import inspect | ||
import platform | ||
import sys | ||
import types | ||
|
||
WIN = platform.system() == 'Windows' | ||
|
||
try: # pragma: no cover | ||
import __pypy__ | ||
|
||
PYPY = True | ||
except BaseException: # pragma: no cover | ||
__pypy__ = None | ||
PYPY = False | ||
|
||
import pickle | ||
|
||
from functools import lru_cache | ||
|
||
PY3 = sys.version_info[0] == 3 | ||
|
||
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'): # pragma: no cover | ||
""" If ``s`` is an instance of ``binary_type``, return | ||
``s.decode(encoding, errors)``, otherwise return ``s``""" | ||
if isinstance(s, binary_type): | ||
return s.decode(encoding, errors) | ||
return s | ||
|
||
|
||
def bytes_(s, encoding='latin-1', errors='strict'): # pragma: no cover | ||
""" If ``s`` is an instance of ``text_type``, return | ||
``s.encode(encoding, errors)``, otherwise return ``s``""" | ||
if isinstance(s, text_type): | ||
return s.encode(encoding, errors) | ||
return s | ||
|
||
|
||
def ascii_native_(s): # pragma: no cover | ||
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)`` | ||
""" | ||
|
||
|
||
def native_(s, encoding='latin-1', errors='strict'): # pragma: no cover | ||
""" 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)`` | ||
""" | ||
|
||
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 | ||
|
||
|
||
import builtins | ||
|
||
exec_ = getattr(builtins, "exec") | ||
|
||
|
||
def reraise(tp, value, tb=None): # pragma: no cover | ||
if value is None: | ||
value = tp | ||
if value.__traceback__ is not tb: | ||
raise value.with_traceback(tb) | ||
raise value | ||
|
||
|
||
del builtins | ||
|
||
|
||
def iteritems_(d): # pragma: no cover | ||
return d.items() | ||
|
||
|
||
def itervalues_(d): # pragma: no cover | ||
return d.values() | ||
|
||
|
||
def iterkeys_(d): # pragma: no cover | ||
return d.keys() | ||
|
||
|
||
def map_(*arg): # pragma: no cover | ||
return list(map(*arg)) | ||
|
||
|
||
def is_nonstr_iter(v): # pragma: no cover | ||
if isinstance(v, str): | ||
return False | ||
return hasattr(v, '__iter__') | ||
|
||
|
||
im_func = '__func__' | ||
im_self = '__self__' | ||
|
||
import configparser | ||
|
||
from http.cookies import SimpleCookie | ||
|
||
from html import escape | ||
|
||
input_ = input | ||
|
||
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 | ||
|
||
# see PEP 3333 for why we encode WSGI PATH_INFO to latin-1 before | ||
# decoding it to utf-8 | ||
def decode_path_info(path): # pragma: no cover | ||
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 | ||
|
||
|
||
def unquote_bytes_to_wsgi(bytestring): # pragma: no cover | ||
return unquote_to_bytes(bytestring).decode('latin-1') | ||
|
||
|
||
def is_bound_method(ob): # pragma: no cover | ||
return inspect.ismethod(ob) and getattr(ob, im_self, None) is not None | ||
|
||
|
||
# support annotations and keyword-only arguments in PY3 | ||
from inspect import getfullargspec as getargspec | ||
|
||
from itertools import zip_longest | ||
|
||
|
||
def is_unbound_method(fn): | ||
""" | ||
This consistently verifies that the callable is bound to a | ||
class. | ||
""" | ||
is_bound = is_bound_method(fn) | ||
|
||
if not is_bound and inspect.isroutine(fn): | ||
spec = getargspec(fn) | ||
has_self = len(spec.args) > 0 and spec.args[0] == 'self' | ||
|
||
if inspect.isfunction(fn) and has_self: | ||
return True | ||
|
||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import unittest | ||
from pyramid.compat import is_unbound_method | ||
|
||
|
||
class TestUnboundMethods(unittest.TestCase): | ||
def test_old_style_bound(self): | ||
self.assertFalse(is_unbound_method(OldStyle().run)) | ||
|
||
def test_new_style_bound(self): | ||
self.assertFalse(is_unbound_method(NewStyle().run)) | ||
|
||
def test_old_style_unbound(self): | ||
self.assertTrue(is_unbound_method(OldStyle.run)) | ||
|
||
def test_new_style_unbound(self): | ||
self.assertTrue(is_unbound_method(NewStyle.run)) | ||
|
||
def test_normal_func_unbound(self): | ||
def func(): # pragma: no cover | ||
return 'OK' | ||
|
||
self.assertFalse(is_unbound_method(func)) | ||
|
||
|
||
class OldStyle: | ||
def run(self): # pragma: no cover | ||
return 'OK' | ||
|
||
|
||
class NewStyle(object): | ||
def run(self): # pragma: no cover | ||
return 'OK' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Python 3 only has new-style classes, some of these tests can be removed. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These functions are already defined in
pyramid.util
. Please import them from there and re-export them instead of re-defining them here.