summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--CHANGES.txt17
-rw-r--r--RELEASING.txt10
-rw-r--r--docs/quick_tour.rst6
-rw-r--r--docs/quick_tutorial/scaffolds.rst6
-rw-r--r--pyramid/authentication.py16
-rw-r--r--pyramid/renderers.py17
-rw-r--r--pyramid/scaffolds/__init__.py7
-rw-r--r--pyramid/scripts/proutes.py2
-rw-r--r--pyramid/tests/test_authentication.py5
-rw-r--r--pyramid/tests/test_config/test_views.py4
-rw-r--r--pyramid/tests/test_renderers.py31
-rw-r--r--tox.ini4
13 files changed, 68 insertions, 61 deletions
diff --git a/.travis.yml b/.travis.yml
index fbdd88224..7528a948a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,6 +20,10 @@ matrix:
env: TOXENV=docs
- python: 3.5
env: TOXENV=pep8
+ - python: nightly
+ env: TOXENV=py36
+ allow_failures:
+ - env: TOXENV=py36
install:
- travis_retry pip install tox
diff --git a/CHANGES.txt b/CHANGES.txt
index a614a4499..b485ae59e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -14,6 +14,8 @@ Backward Incompatibilities
To run your server as a daemon you should use a process manager instead of
pserve.
+ See https://github.com/Pylons/pyramid/pull/2615
+
Features
--------
@@ -29,10 +31,17 @@ Bug Fixes
and `attr` is involved.
See: https://github.com/Pylons/pyramid/pull/2687
-- The JSON renderers now encode their result as UTF-8. The renderer helper
- will now warn the user and encode the result as UTF-8 if a renderer returns a
- text type and the response does not have a valid character set. See
- https://github.com/Pylons/pyramid/pull/2706
+- Fix a ``FutureWarning`` in Python 3.5 when using ``re.split`` on the
+ ``format`` setting to the ``proutes`` script.
+ See https://github.com/Pylons/pyramid/pull/2714
+
+- Fix a ``RuntimeWarning`` emitted by WebOb when using arbitrary objects
+ as the ``userid`` in the ``AuthTktAuthenticationPolicy``. This is now caught
+ by the policy and the object is serialized as a base64 string to avoid
+ the cryptic warning. Since the userid will be read back as a string on
+ subsequent requests a more useful warning is emitted encouraging you to
+ use a primitive type instead.
+ See https://github.com/Pylons/pyramid/pull/2715
Deprecations
------------
diff --git a/RELEASING.txt b/RELEASING.txt
index d8572fa94..326dea993 100644
--- a/RELEASING.txt
+++ b/RELEASING.txt
@@ -148,12 +148,12 @@ Here are the changes:
<<changes>>
-A "What's New In Pyramid 1.X" document exists at
-http://docs.pylonsproject.org/projects/pyramid/1.X-branch/whatsnew-1.X.html .
+What's New In Pyramid 1.X:
+http://docs.pylonsproject.org/projects/pyramid/en/1.X-branch/whatsnew-1.X.html
-You will be able to see the 1.X release documentation (across all
-alphas and betas, as well as when it eventually gets to final release)
-at http://docs.pylonsproject.org/projects/pyramid/1.X-branch/ .
+1.X release documentation (across all alphas and betas, as well as when it gets
+to final release):
+http://docs.pylonsproject.org/projects/pyramid/en/1.X-branch/
You can install it via PyPI:
diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst
index fb957be1c..88cd69400 100644
--- a/docs/quick_tour.rst
+++ b/docs/quick_tour.rst
@@ -504,10 +504,10 @@ Pyramid's ``pcreate`` command can list the available scaffolds:
$ pcreate --list
Available scaffolds:
- alchemy: Pyramid SQLAlchemy project using url dispatch
+ alchemy: Pyramid project using SQLAlchemy, SQLite, URL dispatch, and Jinja2
pyramid_jinja2_starter: Pyramid Jinja2 starter project
- starter: Pyramid starter project
- zodb: Pyramid ZODB project using traversal
+ starter: Pyramid starter project using URL dispatch and Chameleon
+ zodb: Pyramid project using ZODB, traversal, and Chameleon
The ``pyramid_jinja2`` add-on gave us a scaffold that we can use. From the
parent directory of where we want our Python package to be generated, let's use
diff --git a/docs/quick_tutorial/scaffolds.rst b/docs/quick_tutorial/scaffolds.rst
index 7845f2b71..ad002f4fd 100644
--- a/docs/quick_tutorial/scaffolds.rst
+++ b/docs/quick_tutorial/scaffolds.rst
@@ -38,9 +38,9 @@ Steps
$ $VENV/bin/pcreate --list
Available scaffolds:
- alchemy: Pyramid SQLAlchemy project using url dispatch
- starter: Pyramid starter project
- zodb: Pyramid ZODB project using traversal
+ alchemy: Pyramid project using SQLAlchemy, SQLite, URL dispatch, and Jinja2
+ starter: Pyramid starter project using URL dispatch and Chameleon
+ zodb: Pyramid project using ZODB, traversal, and Chameleon
#. Tell ``pcreate`` to use the ``starter`` scaffold to make our project:
diff --git a/pyramid/authentication.py b/pyramid/authentication.py
index 034da9e46..7d766fd06 100644
--- a/pyramid/authentication.py
+++ b/pyramid/authentication.py
@@ -6,6 +6,7 @@ import hashlib
import base64
import re
import time as time_mod
+import warnings
from zope.interface import implementer
@@ -948,8 +949,19 @@ class AuthTktCookieHelper(object):
if encoding_data:
encoding, encoder = encoding_data
- userid = encoder(userid)
- user_data = 'userid_type:%s' % encoding
+ else:
+ warnings.warn(
+ "userid is of type {}, and is not supported by the "
+ "AuthTktAuthenticationPolicy. Explicitly converting to string "
+ "and storing as base64. Subsequent requests will receive a "
+ "string as the userid, it will not be decoded back to the type "
+ "provided.".format(type(userid)), RuntimeWarning
+ )
+ encoding, encoder = self.userid_type_encoders.get(text_type)
+ userid = str(userid)
+
+ userid = encoder(userid)
+ user_data = 'userid_type:%s' % encoding
new_tokens = []
for token in tokens:
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index 5b915ffdf..9b3f19510 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -1,7 +1,6 @@
import json
import os
import re
-import warnings
from zope.interface import (
implementer,
@@ -273,7 +272,7 @@ class JSON(object):
if ct == response.default_content_type:
response.content_type = 'application/json'
default = self._make_default(request)
- return self.serializer(value, default=default, **self.kw).encode('UTF-8')
+ return self.serializer(value, default=default, **self.kw)
return _render
@@ -380,7 +379,7 @@ class JSONP(JSON):
raise HTTPBadRequest('Invalid JSONP callback function name.')
ct = 'application/javascript'
- body = '/**/{0}({1});'.format(callback, val).encode('UTF-8')
+ body = '/**/{0}({1});'.format(callback, val)
response = request.response
if response.content_type == response.default_content_type:
response.content_type = ct
@@ -468,17 +467,7 @@ class RendererHelper(object):
if result is not None:
if isinstance(result, text_type):
- if response.charset is None:
- warnings.warn(
- "Renderer returned a result of type {0}, "
- "however the response Content-Type <{1}> does not "
- "have a charset. Implicitly encoding the result as "
- "UTF-8.".format(type(result), response.content_type),
- RuntimeWarning
- )
- response.body = result.encode('UTF-8')
- else:
- response.text = result
+ response.text = result
elif isinstance(result, bytes):
response.body = result
elif hasattr(result, '__iter__'):
diff --git a/pyramid/scaffolds/__init__.py b/pyramid/scaffolds/__init__.py
index 62c3eeecc..841dc403e 100644
--- a/pyramid/scaffolds/__init__.py
+++ b/pyramid/scaffolds/__init__.py
@@ -4,7 +4,7 @@ from textwrap import dedent
from pyramid.compat import native_
-from pyramid.scaffolds.template import Template # API
+from pyramid.scaffolds.template import Template # API
class PyramidTemplate(Template):
"""
@@ -60,5 +60,6 @@ class ZODBProjectTemplate(PyramidTemplate):
class AlchemyProjectTemplate(PyramidTemplate):
_template_dir = 'alchemy'
- summary = 'Pyramid project using SQLAlchemy, SQLite, URL dispatch, and'
- ' Chameleon'
+ summary = (
+ 'Pyramid project using SQLAlchemy, SQLite, URL dispatch, and '
+ 'Jinja2')
diff --git a/pyramid/scripts/proutes.py b/pyramid/scripts/proutes.py
index 19d91cc72..f75810c06 100644
--- a/pyramid/scripts/proutes.py
+++ b/pyramid/scripts/proutes.py
@@ -296,7 +296,7 @@ class PRoutesCommand(object):
items = config.items('proutes')
for k, v in items:
if 'format' == k:
- cols = re.split(r'[,|\s|\n]*', v)
+ cols = re.split(r'[,|\s\n]+', v)
self.column_format = [x.strip() for x in cols]
except configparser.NoSectionError:
diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py
index 32923c9ab..b9a4c6be4 100644
--- a/pyramid/tests/test_authentication.py
+++ b/pyramid/tests/test_authentication.py
@@ -1089,7 +1089,10 @@ class TestAuthTktCookieHelper(unittest.TestCase):
helper = self._makeOne('secret')
request = self._makeRequest()
userid = object()
- result = helper.remember(request, userid)
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always', RuntimeWarning)
+ result = helper.remember(request, userid)
+ self.assertTrue(str(w[-1].message).startswith('userid is of type'))
values = self._parseHeaders(result)
self.assertEqual(len(result), 3)
value = values[0]
diff --git a/pyramid/tests/test_config/test_views.py b/pyramid/tests/test_config/test_views.py
index c57deec7a..878574e88 100644
--- a/pyramid/tests/test_config/test_views.py
+++ b/pyramid/tests/test_config/test_views.py
@@ -2168,7 +2168,7 @@ class TestViewsConfigurationMixin(unittest.TestCase):
ctx_iface=implementedBy(HTTPNotFound),
request_iface=IRequest)
result = view(None, request)
- self._assertBody(result, b'{}')
+ self._assertBody(result, '{}')
def test_add_forbidden_view_with_renderer(self):
from zope.interface import implementedBy
@@ -2185,7 +2185,7 @@ class TestViewsConfigurationMixin(unittest.TestCase):
ctx_iface=implementedBy(HTTPForbidden),
request_iface=IRequest)
result = view(None, request)
- self._assertBody(result, b'{}')
+ self._assertBody(result, '{}')
def test_set_view_mapper(self):
from pyramid.interfaces import IViewMapperFactory
diff --git a/pyramid/tests/test_renderers.py b/pyramid/tests/test_renderers.py
index ce337cd99..65bfa5582 100644
--- a/pyramid/tests/test_renderers.py
+++ b/pyramid/tests/test_renderers.py
@@ -18,7 +18,7 @@ class TestJSON(unittest.TestCase):
def test_it(self):
renderer = self._makeOne()(None)
result = renderer({'a':1}, {})
- self.assertEqual(result, b'{"a": 1}')
+ self.assertEqual(result, '{"a": 1}')
def test_with_request_content_type_notset(self):
request = testing.DummyRequest()
@@ -43,7 +43,7 @@ class TestJSON(unittest.TestCase):
renderer = self._makeOne()
renderer.add_adapter(datetime, adapter)
result = renderer(None)({'a':now}, {'request':request})
- self.assertEqual(result, '{{"a": "{0}"}}'.format(now.isoformat()).encode('UTF-8'))
+ self.assertEqual(result, '{"a": "%s"}' % now.isoformat())
def test_with_custom_adapter2(self):
request = testing.DummyRequest()
@@ -54,7 +54,7 @@ class TestJSON(unittest.TestCase):
now = datetime.utcnow()
renderer = self._makeOne(adapters=((datetime, adapter),))
result = renderer(None)({'a':now}, {'request':request})
- self.assertEqual(result, '{{"a": "{0}"}}'.format(now.isoformat()).encode('UTF-8'))
+ self.assertEqual(result, '{"a": "%s"}' % now.isoformat())
def test_with_custom_serializer(self):
class Serializer(object):
@@ -66,7 +66,7 @@ class TestJSON(unittest.TestCase):
renderer = self._makeOne(serializer=serializer, baz=5)
obj = {'a':'b'}
result = renderer(None)(obj, {})
- self.assertEqual(result, b'foo')
+ self.assertEqual(result, 'foo')
self.assertEqual(serializer.obj, obj)
self.assertEqual(serializer.kw['baz'], 5)
self.assertTrue('default' in serializer.kw)
@@ -84,7 +84,7 @@ class TestJSON(unittest.TestCase):
objects = [MyObject(1), MyObject(2)]
renderer = self._makeOne()(None)
result = renderer(objects, {'request':request})
- self.assertEqual(result, b'[{"x": 1}, {"x": 2}]')
+ self.assertEqual(result, '[{"x": 1}, {"x": 2}]')
def test_with_object_adapter_no___json__(self):
class MyObject(object):
@@ -290,19 +290,6 @@ class TestRendererHelper(unittest.TestCase):
response = helper._make_response(la.encode('utf-8'), request)
self.assertEqual(response.body, la.encode('utf-8'))
- def test__make_response_result_is_str_no_charset(self):
- from pyramid.response import Response
- request = testing.DummyRequest()
- request.response = Response(content_type='application/json', charset=None)
-
- self.assertIsNone(request.response.charset)
-
- helper = self._makeOne('loo.foo')
- la = text_('/La Pe\xc3\xb1a', 'utf-8')
- response = helper._make_response(la, request)
- self.assertIsNone(response.charset)
- self.assertEqual(response.body, la.encode('utf-8'))
-
def test__make_response_result_is_iterable(self):
from pyramid.response import Response
request = testing.DummyRequest()
@@ -505,7 +492,7 @@ class Test_render(unittest.TestCase):
request.response = response
# use a json renderer, which will mutate the response
result = self._callFUT('json', dict(a=1), request=request)
- self.assertEqual(result, b'{"a": 1}')
+ self.assertEqual(result, '{"a": 1}')
self.assertEqual(request.response, response)
def test_no_response_to_preserve(self):
@@ -520,7 +507,7 @@ class Test_render(unittest.TestCase):
request = DummyRequestWithClassResponse()
# use a json renderer, which will mutate the response
result = self._callFUT('json', dict(a=1), request=request)
- self.assertEqual(result, b'{"a": 1}')
+ self.assertEqual(result, '{"a": 1}')
self.assertFalse('response' in request.__dict__)
class Test_render_to_response(unittest.TestCase):
@@ -640,7 +627,7 @@ class TestJSONP(unittest.TestCase):
request = testing.DummyRequest()
request.GET['callback'] = 'callback'
result = renderer({'a':'1'}, {'request':request})
- self.assertEqual(result, b'/**/callback({"a": "1"});')
+ self.assertEqual(result, '/**/callback({"a": "1"});')
self.assertEqual(request.response.content_type,
'application/javascript')
@@ -650,7 +637,7 @@ class TestJSONP(unittest.TestCase):
request = testing.DummyRequest()
request.GET['callback'] = 'angular.callbacks._0'
result = renderer({'a':'1'}, {'request':request})
- self.assertEqual(result, b'/**/angular.callbacks._0({"a": "1"});')
+ self.assertEqual(result, '/**/angular.callbacks._0({"a": "1"});')
self.assertEqual(request.response.content_type,
'application/javascript')
diff --git a/tox.ini b/tox.ini
index 0156d9e51..a74aaadbc 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,8 +1,9 @@
[tox]
envlist =
- py27,py33,py34,py35,pypy,
+ py27,py33,py34,py35,py36,pypy,
docs,pep8,
{py2,py3}-cover,coverage,
+skip-missing-interpreters = True
[testenv]
# Most of these are defaults but if you specify any you can't fall back
@@ -12,6 +13,7 @@ basepython =
py33: python3.3
py34: python3.4
py35: python3.5
+ py36: python3.6
pypy: pypy
py2: python2.7
py3: python3.5