Merge branch 'master' into pr/2854
| | |
| | | See https://github.com/Pylons/pyramid/pull/2854 and |
| | | https://github.com/Pylons/pyramid/pull/3019 |
| | | |
| | | - The ``pyramid.config.Configurator`` can now be used as a context manager |
| | | which will automatically push/pop threadlocals (similar to |
| | | ``config.begin()`` and ``config.end()``). It will also automatically perform |
| | | a ``config.commit()`` and thus it is only recommended to be used at the |
| | | top-level of your app. See https://github.com/Pylons/pyramid/pull/2874 |
| | | |
| | | Bug Fixes |
| | | --------- |
| | |
| | | - Martin Frlin, 2016/12/7 |
| | | |
| | | - Kirill Kuzminykh, 2017/03/01 |
| | | |
| | | - Jeremy(Ching-Rui) Chen, 2017/04/19 |
| | |
| | | |
| | | See https://github.com/Pylons/pyramid/pull/2873 |
| | | |
| | | - Added a new ``callback`` option to ``config.set_default_csrf_options`` which |
| | | can be used to determine per-request whether CSRF checking should be enabled |
| | | to allow for a mix authentication methods. Only cookie-based methods |
| | | generally require CSRF checking. |
| | | See https://github.com/Pylons/pyramid/pull/2778 |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | |
| | | return Response('Hello %(name)s!' % request.matchdict) |
| | | |
| | | if __name__ == '__main__': |
| | | config = Configurator() |
| | | config.add_route('hello', '/hello/{name}') |
| | | config.add_view(hello_world, route_name='hello') |
| | | app = config.make_wsgi_app() |
| | | with Configurator() as config: |
| | | config.add_route('hello', '/hello/{name}') |
| | | config.add_view(hello_world, route_name='hello') |
| | | app = config.make_wsgi_app() |
| | | server = make_server('0.0.0.0', 8080, app) |
| | | server.serve_forever() |
| | | |
| | |
| | | cookiecutter which does not create these files, the configuration information in |
| | | this chapter may not be applicable. |
| | | |
| | | .. index: |
| | | .. index:: |
| | | pair: settings; logging |
| | | pair: .ini; logging |
| | | pair: logging; configuration |
| | |
| | | MyProject |
| | | =============================== |
| | | ========= |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before. |
| | | Is it okay to delete and re-clone it? [yes]: yes |
| | | project_name [Pyramid Scaffold]: myproject |
| | | repo_name [scaffold]: myproject |
| | | repo_name [myproject]: myproject |
| | | Select template_language: |
| | | 1 - jinja2 |
| | | 2 - chameleon |
| | |
| | | You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before. |
| | | Is it okay to delete and re-clone it? [yes]: yes |
| | | project_name [Pyramid Scaffold]: hello_world |
| | | repo_name [scaffold]: hello_world |
| | | repo_name [hello_world]: hello_world |
| | | Select template_language: |
| | | 1 - jinja2 |
| | | 2 - chameleon |
| | |
| | | You've cloned ~/.cookiecutters/pyramid-cookiecutter-alchemy before. |
| | | Is it okay to delete and re-clone it? [yes]: yes |
| | | project_name [Pyramid Scaffold]: sqla_demo |
| | | repo_name [scaffold]: sqla_demo |
| | | repo_name [sqla_demo]: sqla_demo |
| | | |
| | | We then run through the following commands as before. |
| | | |
| | |
| | | hello_world |
| | | =============================== |
| | | =========== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | hello_world |
| | | =============================== |
| | | =========== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | hello_world |
| | | =============================== |
| | | =========== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | sqla_demo |
| | | =============================== |
| | | ========= |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before. |
| | | Is it okay to delete and re-clone it? [yes]: yes |
| | | project_name [Pyramid Scaffold]: cc_starter |
| | | repo_name [scaffold]: cc_starter |
| | | repo_name [cc_starter]: cc_starter |
| | | Select template_language: |
| | | 1 - jinja2 |
| | | 2 - chameleon |
| | |
| | | cc_starter |
| | | =============================== |
| | | ========== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before. |
| | | Is it okay to delete and re-clone it? [yes]: yes |
| | | project_name [Pyramid Scaffold]: myproject |
| | | repo_name [scaffold]: myproject |
| | | repo_name [myproject]: myproject |
| | | Select template_language: |
| | | 1 - jinja2 |
| | | 2 - chameleon |
| | |
| | | You've cloned ~/.cookiecutters/pyramid-cookiecutter-zodb before. |
| | | Is it okay to delete and re-clone it? [yes]: yes |
| | | project_name [Pyramid Scaffold]: myproj |
| | | repo_name [scaffold]: tutorial |
| | | repo_name [myproj]: tutorial |
| | | |
| | | Change directory into your newly created project |
| | | ------------------------------------------------ |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | You've cloned ~/.cookiecutters/pyramid-cookiecutter-alchemy before. |
| | | Is it okay to delete and re-clone it? [yes]: yes |
| | | project_name [Pyramid Scaffold]: myproj |
| | | repo_name [scaffold]: tutorial |
| | | repo_name [myproj]: tutorial |
| | | |
| | | Change directory into your newly created project |
| | | ------------------------------------------------ |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | import cgi |
| | | from pyramid.compat import escape |
| | | import re |
| | | from docutils.core import publish_parts |
| | | |
| | |
| | | exists = request.dbsession.query(Page).filter_by(name=word).all() |
| | | if exists: |
| | | view_url = request.route_url('view_page', pagename=word) |
| | | return '<a href="%s">%s</a>' % (view_url, cgi.escape(word)) |
| | | return '<a href="%s">%s</a>' % (view_url, escape(word)) |
| | | else: |
| | | add_url = request.route_url('add_page', pagename=word) |
| | | return '<a href="%s">%s</a>' % (add_url, cgi.escape(word)) |
| | | return '<a href="%s">%s</a>' % (add_url, escape(word)) |
| | | |
| | | content = publish_parts(page.data, writer_name='html')['html_body'] |
| | | content = wikiwords.sub(add_link, content) |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | import cgi |
| | | from pyramid.compat import escape |
| | | import re |
| | | from docutils.core import publish_parts |
| | | |
| | |
| | | exists = request.dbsession.query(Page).filter_by(name=word).all() |
| | | if exists: |
| | | view_url = request.route_url('view_page', pagename=word) |
| | | return '<a href="%s">%s</a>' % (view_url, cgi.escape(word)) |
| | | return '<a href="%s">%s</a>' % (view_url, escape(word)) |
| | | else: |
| | | add_url = request.route_url('add_page', pagename=word) |
| | | return '<a href="%s">%s</a>' % (add_url, cgi.escape(word)) |
| | | return '<a href="%s">%s</a>' % (add_url, escape(word)) |
| | | |
| | | content = publish_parts(page.data, writer_name='html')['html_body'] |
| | | content = wikiwords.sub(add_link, content) |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | import cgi |
| | | from pyramid.compat import escape |
| | | import re |
| | | from docutils.core import publish_parts |
| | | |
| | |
| | | exists = request.dbsession.query(Page).filter_by(name=word).all() |
| | | if exists: |
| | | view_url = request.route_url('view_page', pagename=word) |
| | | return '<a href="%s">%s</a>' % (view_url, cgi.escape(word)) |
| | | return '<a href="%s">%s</a>' % (view_url, escape(word)) |
| | | else: |
| | | add_url = request.route_url('add_page', pagename=word) |
| | | return '<a href="%s">%s</a>' % (add_url, cgi.escape(word)) |
| | | return '<a href="%s">%s</a>' % (add_url, escape(word)) |
| | | |
| | | content = publish_parts(page.data, writer_name='html')['html_body'] |
| | | content = wikiwords.sub(add_link, content) |
| | |
| | | myproj |
| | | =============================== |
| | | ====== |
| | | |
| | | Getting Started |
| | | --------------- |
| | |
| | | import cgi |
| | | from pyramid.compat import escape |
| | | import re |
| | | from docutils.core import publish_parts |
| | | |
| | |
| | | exists = request.dbsession.query(Page).filter_by(name=word).all() |
| | | if exists: |
| | | view_url = request.route_url('view_page', pagename=word) |
| | | return '<a href="%s">%s</a>' % (view_url, cgi.escape(word)) |
| | | return '<a href="%s">%s</a>' % (view_url, escape(word)) |
| | | else: |
| | | add_url = request.route_url('add_page', pagename=word) |
| | | return '<a href="%s">%s</a>' % (add_url, cgi.escape(word)) |
| | | return '<a href="%s">%s</a>' % (add_url, escape(word)) |
| | | |
| | | content = publish_parts(page.data, writer_name='html')['html_body'] |
| | | content = wikiwords.sub(add_link, content) |
| | |
| | | later calls to place translation directories at a higher priority then |
| | | earlier calls. See https://github.com/Pylons/pyramid/pull/2902 |
| | | |
| | | - Added a new ``callback`` option to |
| | | :meth:`pyramid.config.Configurator.set_default_csrf_options`` which |
| | | can be used to determine per-request whether CSRF checking should be enabled |
| | | to allow for a mix authentication methods. Only cookie-based methods |
| | | generally require CSRF checking. |
| | | See https://github.com/Pylons/pyramid/pull/2778 |
| | | |
| | | Backwards Incompatibilities |
| | | --------------------------- |
| | | |
| | |
| | | A Configurator is used to configure a :app:`Pyramid` |
| | | :term:`application registry`. |
| | | |
| | | The Configurator lifecycle can be managed by using a context manager to |
| | | automatically handle calling :meth:`pyramid.config.Configurator.begin` and |
| | | :meth:`pyramid.config.Configurator.end` as well as |
| | | :meth:`pyramid.config.Configurator.commit`. |
| | | |
| | | .. code-block:: python |
| | | |
| | | with Configurator(settings=settings) as config: |
| | | config.add_route('home', '/') |
| | | app = config.make_wsgi_app() |
| | | |
| | | If the ``registry`` argument is not ``None``, it must |
| | | be an instance of the :class:`pyramid.registry.Registry` class |
| | | representing the registry to configure. If ``registry`` is ``None``, the |
| | |
| | | .. versionadded:: 1.6 |
| | | The ``root_package`` argument. |
| | | The ``response_factory`` argument. |
| | | |
| | | .. versionadded:: 1.9 |
| | | The ability to use the configurator as a context manager with the |
| | | ``with``-statement to make threadlocal configuration available for |
| | | further configuration with an implicit commit. |
| | | """ |
| | | manager = manager # for testing injection |
| | | venusian = venusian # for testing injection |
| | |
| | | _ctx = action_state # bw compat |
| | | |
| | | def commit(self): |
| | | """ Commit any pending configuration actions. If a configuration |
| | | """ |
| | | Commit any pending configuration actions. If a configuration |
| | | conflict is detected in the pending configuration actions, this method |
| | | will raise a :exc:`ConfigurationConflictError`; within the traceback |
| | | of this error will be information about the source of the conflict, |
| | | usually including file names and line numbers of the cause of the |
| | | configuration conflicts.""" |
| | | configuration conflicts. |
| | | |
| | | .. warning:: |
| | | You should think very carefully before manually invoking |
| | | ``commit()``. Especially not as part of any reusable configuration |
| | | methods. Normally it should only be done by an application author at |
| | | the end of configuration in order to override certain aspects of an |
| | | addon. |
| | | |
| | | """ |
| | | self.begin() |
| | | try: |
| | | self.action_state.execute_actions(introspector=self.introspector) |
| | |
| | | """ |
| | | return self.manager.pop() |
| | | |
| | | def __enter__(self): |
| | | self.begin() |
| | | return self |
| | | |
| | | def __exit__(self, exc_type, exc_value, exc_traceback): |
| | | self.end() |
| | | |
| | | if exc_value is None: |
| | | self.commit() |
| | | |
| | | # this is *not* an action method (uses caller_package) |
| | | def scan(self, package=None, categories=None, onerror=None, ignore=None, |
| | | **kw): |
| | |
| | | are not subject to CSRF attacks. For example, if a request is |
| | | authenticated using the ``Authorization`` header instead of a cookie, |
| | | this may return ``False`` for that request so that clients do not |
| | | need to send the ``X-CSRF-Token` header. The callback is only tested |
| | | need to send the ``X-CSRF-Token`` header. The callback is only tested |
| | | for non-safe methods as defined by ``safe_methods``. |
| | | |
| | | .. versionadded:: 1.7 |
| | | |
| | | .. versionchanged:: 1.8 |
| | | Added the ``callback`` option. |
| | | |
| | | """ |
| | | options = DefaultCSRFOptions( |
| | | require_csrf, token, header, safe_methods, callback, |
| | |
| | | def register_view(classifier, request_iface, derived_view): |
| | | # A multiviews is a set of views which are registered for |
| | | # exactly the same context type/request type/name triad. Each |
| | | # consituent view in a multiview differs only by the |
| | | # constituent view in a multiview differs only by the |
| | | # predicates which it possesses. |
| | | |
| | | # To find a previously registered view for a context |
| | |
| | | |
| | | # XXX we could try to be more efficient here and register |
| | | # a non-secured view for a multiview if none of the |
| | | # multiview's consituent views have a permission |
| | | # multiview's constituent views have a permission |
| | | # associated with them, but this code is getting pretty |
| | | # rough already |
| | | if is_multiview: |
| | |
| | | self.assertEqual(manager.pushed, pushed) |
| | | self.assertEqual(manager.popped, True) |
| | | |
| | | def test_context_manager(self): |
| | | from pyramid.config import Configurator |
| | | config = Configurator() |
| | | manager = DummyThreadLocalManager() |
| | | config.manager = manager |
| | | view = lambda r: None |
| | | with config as ctx: |
| | | self.assertTrue(config is ctx) |
| | | self.assertEqual(manager.pushed, |
| | | {'registry': config.registry, 'request': None}) |
| | | self.assertFalse(manager.popped) |
| | | config.add_view(view) |
| | | self.assertTrue(manager.popped) |
| | | config.add_view(view) # did not raise a conflict because of commit |
| | | config.commit() |
| | | |
| | | def test_ctor_with_package_registry(self): |
| | | import sys |
| | | from pyramid.config import Configurator |