diff options
| author | Chris McDonough <chrism@plope.com> | 2013-07-24 16:02:16 -0400 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2013-07-24 16:02:16 -0400 |
| commit | d79c0338e6b87ffa657f91065ce73c752f60a0b8 (patch) | |
| tree | 458ac51936a8c58459a1fcb3cf9f23c697465e92 | |
| parent | f47bccfb279ff102d1be2b4b37c201a4cde8f365 (diff) | |
| parent | 716464c1706e7f68977bd5467023b6380d05e545 (diff) | |
| download | pyramid-d79c0338e6b87ffa657f91065ce73c752f60a0b8.tar.gz pyramid-d79c0338e6b87ffa657f91065ce73c752f60a0b8.tar.bz2 pyramid-d79c0338e6b87ffa657f91065ce73c752f60a0b8.zip | |
Merge branch 'master' of github.com:Pylons/pyramid
| -rw-r--r-- | CHANGES.txt | 52 | ||||
| -rw-r--r-- | CONTRIBUTORS.txt | 2 | ||||
| -rw-r--r-- | HACKING.txt | 2 | ||||
| -rw-r--r-- | docs/authorintro.rst | 2 | ||||
| -rw-r--r-- | docs/conf.py | 2 | ||||
| -rw-r--r-- | docs/index.rst | 5 | ||||
| -rw-r--r-- | docs/latexindex.rst | 27 | ||||
| -rw-r--r-- | docs/narr/renderers.rst | 2 | ||||
| -rw-r--r-- | docs/whatsnew-1.5.rst | 125 | ||||
| -rw-r--r-- | pyramid/authentication.py | 40 | ||||
| -rw-r--r-- | pyramid/config/routes.py | 4 | ||||
| -rw-r--r-- | pyramid/router.py | 6 | ||||
| -rw-r--r-- | pyramid/testing.py | 2 | ||||
| -rw-r--r-- | pyramid/tests/test_authentication.py | 24 | ||||
| -rw-r--r-- | pyramid/tests/test_router.py | 8 | ||||
| -rw-r--r-- | setup.py | 2 |
16 files changed, 244 insertions, 61 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 0156b24fd..0031fc635 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,4 @@ -next release +Next Release ============ Features @@ -6,7 +6,7 @@ Features - ``scripts/prequest.py``: add support for submitting ``PUT`` and ``PATCH`` requests. See https://github.com/Pylons/pyramid/pull/1033. add support for - submitting ``OPTIONS`` and ``PROPFIND`` requests, and allow users to specify + submitting ``OPTIONS`` and ``PROPFIND`` requests, and allow users to specify basic authentication credentials in the request via a ``--login`` argument to the script. See https://github.com/Pylons/pyramid/pull/1039. @@ -21,6 +21,10 @@ Features ``pyramid.config.Configurator.add_static_view``. This allows externally-hosted static URLs to be generated based on the current protocol. +- The ``AuthTktAuthenticationPolicy`` has a new ``parent_domain`` option to + set the authentication cookie as a wildcard cookie on the parent domain. This + is useful if you have multiple sites sharing the same domain. + - The ``AuthTktAuthenticationPolicy`` now supports IPv6 addresses when using the ``include_ip=True`` option. This is possibly incompatible with alternative ``auth_tkt`` implementations, as the specification does not @@ -40,22 +44,6 @@ Features ``X-CSRF-Token`` (as well as the ``csrf_token`` form parameter, which they always did). The header is tried when the form parameter does not exist. -Bug Fixes ---------- - -- Make the ``pyramid.config.assets.PackageOverrides`` object implement the API - for ``__loader__`` objects specified in PEP 302. Proxies to the - ``__loader__`` set by the importer, if present; otherwise, raises - ``NotImplementedError``. This makes Pyramid static view overrides work - properly under Python 3.3 (previously they would not). See - https://github.com/Pylons/pyramid/pull/1015 for more information. - -- ``mako_templating``: added defensive workaround for non-importability of - ``mako`` due to upstream ``markupsafe`` dropping Python 3.2 support. Mako - templating will no longer work under the combination of MarkupSafe 0.17 and - Python 3.2 (although the combination of MarkupSafe 0.17 and Python 3.3 or any - supported Python 2 version will work OK). - - View lookup will now search for valid views based on the inheritance hierarchy of the context. It tries to find views based on the most specific context first, and upon predicate failure, will move up the @@ -63,7 +51,7 @@ Bug Fixes In the past, only the most specific type containing views would be checked and if no matching view could be found then a PredicateMismatch would be raised. Now predicate mismatches don't hide valid views registered on - super-types. Here's an example that now works:: + super-types. Here's an example that now works: .. code-block:: python @@ -101,7 +89,25 @@ Bug Fixes predicate mismatch error when trying to use GET or DELETE methods. Now the views are found and no predicate mismatch is raised. - See https://github.com/Pylons/pyramid/pull/786 + See https://github.com/Pylons/pyramid/pull/786 and + https://github.com/Pylons/pyramid/pull/1004 and + https://github.com/Pylons/pyramid/pull/1046 + +Bug Fixes +--------- + +- Make the ``pyramid.config.assets.PackageOverrides`` object implement the API + for ``__loader__`` objects specified in PEP 302. Proxies to the + ``__loader__`` set by the importer, if present; otherwise, raises + ``NotImplementedError``. This makes Pyramid static view overrides work + properly under Python 3.3 (previously they would not). See + https://github.com/Pylons/pyramid/pull/1015 for more information. + +- ``mako_templating``: added defensive workaround for non-importability of + ``mako`` due to upstream ``markupsafe`` dropping Python 3.2 support. Mako + templating will no longer work under the combination of MarkupSafe 0.17 and + Python 3.2 (although the combination of MarkupSafe 0.17 and Python 3.3 or any + supported Python 2 version will work OK). - Spaces and dots may now be in mako renderer template paths. This was broken when support for the new makodef syntax was added in 1.4a1. @@ -118,9 +124,9 @@ Bug Fixes https://github.com/Pylons/pyramid/issues/981 - ``pyramid.testing.DummyResource`` didn't define ``__bool__``, so code under - Python 3 would use ``__len__`` to find truthiness; this usually caused an - instance of DummyResource to be "falsy" instead of "truthy". See - https://github.com/Pylons/pyramid/pull/1032 + Python 3 would use ``__len__`` to find truthiness; this usually caused an + instance of DummyResource to be "falsy" instead of "truthy". See + https://github.com/Pylons/pyramid/pull/1032 1.4 (2012-12-18) ================ diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 61155ca80..d2b116f46 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -200,3 +200,5 @@ Contributors - Jason McKellar, 2013/03/28 - Luke Cyca, 2013/05/30 + +- Laurence Rowe, 2013/04/24 diff --git a/HACKING.txt b/HACKING.txt index 26e85ee80..5b5dcc458 100644 --- a/HACKING.txt +++ b/HACKING.txt @@ -126,7 +126,7 @@ documentation in this package which references that API or behavior must change to reflect the bug fix, ideally in the same commit that fixes the bug or adds the feature. -To build and review docs (where ``$yourvenv`` refers to the virtualenv you're +To build and review docs (where ``$VENV`` refers to the virtualenv you're using to develop Pyramid): 1. Run ``$VENV/bin/python setup.py dev docs``. This will cause Sphinx diff --git a/docs/authorintro.rst b/docs/authorintro.rst index f1a9d1484..b3cd68494 100644 --- a/docs/authorintro.rst +++ b/docs/authorintro.rst @@ -73,7 +73,7 @@ This book is divided into three major parts: concepts in terms of the sample. You should read the tutorials if you want a guided tour of :app:`Pyramid`. -:ref:`api_reference` +:ref:`api_documentation` Comprehensive reference material for every public API exposed by :app:`Pyramid`. The API documentation is organized diff --git a/docs/conf.py b/docs/conf.py index 84b01a791..ff5f325d8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -93,7 +93,7 @@ copyright = '2008-%s, Agendaless Consulting' % thisyear # other places throughout the built documents. # # The short X.Y version. -version = '1.4' +version = '1.5dev' # The full version, including alpha/beta/rc tags. release = version diff --git a/docs/index.rst b/docs/index.rst index bc711f8ff..22b27039c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,6 +37,7 @@ What's New .. toctree:: :maxdepth: 1 + whatsnew-1.5 whatsnew-1.4 whatsnew-1.3 whatsnew-1.2 @@ -45,7 +46,7 @@ What's New .. _html_narrative_documentation: -Narrative documentation +Narrative Documentation ======================= Narrative documentation in chapter form explaining how to use @@ -110,7 +111,7 @@ platforms. tutorials/modwsgi/index.rst API Documentation -================== +================= Comprehensive reference material for every public API exposed by :app:`Pyramid`: diff --git a/docs/latexindex.rst b/docs/latexindex.rst index 6bb875f73..83641d8b3 100644 --- a/docs/latexindex.rst +++ b/docs/latexindex.rst @@ -1,13 +1,13 @@ .. _latexindex: -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -The :app:`Pyramid` Web Application Framework -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +================================================= +The Pyramid Web Application Development Framework +================================================= .. frontmatter:: Front Matter -@@@@@@@@@@@@ +============ .. toctree:: :maxdepth: 1 @@ -21,15 +21,15 @@ Front Matter .. _narrative_documentation: Narrative Documentation -@@@@@@@@@@@@@@@@@@@@@@@ +======================= .. toctree:: :maxdepth: 1 narr/introduction narr/install - narr/configuration narr/firstapp + narr/configuration narr/project narr/startup narr/router @@ -50,6 +50,7 @@ Narrative Documentation narr/vhosting narr/testing narr/resources + narr/hellotraversal narr/muchadoabouttraversal narr/traversal narr/security @@ -60,26 +61,28 @@ Narrative Documentation narr/extending narr/advconfig narr/extconfig + narr/scaffolding + narr/upgrading narr/threadlocals narr/zca .. _tutorials: Tutorials -@@@@@@@@@ +========= .. toctree:: :maxdepth: 1 - tutorials/wiki/index.rst tutorials/wiki2/index.rst + tutorials/wiki/index.rst tutorials/bfg/index.rst tutorials/modwsgi/index.rst -.. _api_reference: +.. _api_documentation: -API Reference -@@@@@@@@@@@@@ +API Documentation +================= .. toctree:: :maxdepth: 1 @@ -111,7 +114,7 @@ API Reference .. backmatter:: Glossary and Index -@@@@@@@@@@@@@@@@@@ +================== .. toctree:: :maxdepth: 1 diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst index 20a9eda31..a2811dbae 100644 --- a/docs/narr/renderers.rst +++ b/docs/narr/renderers.rst @@ -198,7 +198,7 @@ representing the JSON serialization of the return value: .. code-block:: python - '{"content": "Hello!"}' + {"content": "Hello!"} The return value needn't be a dictionary, but the return value must contain values serializable by the configured serializer (by default ``json.dumps``). diff --git a/docs/whatsnew-1.5.rst b/docs/whatsnew-1.5.rst new file mode 100644 index 000000000..47b768eb9 --- /dev/null +++ b/docs/whatsnew-1.5.rst @@ -0,0 +1,125 @@ +What's New In Pyramid 1.5 +========================= + +This article explains the new features in :app:`Pyramid` version 1.5 as +compared to its predecessor, :app:`Pyramid` 1.4. It also documents backwards +incompatibilities between the two versions and deprecations added to +:app:`Pyramid` 1.5, as well as software dependency changes and notable +documentation additions. + +Feature Additions +----------------- + +The feature additions in Pyramid 1.5 follow. + +- View lookup will now search for valid views based on the inheritance + hierarchy of the context. It tries to find views based on the most specific + context first, and upon predicate failure, will move up the inheritance chain + to test views found by the super-type of the context. In the past, only the + most specific type containing views would be checked and if no matching view + could be found then a PredicateMismatch would be raised. Now predicate + mismatches don't hide valid views registered on super-types. Here's an + example that now works: + + .. code-block:: python + + class IResource(Interface): + + ... + + @view_config(context=IResource) + def get(context, request): + + ... + + @view_config(context=IResource, request_method='POST') + def post(context, request): + + ... + + @view_config(context=IResource, request_method='DELETE') + def delete(context, request): + + ... + + @implementor(IResource) + class MyResource: + + ... + + @view_config(context=MyResource, request_method='POST') + def override_post(context, request): + + ... + + Previously the override_post view registration would hide the get + and delete views in the context of MyResource -- leading to a + predicate mismatch error when trying to use GET or DELETE + methods. Now the views are found and no predicate mismatch is + raised. + See https://github.com/Pylons/pyramid/pull/786 and + https://github.com/Pylons/pyramid/pull/1004 and + https://github.com/Pylons/pyramid/pull/1046 + +- ``scripts/prequest.py`` (aka the ``prequest`` console script): added support + for submitting ``PUT`` and ``PATCH`` requests. See + https://github.com/Pylons/pyramid/pull/1033. add support for submitting + ``OPTIONS`` and ``PROPFIND`` requests, and allow users to specify basic + authentication credentials in the request via a ``--login`` argument to the + script. See https://github.com/Pylons/pyramid/pull/1039. + +- :class:`pyramid.authorization.ACLAuthorizationPolicy` supports ``__acl__`` as + a callable. This removes the ambiguity between the potential + ``AttributeError`` that would be raised on the ``context`` when the property + was not defined and the ``AttributeError`` that could be raised from any + user-defined code within a dynamic property. It is recommended to define a + dynamic ACL as a callable to avoid this ambiguity. See + https://github.com/Pylons/pyramid/issues/735. + +- Allow a protocol-relative URL (e.g. ``//example.com/images``) to be passed to + :meth:`pyramid.config.Configurator.add_static_view`. This allows + externally-hosted static URLs to be generated based on the current protocol. + +- The :class:`pyramid.authentication.AuthTktAuthenticationPolicy` has a new + ``parent_domain`` option to set the authentication cookie as a wildcard + cookie on the parent domain. This is useful if you have multiple sites + sharing the same domain. It also now supports IPv6 addresses when using + the ``include_ip=True`` option. This is possibly incompatible with + alternative ``auth_tkt`` implementations, as the specification does not + define how to properly handle IPv6. See + https://github.com/Pylons/pyramid/issues/831. + +- Make it possible to use variable arguments via + :func:`pyramid.paster.get_appsettings`. This also allowed the generated + ``initialize_db`` script from the ``alchemy`` scaffold to grow support for + options in the form ``a=1 b=2`` so you can fill in values in a parameterized + ``.ini`` file, e.g. ``initialize_myapp_db etc/development.ini a=1 b=2``. See + https://github.com/Pylons/pyramid/pull/911 + +- The ``request.session.check_csrf_token()`` method and the ``check_csrf`` view + predicate now take into account the value of the HTTP header named + ``X-CSRF-Token`` (as well as the ``csrf_token`` form parameter, which they + always did). The header is tried when the form parameter does not exist. + +Backwards Incompatibilities +--------------------------- + +This release has no known backwards incompatibilities with Pyramid 1.4.X. + +Deprecations +------------ + +This release has no new deprecations as compared to Pyramid 1.4.X. + + +Documentation Enhancements +-------------------------- + +Many documentation enhancements have been added, but we did not track them as +they were added. + +Dependency Changes +------------------ + +No dependency changes from Pyramid 1.4.X were made in Pyramid 1.5. + diff --git a/pyramid/authentication.py b/pyramid/authentication.py index bc0286ed3..c1aa970bd 100644 --- a/pyramid/authentication.py +++ b/pyramid/authentication.py @@ -511,9 +511,23 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): ``wild_domain`` Default: ``True``. An auth_tkt cookie will be generated for the - wildcard domain. + wildcard domain. If your site is hosted as ``example.com`` this + will make the cookie available for sites underneath ``example.com`` + such as ``www.example.com``. Optional. + ``parent_domain`` + + Default: ``False``. An auth_tkt cookie will be generated for the + parent domain of the current site. For example if your site is + hosted under ``www.example.com`` a cookie will be generated for + ``.example.com``. This can be useful if you have multiple sites + sharing the same domain. This option supercedes the ``wild_domain`` + option. + Optional. + + This option is available as of :app:`Pyramid` 1.5. + ``hashalg`` Default: ``md5`` (the literal string). @@ -565,7 +579,8 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): http_only=False, wild_domain=True, debug=False, - hashalg=_marker + hashalg=_marker, + parent_domain=False, ): if hashalg is _marker: hashalg = 'md5' @@ -603,6 +618,7 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): path=path, wild_domain=wild_domain, hashalg=hashalg, + parent_domain=parent_domain, ) self.callback = callback self.debug = debug @@ -800,7 +816,7 @@ class AuthTktCookieHelper(object): def __init__(self, secret, cookie_name='auth_tkt', secure=False, include_ip=False, timeout=None, reissue_time=None, max_age=None, http_only=False, path="/", wild_domain=True, - hashalg='md5'): + hashalg='md5', parent_domain=False): self.secret = secret self.cookie_name = cookie_name self.include_ip = include_ip @@ -811,6 +827,7 @@ class AuthTktCookieHelper(object): self.http_only = http_only self.path = path self.wild_domain = wild_domain + self.parent_domain = parent_domain self.hashalg = hashalg static_flags = [] @@ -850,16 +867,19 @@ class AuthTktCookieHelper(object): cookies = [ ('Set-Cookie', '%s="%s"; Path=%s%s%s' % ( - self.cookie_name, value, self.path, max_age, self.static_flags)), - ('Set-Cookie', '%s="%s"; Path=%s; Domain=%s%s%s' % ( - self.cookie_name, value, self.path, cur_domain, max_age, - self.static_flags)), + self.cookie_name, value, self.path, max_age, self.static_flags)) ] - if self.wild_domain: - wild_domain = '.' + cur_domain + domains = [] + if self.parent_domain and cur_domain.count('.') > 1: + domains.append('.' + cur_domain.split('.', 1)[1]) + else: + domains.append(cur_domain) + if self.wild_domain: + domains.append('.' + cur_domain) + for domain in domains: cookies.append(('Set-Cookie', '%s="%s"; Path=%s; Domain=%s%s%s' % ( - self.cookie_name, value, self.path, wild_domain, max_age, + self.cookie_name, value, self.path, domain, max_age, self.static_flags))) return cookies diff --git a/pyramid/config/routes.py b/pyramid/config/routes.py index f495794b4..c86e4a2dd 100644 --- a/pyramid/config/routes.py +++ b/pyramid/config/routes.py @@ -90,10 +90,10 @@ class RoutesConfiguratorMixin(object): ``traverse`` argument provided to ``add_route`` is ``/{article}``, when a request comes in that causes the route to match in such a way that the ``article`` match value is - '1' (when the request URI is ``/articles/1/edit``), the + ``'1'`` (when the request URI is ``/articles/1/edit``), the traversal path will be generated as ``/1``. This means that the root object's ``__getitem__`` will be called with the - name ``1`` during the traversal phase. If the ``1`` object + name ``'1'`` during the traversal phase. If the ``'1'`` object exists, it will become the :term:`context` of the request. :ref:`traversal_chapter` has more information about traversal. diff --git a/pyramid/router.py b/pyramid/router.py index df1f02b22..1a991648b 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -164,10 +164,14 @@ class Router(object): except PredicateMismatch: # look for other views that meet the predicate # criteria - for iface in context_iface.flattened(): + for iface in context_iface.__sro__[1:]: + previous_view_callable = view_callable view_callable = adapters.lookup( (IViewClassifier, request.request_iface, iface), IView, name=view_name, default=None) + # intermediate bases may lookup same view_callable + if view_callable is previous_view_callable: + continue if view_callable is not None: try: response = view_callable(context, request) diff --git a/pyramid/testing.py b/pyramid/testing.py index 9bd245e4e..14c6f4acf 100644 --- a/pyramid/testing.py +++ b/pyramid/testing.py @@ -411,7 +411,7 @@ def setUp(registry=None, request=None, hook_zca=True, autocommit=True, suitable testing analogue. After ``setUp`` is finished, the registry returned by the - :func:`pyramid.threadlocal.get_current_request` function will + :func:`pyramid.threadlocal.get_current_registry` function will be the passed (or constructed) registry until :func:`pyramid.testing.tearDown` is called (or :func:`pyramid.testing.setUp` is called again) . diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py index cfabf9a9d..960a87a6a 100644 --- a/pyramid/tests/test_authentication.py +++ b/pyramid/tests/test_authentication.py @@ -947,6 +947,30 @@ class TestAuthTktCookieHelper(unittest.TestCase): self.assertTrue(result[1][1].endswith('; Path=/; Domain=localhost')) self.assertTrue(result[1][1].startswith('auth_tkt=')) + def test_remember_parent_domain(self): + helper = self._makeOne('secret', parent_domain=True) + request = self._makeRequest() + request.environ['HTTP_HOST'] = 'www.example.com' + result = helper.remember(request, 'other') + self.assertEqual(len(result), 2) + + self.assertEqual(result[0][0], 'Set-Cookie') + self.assertTrue(result[0][1].endswith('; Path=/')) + self.assertTrue(result[0][1].startswith('auth_tkt=')) + + self.assertEqual(result[1][0], 'Set-Cookie') + self.assertTrue(result[1][1].endswith('; Path=/; Domain=.example.com')) + self.assertTrue(result[1][1].startswith('auth_tkt=')) + + def test_remember_parent_domain_supercedes_wild_domain(self): + helper = self._makeOne('secret', parent_domain=True, wild_domain=True) + request = self._makeRequest() + request.environ['HTTP_HOST'] = 'www.example.com' + result = helper.remember(request, 'other') + self.assertEqual(len(result), 2) + self.assertTrue(result[0][1].endswith('; Path=/')) + self.assertTrue(result[1][1].endswith('; Path=/; Domain=.example.com')) + def test_remember_domain_has_port(self): helper = self._makeOne('secret', wild_domain=False) request = self._makeRequest() diff --git a/pyramid/tests/test_router.py b/pyramid/tests/test_router.py index 432959147..b836d7d72 100644 --- a/pyramid/tests/test_router.py +++ b/pyramid/tests/test_router.py @@ -1180,11 +1180,9 @@ class TestRouter(unittest.TestCase): from pyramid.interfaces import IViewClassifier from pyramid.interfaces import IRequest, IResponse from pyramid.response import Response - from zope.interface import Interface, implementer - class IContext(Interface): + class BaseContext: pass - @implementer(IContext) - class DummyContext: + class DummyContext(BaseContext): pass context = DummyContext() self._registerTraverserFactory(context) @@ -1193,7 +1191,7 @@ class TestRouter(unittest.TestCase): DummyContext) good_view = DummyView('abc') self._registerView(self.config.derive_view(good_view), - '', IViewClassifier, IRequest, IContext) + '', IViewClassifier, IRequest, BaseContext) router = self._makeOne() def make_response(s): return Response(s) @@ -70,7 +70,7 @@ testing_extras = tests_require + [ ] setup(name='pyramid', - version='1.4', + version='1.5dev', description=('The Pyramid web application development framework, a ' 'Pylons project'), long_description=README + '\n\n' + CHANGES, |
