diff options
| author | Chris McDonough <chrism@plope.com> | 2011-11-11 13:38:32 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2011-11-11 13:38:32 -0500 |
| commit | 5cf9fc8ab86e6ec6b76dd9d80cd8dcab42384cc6 (patch) | |
| tree | f25731f39a41c5f74bfa9c0126e680bffadb7303 | |
| parent | c8e2f8e35c99b4f35d53ed0bb73e737e97ef345c (diff) | |
| download | pyramid-5cf9fc8ab86e6ec6b76dd9d80cd8dcab42384cc6.tar.gz pyramid-5cf9fc8ab86e6ec6b76dd9d80cd8dcab42384cc6.tar.bz2 pyramid-5cf9fc8ab86e6ec6b76dd9d80cd8dcab42384cc6.zip | |
- New ``pyramid.compat`` module and API documentation which provides Python
2/3 straddling support for Pyramid add-ons and development environments.
| -rw-r--r-- | CHANGES.txt | 3 | ||||
| -rw-r--r-- | docs/api.rst | 1 | ||||
| -rw-r--r-- | docs/api/compat.rst | 155 | ||||
| -rw-r--r-- | pyramid/compat.py | 79 | ||||
| -rw-r--r-- | pyramid/renderers.py | 2 | ||||
| -rw-r--r-- | pyramid/request.py | 4 | ||||
| -rw-r--r-- | pyramid/scripts/proutes.py | 3 | ||||
| -rw-r--r-- | pyramid/scripts/ptweens.py | 4 | ||||
| -rw-r--r-- | pyramid/scripts/pviews.py | 3 | ||||
| -rw-r--r-- | pyramid/tests/test_docs.py | 3 | ||||
| -rw-r--r-- | pyramid/tests/test_request.py | 2 |
11 files changed, 192 insertions, 67 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 94ca8b0c1..110205055 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,9 @@ Features - Python 3.2 compatibility. +- New ``pyramid.compat`` module and API documentation which provides Python + 2/3 straddling support for Pyramid add-ons and development environments. + - A ``mako.directories`` setting is no longer required to use Mako templates Rationale: Mako template renderers can be specified using an absolute asset spec. An entire application can be written with such asset specs, diff --git a/docs/api.rst b/docs/api.rst index 6ff6e9fb1..dc75e45e0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -12,6 +12,7 @@ documentation is organized alphabetically by module name. api/authentication api/chameleon_text api/chameleon_zpt + api/compat api/config api/events api/exceptions diff --git a/docs/api/compat.rst b/docs/api/compat.rst new file mode 100644 index 000000000..cb8cf918f --- /dev/null +++ b/docs/api/compat.rst @@ -0,0 +1,155 @@ +.. _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. APIs +will be removed from this module over time as Pyramid ceases to support +systems which require compatibility imports. + +.. automodule:: pyramid.compat + + .. attribute:: PYPY + + ``True`` if running on PyPy, ``False`` otherwise. + + .. attribute:: PY3 + + ``True`` if running on Python 3, ``False`` otherwise. + + .. attribute:: pickle + + ``cPickle`` module if it exists, ``pickle`` module otherwise. + + .. attribute:: im_func + + On Python 2, the string value ``im_func``, on Python 3, the string + value ``__func__``. + + .. attribute:: configparser + + On Python 2, the ``ConfigParser`` module, on Python 3, the + ``configparser`` module. + + .. attribute:: SimpleCookie + + On Python 2, the ``Cookie.SimpleCookie`` class, on Python 3, the + ``http.cookies.SimpleCookie`` module. + + .. attribute:: string_types + + Sequence of string types for this platform. For Python 3, it's + ``(str,)``. For Python 2, it's ``(basestring,)``. + + .. attribute:: integer_types + + Sequence of integer types for this platform. For Python 3, it's + ``(int,)``. For Python 2, it's ``(int, long)``. + + .. 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:: text_type + + Text type for this platform. For Python 3, it's ``str``. For Python + 2, it's ``unicode``. + + .. attribute:: binary_type + + Binary type for this platform. For Python 3, it's ``bytes``. For + Python 2, it's ``str``. + + .. attribute:: long + + Long type for this platform. For Python 3, it's ``int``. For + Python 2, it's ``long``. + + .. autofunction:: text_ + + .. autofunction:: bytes_ + + .. autofunction:: ascii_native_ + + .. 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``. + + .. 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())``. + + .. function:: exec_(code, globs=None, locs=None) + + Exec code in a compatible way on both Python 2 and 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. + + .. function:: map_(v) + + Return ``list(map(v))`` on Python 3, ``map(v)`` on Python 2. + + .. function:: is_nonstr_iter(v) + + Return ``True`` if ``v`` is a non-``str`` iterable on both Python 2 and + Python 3. + + .. function:: escape(v) + + On Python 2, the ``cgi.escape`` function, on Python 3, the + ``html.escape`` function. + + .. function:: input_(v) + + On Python 2, the ``raw_input`` function, on Python 3, the + ``input`` function. diff --git a/pyramid/compat.py b/pyramid/compat.py index 73f52b617..80da8097e 100644 --- a/pyramid/compat.py +++ b/pyramid/compat.py @@ -13,14 +13,6 @@ try: except ImportError: # pragma: no cover import pickle -try: - import json -except ImportError: # pragma: no cover - try: - import simplejson as json - except NotImplementedError: - from django.utils import simplejson as json # GAE - # True if we are running on Python 3. PY3 = sys.version_info[0] == 3 @@ -40,11 +32,15 @@ else: long = long def text_(s, encoding='latin-1', errors='strict'): + """ If ``s`` is an instance of ``binary_type``, return + ``s.encode(encoding, errors)``, otherwise return ``s``""" if isinstance(s, binary_type): return s.decode(encoding, errors) return s # pragma: no cover def bytes_(s, encoding='latin-1', errors='strict'): + """ 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 @@ -60,17 +56,38 @@ else: s = s.encode('ascii') return str(s) +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 PY3: # pragma: no cover 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) else: 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) +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 PY3: # pragma: no cover from urllib import parse urlparse = parse @@ -108,7 +125,6 @@ if PY3: # pragma: no cover raise value - print_ = getattr(builtins, "print") del builtins else: # pragma: no cover @@ -130,51 +146,6 @@ else: # pragma: no cover """) - def print_(*args, **kwargs): - """The new-style print function.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - def write(data): - if not isinstance(data, basestring): - data = str(data) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) - if PY3: # pragma: no cover def iteritems_(d): return d.items() diff --git a/pyramid/renderers.py b/pyramid/renderers.py index 073ce444d..3197ca6b8 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -1,3 +1,4 @@ +import json import os import pkg_resources import threading @@ -14,7 +15,6 @@ from pyramid.interfaces import ITemplateRenderer from pyramid.interfaces import IRendererInfo from pyramid.asset import asset_spec_from_abspath -from pyramid.compat import json from pyramid.compat import string_types from pyramid.compat import text_type from pyramid.decorator import reify diff --git a/pyramid/request.py b/pyramid/request.py index 1f62a481d..8f5dfbbb8 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -1,3 +1,5 @@ +import json + from zope.deprecation import deprecate from zope.deprecation.deprecation import deprecated from zope.interface import implementer @@ -10,12 +12,10 @@ from pyramid.interfaces import IResponse from pyramid.interfaces import ISessionFactory from pyramid.interfaces import IResponseFactory -from pyramid.compat import json from pyramid.compat import iterkeys_, itervalues_, iteritems_ from pyramid.compat import text_ from pyramid.compat import bytes_ from pyramid.compat import native_ -from pyramid.exceptions import ConfigurationError from pyramid.decorator import reify from pyramid.response import Response from pyramid.url import URLMethodsMixin diff --git a/pyramid/scripts/proutes.py b/pyramid/scripts/proutes.py index 0e0b345a8..9b25ed169 100644 --- a/pyramid/scripts/proutes.py +++ b/pyramid/scripts/proutes.py @@ -1,7 +1,6 @@ import optparse import sys -from pyramid.compat import print_ from pyramid.paster import bootstrap def main(argv=sys.argv, quiet=False): @@ -42,7 +41,7 @@ class PRoutesCommand(object): def out(self, msg): # pragma: no cover if not self.quiet: - print_(msg) + print(msg) def run(self, quiet=False): if not self.args: diff --git a/pyramid/scripts/ptweens.py b/pyramid/scripts/ptweens.py index 81b4ae307..5bc0c7fbe 100644 --- a/pyramid/scripts/ptweens.py +++ b/pyramid/scripts/ptweens.py @@ -7,8 +7,6 @@ from pyramid.tweens import MAIN from pyramid.tweens import INGRESS from pyramid.paster import bootstrap -from pyramid.compat import print_ - def main(argv=sys.argv, quiet=False): command = PTweensCommand(argv, quiet) command.run() @@ -49,7 +47,7 @@ class PTweensCommand(object): def out(self, msg): # pragma: no cover if not self.quiet: - print_(msg) + print(msg) def show_chain(self, chain): fmt = '%-10s %-65s' diff --git a/pyramid/scripts/pviews.py b/pyramid/scripts/pviews.py index 2ff9d6ed2..38d510542 100644 --- a/pyramid/scripts/pviews.py +++ b/pyramid/scripts/pviews.py @@ -1,7 +1,6 @@ import optparse import sys -from pyramid.compat import print_ from pyramid.interfaces import IMultiView from pyramid.paster import bootstrap @@ -41,7 +40,7 @@ class PViewsCommand(object): def out(self, msg): # pragma: no cover if not self.quiet: - print_(msg) + print(msg) def _find_multi_routes(self, mapper, request): infos = [] diff --git a/pyramid/tests/test_docs.py b/pyramid/tests/test_docs.py index eba95b210..0735a494a 100644 --- a/pyramid/tests/test_docs.py +++ b/pyramid/tests/test_docs.py @@ -1,5 +1,4 @@ import unittest -from pyramid.compat import print_ if 0: # no released version of manuel actually works with :lineno: @@ -32,5 +31,5 @@ if 0: if filename.endswith('.rst'): docs.append(os.path.join(root, filename)) - print_(path) + print(path) return manuel.testing.TestSuite(m, *docs) diff --git a/pyramid/tests/test_request.py b/pyramid/tests/test_request.py index 9d498e12f..546f670c0 100644 --- a/pyramid/tests/test_request.py +++ b/pyramid/tests/test_request.py @@ -249,7 +249,7 @@ class TestRequest(unittest.TestCase): self.assertEqual(request.json_body, {'a':1}) def test_json_body_alternate_charset(self): - from pyramid.compat import json + import json request = self._makeOne({'REQUEST_METHOD':'POST'}) inp = text_( b'/\xe6\xb5\x81\xe8\xa1\x8c\xe8\xb6\x8b\xe5\x8a\xbf', |
