summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-11-11 13:38:32 -0500
committerChris McDonough <chrism@plope.com>2011-11-11 13:38:32 -0500
commit5cf9fc8ab86e6ec6b76dd9d80cd8dcab42384cc6 (patch)
treef25731f39a41c5f74bfa9c0126e680bffadb7303
parentc8e2f8e35c99b4f35d53ed0bb73e737e97ef345c (diff)
downloadpyramid-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.txt3
-rw-r--r--docs/api.rst1
-rw-r--r--docs/api/compat.rst155
-rw-r--r--pyramid/compat.py79
-rw-r--r--pyramid/renderers.py2
-rw-r--r--pyramid/request.py4
-rw-r--r--pyramid/scripts/proutes.py3
-rw-r--r--pyramid/scripts/ptweens.py4
-rw-r--r--pyramid/scripts/pviews.py3
-rw-r--r--pyramid/tests/test_docs.py3
-rw-r--r--pyramid/tests/test_request.py2
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',