Merge remote-tracking branch 'origin/master' into docs.gettingstarted
Conflicts:
docs/index.rst
docs/latexindex.rst
setup.py
3 files added
47 files modified
| | |
| | | next release |
| | | Next Release |
| | | ============ |
| | | |
| | | Features |
| | | -------- |
| | | |
| | | - ``scripts/prequest.py``: add support for submitting ``PUT`` and ``PATCH`` |
| | | requests. See https://github.com/Pylons/pyramid/pull/1033. |
| | | - Add ``pdistreport`` script, which prints the Python version in use, the |
| | | Pyramid version in use, and the version number and location of all Python |
| | | distributions currently installed. |
| | | |
| | | - Add the ability to invert the result of any view, route, or subscriber |
| | | predicate using the ``not_`` class. For example:: |
| | | |
| | | from pyramid.config import not_ |
| | | |
| | | @view_config(route_name='myroute', request_method=not_('POST')) |
| | | def myview(request): ... |
| | | |
| | | The above example will ensure that the view is called if the request method |
| | | is not POST (at least if no other view is more specific). |
| | | |
| | | The :class:`pyramid.config.not_` class can be used against any value that is |
| | | a predicate value passed in any of these contexts: |
| | | |
| | | - ``pyramid.config.Configurator.add_view`` |
| | | |
| | | - ``pyramid.config.Configurator.add_route`` |
| | | |
| | | - ``pyramid.config.Configurator.add_subscriber`` |
| | | |
| | | - ``pyramid.view.view_config`` |
| | | |
| | | - ``pyramid.events.subscriber`` |
| | | |
| | | - ``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 |
| | | basic authentication credentials in the request via a ``--login`` argument to |
| | | the script. See https://github.com/Pylons/pyramid/pull/1039. |
| | | |
| | | - ``ACLAuthorizationPolicy`` supports ``__acl__`` as a callable. This |
| | | removes the ambiguity between the potential ``AttributeError`` that would |
| | |
| | | - Allow a protocol-relative URL (e.g. ``//example.com/images``) to be passed to |
| | | ``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 |
| | |
| | | ``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 |
| | |
| | | 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 |
| | | |
| | |
| | | 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 |
| | | |
| | | - The ``pserve`` command now takes a ``-v`` (or ``--verbose``) flag and a |
| | | ``-q`` (or ``--quiet``) flag. Output from running ``pserve`` can be |
| | | controlled using these flags. ``-v`` can be specified multiple times to |
| | | increase verbosity. ``-q`` sets verbosity to ``0`` unconditionally. The |
| | | default verbosity level is ``1``. |
| | | |
| | | - The ``alchemy`` scaffold tests now provide better coverage. See |
| | | https://github.com/Pylons/pyramid/pull/1029 |
| | | |
| | | 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. |
| | |
| | | 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 |
| | | |
| | | - The ``alchemy`` scaffold would break when the database was MySQL during |
| | | tables creation. See https://github.com/Pylons/pyramid/pull/1049 |
| | | |
| | | 1.4 (2012-12-18) |
| | | ================ |
| | |
| | | - Jason McKellar, 2013/03/28 |
| | | |
| | | - Luke Cyca, 2013/05/30 |
| | | |
| | | - Laurence Rowe, 2013/04/24 |
| | | |
| | | - Julian P. Glass, 2013/08/10 |
| | | |
| | | - Junaid Ali, 2013/08/10 |
| | | |
| | | - Chris Davies, 2013/08/11 |
| | |
| | | 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 |
| | |
| | | |
| | | - Add ``wild_domain`` argument to AuthTktAuthenticationPolicy, which defaults |
| | | to ``True``. If it is set to ``False``, the feature of the policy which |
| | | sets a cookie with a wilcard domain will be turned off. |
| | | sets a cookie with a wildcard domain will be turned off. |
| | | |
| | | - Add a ``MANIFEST.in`` file to each paster template. See |
| | | https://github.com/Pylons/pyramid/issues#issue/95 |
| | |
| | | cp _static/latex-note.png _build/latex |
| | | @echo |
| | | @echo "Build finished; the LaTeX files are in _build/latex." |
| | | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ |
| | | "run these through (pdf)latex." |
| | | @echo "Run \`make latexpdf' to build a PDF file from them." |
| | | |
| | | latexpdf: |
| | | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex |
| | | @echo "Running LaTeX files through pdflatex..." |
| | | $(MAKE) -C _build/latex all-pdf |
| | | @echo "pdflatex finished; the PDF file is in _build/latex." |
| | | |
| | | changes: |
| | | mkdir -p _build/changes _build/doctrees |
| | |
| | | Subproject commit f59f7bfce5259f50fbb67b9040c03ecb080130b4 |
| | | Subproject commit 8673c4a14f192c15f1949dc9862821e60f31604a |
| | |
| | | will only exist for the lifetime of the actual applications for which they |
| | | are being used. |
| | | |
| | | .. autoclass:: not_ |
| | |
| | | This attribute is often accessed as ``request.registry.introspector`` in |
| | | a typical Pyramid application. |
| | | |
| | | .. method:: notify(*events) |
| | | |
| | | Fire one or more events. All event subscribers to the event(s) |
| | | will be notified. The subscribers will be called synchronously. |
| | | This method is often accessed as ``request.registry.notify`` |
| | | in Pyramid applications to fire custom events. See |
| | | :ref:`custom_events` for more information. |
| | | |
| | | |
| | | .. class:: Introspectable |
| | | |
| | | .. versionadded:: 1.3 |
| | |
| | | .. attribute:: matched_route |
| | | |
| | | If a :term:`route` has matched during this request, this attribute will |
| | | be an obect representing the route matched by the URL pattern |
| | | be an object representing the route matched by the URL pattern |
| | | associated with the route. If a route has not matched during this |
| | | request, the value of this attribute will be ``None``. See |
| | | :ref:`matched_route`. |
| | |
| | | .. attribute:: response_* |
| | | |
| | | In Pyramid 1.0, you could set attributes on a |
| | | :class:`pyramid.request.Request` which influenced the behavor of |
| | | :class:`pyramid.request.Request` which influenced the behavior of |
| | | *rendered* responses (views which use a :term:`renderer` and which |
| | | don't directly return a response). These attributes began with |
| | | ``response_``, such as ``response_headerlist``. If you needed to |
| | |
| | | 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 |
| | |
| | | |
| | | warnings.simplefilter('ignore', DeprecationWarning) |
| | | |
| | | import pkg_resources |
| | | |
| | | # skip raw nodes |
| | | from sphinx.writers.text import TextTranslator |
| | | from sphinx.writers.latex import LaTeXTranslator |
| | |
| | | # other places throughout the built documents. |
| | | # |
| | | # The short X.Y version. |
| | | version = '1.4' |
| | | version = pkg_resources.get_distribution('pyramid').version |
| | | |
| | | # The full version, including alpha/beta/rc tags. |
| | | release = version |
| | |
| | | :orphan: |
| | | |
| | | Foreword |
| | | ======== |
| | | |
| | |
| | | .. _index: |
| | | |
| | | ================================================= |
| | | ========================= |
| | | The Pyramid Web Framework |
| | | ================================================= |
| | | ========================= |
| | | |
| | | :app:`Pyramid` is a small, fast, down-to-earth Python web framework. It |
| | | is developed as part of the `Pylons Project |
| | |
| | | |
| | | .. _html_narrative_documentation: |
| | | |
| | | Narrative documentation |
| | | Narrative Documentation |
| | | ======================= |
| | | |
| | | Narrative documentation in chapter form explaining how to use |
| | |
| | | tutorials/modwsgi/index.rst |
| | | |
| | | API Documentation |
| | | ================== |
| | | ================= |
| | | |
| | | Comprehensive reference material for every public API exposed by :app:`Pyramid`: |
| | | |
| | |
| | | .. toctree:: |
| | | :maxdepth: 1 |
| | | |
| | | whatsnew-1.5 |
| | | whatsnew-1.4 |
| | | whatsnew-1.3 |
| | | whatsnew-1.2 |
| | |
| | | * :ref:`search` |
| | | |
| | | |
| | | .. add glossary, foreword, and latexindex in a hidden toc to avoid warnings |
| | | |
| | | .. toctree:: |
| | | :hidden: |
| | | |
| | | glossary |
| | | foreword.rst |
| | | latexindex.rst |
| | | |
| | |
| | | .. _latexindex: |
| | | |
| | | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| | | The :app:`Pyramid` Web Framework |
| | | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| | | ========================= |
| | | The Pyramid Web Framework |
| | | ========================= |
| | | |
| | | .. frontmatter:: |
| | | |
| | |
| | | |
| | | $ $VENV/bin/prequest -mPOST development.ini / < somefile |
| | | |
| | | Showing All Installed Distributions and their Versions |
| | | ------------------------------------------------------ |
| | | |
| | | .. versionadded:: 1.5 |
| | | |
| | | You can use the ``pdistreport`` command to show the Pyramid version in use, the |
| | | Python version in use, and all installed versions of Python distributions in |
| | | your Python environment:: |
| | | |
| | | $ $VENV/bin/pdistreport |
| | | Pyramid version: 1.5dev |
| | | Platform Linux-3.2.0-51-generic-x86_64-with-debian-wheezy-sid |
| | | Packages: |
| | | authapp 0.0 |
| | | /home/chrism/projects/foo/src/authapp |
| | | beautifulsoup4 4.1.3 |
| | | /home/chrism/projects/foo/lib/python2.7/site-packages/beautifulsoup4-4.1.3-py2.7.egg |
| | | ... more output ... |
| | | |
| | | ``pdistreport`` takes no options. Its output is useful to paste into a |
| | | pastebin when you are having problems and need someone with more familiarity |
| | | with Python packaging and distribution than you have to look at your |
| | | environment. |
| | | |
| | | .. _writing_a_script: |
| | | |
| | | Writing a Script |
| | |
| | | |
| | | from subscribers import mysubscriber |
| | | |
| | | # "config" below is assumed to be an instance of a |
| | | # "config" below is assumed to be an instance of a |
| | | # pyramid.config.Configurator object |
| | | |
| | | config.add_subscriber(mysubscriber, NewRequest) |
| | |
| | | |
| | | @subscriber(NewRequest) |
| | | def mysubscriber(event): |
| | | event.request.foo = 1 |
| | | event.request.foo = 1 |
| | | |
| | | When the :func:`~pyramid.events.subscriber` decorator is used a |
| | | :term:`scan` must be performed against the package containing the |
| | |
| | | :linenos: |
| | | |
| | | def handle_new_request(event): |
| | | print 'request', event.request |
| | | print 'request', event.request |
| | | |
| | | def handle_new_response(event): |
| | | print 'response', event.response |
| | |
| | | :class:`pyramid.interfaces.INewResponse` says it must |
| | | (:class:`pyramid.events.NewResponse` objects also have a ``request``). |
| | | |
| | | .. _custom_events: |
| | | |
| | | Creating Your Own Events |
| | | ------------------------ |
| | | |
| | | In addition to using the events that the Pyramid framework creates, |
| | | you can create your own events for use in your application. This can |
| | | be useful to decouple parts of your application. |
| | | |
| | | For example, suppose your application has to do many things when a new |
| | | document is created. Rather than putting all this logic in the view |
| | | that creates the document, you can create the document in your view |
| | | and then fire a custom event. Subscribers to the custom event can take |
| | | other actions, such as indexing the document, sending email, or |
| | | sending a message to a remote system. |
| | | |
| | | An event is simply an object. There are no required attributes or |
| | | method for your custom events. In general, your events should keep |
| | | track of the information that subscribers will need. Here are some |
| | | example custom event classes: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | class DocCreated(object): |
| | | def __init__(self, doc, request): |
| | | self.doc = doc |
| | | self.request = request |
| | | |
| | | class UserEvent(object): |
| | | def __init__(self, user): |
| | | self.user = user |
| | | |
| | | class UserLoggedIn(UserEvent): |
| | | pass |
| | | |
| | | Some Pyramid applications choose to define custom events classes in an |
| | | ``events`` module. |
| | | |
| | | You can subscribe to custom events in the same way that you subscribe |
| | | to Pyramid events -- either imperatively or with a decorator. You can |
| | | also use custom events with :ref:`subscriber predicates |
| | | <subscriber_predicates>`. Here's an example of subscribing to a custom |
| | | event with a decorator: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.events import subscriber |
| | | from .events import DocCreated |
| | | from .index import index_doc |
| | | |
| | | @subscriber(DocCreated) |
| | | def index_doc(event): |
| | | # index the document using our application's index_doc function |
| | | index_doc(event.doc, event.request) |
| | | |
| | | The above example assumes that the application defines a |
| | | ``DocCreated`` event class and an ``index_doc`` function. |
| | | |
| | | To fire your custom events use the |
| | | :meth:`pyramid.registry.Registry.notify` method, which is most often |
| | | accessed as ``request.registry.notify``. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from .events import DocCreated |
| | | |
| | | def new_doc_view(request): |
| | | doc = MyDoc() |
| | | event = DocCreated(doc, request) |
| | | request.registry.notify(event) |
| | | return {'document': doc} |
| | | |
| | | This example view will notify all subscribers to the custom |
| | | ``DocCreated`` event. |
| | | |
| | | Note that when you fire an event, all subscribers are run |
| | | synchronously so it's generally not a good idea |
| | | to create event handlers that may take a long time to run. Although |
| | | event handlers could be used as a central place to spawn tasks on your |
| | | own message queues. |
| | |
| | | default_locale_name = settings['pyramid.default_locale_name'] |
| | | |
| | | .. index:: |
| | | single: detecting langauges |
| | | single: detecting languages |
| | | |
| | | "Detecting" Available Languages |
| | | ------------------------------- |
| | |
| | | |
| | | The default locale negotiator implementation named |
| | | :class:`~pyramid.i18n.default_locale_negotiator` uses the following |
| | | set of steps to dermine the locale name. |
| | | set of steps to determine the locale name. |
| | | |
| | | - First, the negotiator looks for the ``_LOCALE_`` attribute of the |
| | | request object (possibly set directly by view code or by a listener |
| | |
| | | easily send email, let you use the Jinja2 templating system, let you use |
| | | XML-RPC or JSON-RPC, let you integrate with jQuery Mobile, etc. |
| | | |
| | | Examples: http://docs.pylonsproject.org/en/latest/docs/pyramid.html#pyramid-add-on-documentation |
| | | |
| | | |
| | | Class-based and function-based views |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | question on IRC, on the Pylons-discuss maillist, or on StackOverflow, you're |
| | | likely to get a reasonably prompt response. We don't tolerate "support |
| | | trolls" or other people who seem to get their rocks off by berating fellow |
| | | users in our various offical support channels. We try to keep it well-lit |
| | | users in our various official support channels. We try to keep it well-lit |
| | | and new-user-friendly. |
| | | |
| | | Example: Visit irc\://freenode.net#pyramid (the ``#pyramid`` channel on |
| | |
| | | application. As we saw in :ref:`firstapp_chapter`, ``pserve`` needn't be |
| | | invoked at all to run a :app:`Pyramid` application. The use of ``pserve`` to |
| | | run a :app:`Pyramid` application is purely conventional based on the output |
| | | of its scaffolding. But we strongly recommend using while developing your |
| | | application, because many other convenience introspection commands (such as |
| | | ``pviews``, ``prequest``, ``proutes`` and others) are also implemented in |
| | | terms of configuration availability of this ``.ini`` file format. It also |
| | | configures Pyramid logging and provides the ``--reload`` switch for |
| | | convenient restarting of the server when code changes. |
| | | of its scaffolding. But we strongly recommend using ``pserve`` while |
| | | developing your application, because many other convenience introspection |
| | | commands (such as ``pviews``, ``prequest``, ``proutes`` and others) are also |
| | | implemented in terms of configuration availability of this ``.ini`` file |
| | | format. It also configures Pyramid logging and provides the ``--reload`` |
| | | switch for convenient restarting of the server when code changes. |
| | | |
| | | .. _alternate_wsgi_server: |
| | | |
| | |
| | | |
| | | .. 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``). |
| | |
| | | .. index:: |
| | | single: pyramid_beaker |
| | | single: Beaker |
| | | single: pyramid_redis_sessions |
| | | single: session factory (alternates) |
| | | |
| | | .. _using_alternate_session_factories: |
| | |
| | | Using Alternate Session Factories |
| | | --------------------------------- |
| | | |
| | | At the time of this writing, exactly one alternate session factory |
| | | implementation exists, named ``pyramid_beaker``. This is a session factory |
| | | that uses the `Beaker <http://beaker.groovie.org/>`_ library as a backend. |
| | | Beaker has support for file-based sessions, database based sessions, and |
| | | encrypted cookie-based sessions. See `the pyramid_beaker documentation |
| | | At the time of this writing, exactly two alternate session factories |
| | | exist. |
| | | |
| | | The first is named ``pyramid_redis_sessions``. It can be downloaded from PyPI. |
| | | It uses Redis as a backend. It is the recommended persistent session solution |
| | | at the time of this writing. |
| | | |
| | | The second is named ``pyramid_beaker``. This is a session factory that uses the |
| | | `Beaker <http://beaker.groovie.org/>`_ library as a backend. Beaker has |
| | | support for file-based sessions, database based sessions, and encrypted |
| | | cookie-based sessions. See `the pyramid_beaker documentation |
| | | <http://docs.pylonsproject.org/projects/pyramid_beaker/en/latest/>`_ for more |
| | | information about ``pyramid_beaker``. |
| | | |
| | |
| | | Using A Mako def name Within a Renderer Name |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | Sommetime you'd like to render a ``def`` inside of a Mako template instead of |
| | | Sometimes you'd like to render a ``def`` inside of a Mako template instead of |
| | | the full Mako template. To render a def inside a Mako template, given a |
| | | :term:`Mako` template file named ``foo.mak`` and a def named ``bar``, you can |
| | | configure the template as a :term:`renderer` like so: |
| | |
| | | return resource "C". |
| | | |
| | | #. Traversal ends when a) the entire path is exhausted or b) when any |
| | | resouce raises a :exc:`KeyError` from its ``__getitem__`` or c) when any |
| | | resource raises a :exc:`KeyError` from its ``__getitem__`` or c) when any |
| | | non-final path element traversal does not have a ``__getitem__`` method |
| | | (resulting in a :exc:`AttributeError`) or d) when any path element is |
| | | prefixed with the set of characters ``@@`` (indicating that the characters |
| | |
| | | ------------------------ |
| | | |
| | | It's useful to be able to take a peek under the hood when requests that enter |
| | | your application arent matching your routes as you expect them to. To debug |
| | | your application aren't matching your routes as you expect them to. To debug |
| | | route matching, use the ``PYRAMID_DEBUG_ROUTEMATCH`` environment variable or the |
| | | ``pyramid.debug_routematch`` configuration file setting (set either to ``true``). |
| | | Details of the route matching decision for a particular request to the |
| | |
| | | of the ``REQUEST_METHOD`` of the :term:`WSGI` environment. |
| | | |
| | | ``request_param`` |
| | | This value can be any string or a sequence of strings. A view declaration |
| | | with this argument ensures that the view will only be called when the |
| | | :term:`request` has a key in the ``request.params`` dictionary (an HTTP |
| | | This value can be any string or a sequence of strings. A view declaration |
| | | with this argument ensures that the view will only be called when the |
| | | :term:`request` has a key in the ``request.params`` dictionary (an HTTP |
| | | ``GET`` or ``POST`` variable) that has a name which matches the |
| | | supplied value. |
| | | |
| | |
| | | consideration of keys and values in the ``request.params`` dictionary. |
| | | |
| | | ``match_param`` |
| | | .. versionadded:: 1.2 |
| | | |
| | | This param may be either a single string of the format "key=value" or a |
| | | dict of key/value pairs. |
| | | |
| | |
| | | |
| | | If ``match_param`` is not supplied, the view will be invoked without |
| | | consideration of the keys and values in ``request.matchdict``. |
| | | |
| | | .. versionadded:: 1.2 |
| | | |
| | | ``containment`` |
| | | This value should be a reference to a Python class or :term:`interface` |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | config.add_view('mypackage.views.my_view', route_name='ok', |
| | | config.add_view('mypackage.views.my_view', route_name='ok', |
| | | request_method='POST', permission='read') |
| | | |
| | | All arguments to ``view_config`` may be omitted. For example: |
| | |
| | | form of :term:`declarative configuration`, while |
| | | :meth:`pyramid.config.Configurator.add_view` is a form of :term:`imperative |
| | | configuration`. However, they both do the same thing. |
| | | |
| | | Inverting Predicate Values |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | You can invert the meaning of any predicate value by wrapping it in a call to |
| | | :class:`pyramid.config.not_`. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.config import not_ |
| | | |
| | | config.add_view( |
| | | 'mypackage.views.my_view', |
| | | route_name='ok', |
| | | request_method=not_('POST') |
| | | ) |
| | | |
| | | The above example will ensure that the view is called if the request method |
| | | is *not* ``POST``, at least if no other view is more specific. |
| | | |
| | | This technique of wrapping a predicate value in ``not_`` can be used anywhere |
| | | predicate values are accepted: |
| | | |
| | | - :meth:`pyramid.config.Configurator.add_view` |
| | | |
| | | - :meth:`pyramid.view.view_config` |
| | | |
| | | .. versionadded:: 1.5 |
| | | |
| | | .. index:: |
| | | single: view_config placement |
| | |
| | | config.add_view( |
| | | RESTView, route_name='rest', attr='delete', request_method='DELETE') |
| | | |
| | | To reduce the amount of repetion in the ``config.add_view`` statements, we |
| | | To reduce the amount of repetition in the ``config.add_view`` statements, we |
| | | can move the ``route_name='rest'`` argument to a ``@view_default`` class |
| | | decorator on the RESTView class: |
| | | |
| | |
| | | The term "template" used by the Pyramid documentation used to refer to both |
| | | "paster templates" and "rendered templates" (templates created by a rendering |
| | | engine. i.e. Mako, Chameleon, Jinja, etc.). "Paster templates" will now be |
| | | refered to as "scaffolds", whereas the name for "rendered templates" will |
| | | referred to as "scaffolds", whereas the name for "rendered templates" will |
| | | remain as "templates." |
| | | |
| | | Major Feature Additions |
| | |
| | | shell you use to invoke ``paster serve`` to see these warnings, e.g. on |
| | | UNIX, ``PYTHONWARNINGS=all $VENV/bin/paster serve development.ini``. |
| | | Python 2.5 and 2.6 show deprecation warnings by default, |
| | | so this is unecessary there. |
| | | so this is unnecessary there. |
| | | All deprecation warnings are emitted to the console. |
| | | |
| | | - The :class:`pyramid.view.static` class has been deprecated in favor of the |
New file |
| | |
| | | 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. |
| | | |
| | | - Add ``pdistreport`` script, which prints the Python version in use, the |
| | | Pyramid version in use, and the version number and location of all Python |
| | | distributions currently installed. |
| | | |
| | | - Add the ability to invert the result of any view, route, or subscriber |
| | | predicate value using the ``not_`` class. For example: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.config import not_ |
| | | |
| | | @view_config(route_name='myroute', request_method=not_('POST')) |
| | | def myview(request): ... |
| | | |
| | | The above example will ensure that the view is called if the request method |
| | | is not POST, at least if no other view is more specific. |
| | | |
| | | The :class:`pyramid.config.not_` class can be used against any value that is |
| | | a predicate value passed in any of these contexts: |
| | | |
| | | - :meth:`pyramid.config.Configurator.add_view` |
| | | |
| | | - :meth:`pyramid.config.Configurator.add_route` |
| | | |
| | | - :meth:`pyramid.config.Configurator.add_subscriber` |
| | | |
| | | - :meth:`pyramid.view.view_config` |
| | | |
| | | - :meth:`pyramid.events.subscriber` |
| | | |
| | | - 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. |
| | | |
| | |
| | | ``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`` |
| | | |
| | |
| | | http_only=False, |
| | | wild_domain=True, |
| | | debug=False, |
| | | hashalg=_marker |
| | | hashalg=_marker, |
| | | parent_domain=False, |
| | | ): |
| | | if hashalg is _marker: |
| | | hashalg = 'md5' |
| | |
| | | path=path, |
| | | wild_domain=wild_domain, |
| | | hashalg=hashalg, |
| | | parent_domain=parent_domain, |
| | | ) |
| | | self.callback = callback |
| | | self.debug = debug |
| | |
| | | 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 |
| | |
| | | self.http_only = http_only |
| | | self.path = path |
| | | self.wild_domain = wild_domain |
| | | self.parent_domain = parent_domain |
| | | self.hashalg = hashalg |
| | | |
| | | static_flags = [] |
| | |
| | | |
| | | 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 |
| | |
| | | from pyramid.config.settings import SettingsConfiguratorMixin |
| | | from pyramid.config.testing import TestingConfiguratorMixin |
| | | from pyramid.config.tweens import TweensConfiguratorMixin |
| | | from pyramid.config.util import PredicateList |
| | | from pyramid.config.util import PredicateList, not_ |
| | | from pyramid.config.views import ViewsConfiguratorMixin |
| | | from pyramid.config.zca import ZCAConfiguratorMixin |
| | | |
| | |
| | | |
| | | ConfigurationError = ConfigurationError # pyflakes |
| | | |
| | | not_ = not_ # pyflakes, this is an API |
| | | |
| | | |
| | | class Configurator( |
| | | TestingConfiguratorMixin, |
| | | TweensConfiguratorMixin, |
| | |
| | | config.add_traverser(MyCustomTraverser) |
| | | |
| | | This would cause the Pyramid superdefault traverser to never be used; |
| | | intead all traversal would be done using your ``MyCustomTraverser`` |
| | | instead all traversal would be done using your ``MyCustomTraverser`` |
| | | class, no matter which object was returned by the :term:`root |
| | | factory` of this application. Note that we passed no arguments to |
| | | the ``iface`` keyword parameter. The default value of ``iface``, |
| | |
| | | time. The traverser used can depend on the result of the :term:`root |
| | | factory`. For instance, if your root factory returns more than one |
| | | type of object conditionally, you could claim that an alternate |
| | | traverser adapter should be used agsinst one particular class or |
| | | traverser adapter should be used against one particular class or |
| | | interface returned by that root factory. When the root factory |
| | | returned an object that implemented that class or interface, a custom |
| | | traverser would be used. Otherwise, the default traverser would be |
| | |
| | | if self.val.issubset(rpset): |
| | | return True |
| | | return False |
| | | |
| | |
| | | ``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. |
| | |
| | | val = tuple(sorted(val)) |
| | | return val |
| | | |
| | | class not_(object): |
| | | """ |
| | | |
| | | You can invert the meaning of any predicate value by wrapping it in a call |
| | | to :class:`pyramid.config.not_`. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.config import not_ |
| | | |
| | | config.add_view( |
| | | 'mypackage.views.my_view', |
| | | route_name='ok', |
| | | request_method=not_('POST') |
| | | ) |
| | | |
| | | The above example will ensure that the view is called if the request method |
| | | is *not* ``POST``, at least if no other view is more specific. |
| | | |
| | | This technique of wrapping a predicate value in ``not_`` can be used |
| | | anywhere predicate values are accepted: |
| | | |
| | | - :meth:`pyramid.config.Configurator.add_view` |
| | | |
| | | - :meth:`pyramid.config.Configurator.add_route` |
| | | |
| | | - :meth:`pyramid.config.Configurator.add_subscriber` |
| | | |
| | | - :meth:`pyramid.view.view_config` |
| | | |
| | | - :meth:`pyramid.events.subscriber` |
| | | |
| | | .. versionadded:: 1.5 |
| | | """ |
| | | def __init__(self, value): |
| | | self.value = value |
| | | |
| | | class Notted(object): |
| | | def __init__(self, predicate): |
| | | self.predicate = predicate |
| | | |
| | | def _notted_text(self, val): |
| | | # if the underlying predicate doesnt return a value, it's not really |
| | | # a predicate, it's just something pretending to be a predicate, |
| | | # so dont update the hash |
| | | if val: |
| | | val = '!' + val |
| | | return val |
| | | |
| | | def text(self): |
| | | return self._notted_text(self.predicate.text()) |
| | | |
| | | def phash(self): |
| | | return self._notted_text(self.predicate.phash()) |
| | | |
| | | def __call__(self, context, request): |
| | | result = self.predicate(context, request) |
| | | phash = self.phash() |
| | | if phash: |
| | | result = not result |
| | | return result |
| | | |
| | | # under = after |
| | | # over = before |
| | | |
| | |
| | | if not isinstance(vals, predvalseq): |
| | | vals = (vals,) |
| | | for val in vals: |
| | | pred = predicate_factory(val, config) |
| | | realval = val |
| | | notted = False |
| | | if isinstance(val, not_): |
| | | realval = val.value |
| | | notted = True |
| | | pred = predicate_factory(realval, config) |
| | | if notted: |
| | | pred = Notted(pred) |
| | | hashes = pred.phash() |
| | | if not is_nonstr_iter(hashes): |
| | | hashes = [hashes] |
| | |
| | | by ``queue``. An alternate flash message queue can used by passing |
| | | an optional ``queue``, which must be a string. If |
| | | ``allow_duplicate`` is false, if the ``msg`` already exists in the |
| | | queue, it will not be readded.""" |
| | | queue, it will not be re-added.""" |
| | | |
| | | def pop_flash(queue=''): |
| | | """ Pop a queue from the flash storage. The queue is removed from |
| | |
| | | top-level system names, such as ``request``, ``context``, |
| | | ``renderer_name``, and ``view``. See :ref:`renderer_system_values` for |
| | | the full list. If :term:`renderer globals` have been specified, these |
| | | will also be used to agument the value. |
| | | will also be used to argument the value. |
| | | |
| | | Supply a ``request`` parameter in order to provide the renderer |
| | | with the most correct 'system' values (``request`` and ``context`` |
| | |
| | | The default serializer uses ``json.JSONEncoder``. A different |
| | | serializer can be specified via the ``serializer`` argument. |
| | | Custom serializers should accept the object, a callback |
| | | ``default``, and any extra ``kw`` keyword argments passed during |
| | | ``default``, and any extra ``kw`` keyword arguments passed during |
| | | renderer construction. |
| | | |
| | | .. versionadded:: 1.4 |
| | |
| | | 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) |
| | |
| | | from sqlalchemy import ( |
| | | Column, |
| | | Index, |
| | | Integer, |
| | | Text, |
| | | ) |
| | |
| | | class MyModel(Base): |
| | | __tablename__ = 'models' |
| | | id = Column(Integer, primary_key=True) |
| | | name = Column(Text, unique=True) |
| | | name = Column(Text) |
| | | value = Column(Integer) |
| | | |
| | | def __init__(self, name, value): |
| | | self.name = name |
| | | self.value = value |
| | | |
| | | Index('my_index', MyModel.name, unique=True, mysql_length=255) |
| | |
| | | from .models import DBSession |
| | | |
| | | |
| | | class TestMyView(unittest.TestCase): |
| | | class TestMyViewSuccessCondition(unittest.TestCase): |
| | | def setUp(self): |
| | | self.config = testing.setUp() |
| | | from sqlalchemy import create_engine |
| | |
| | | DBSession.remove() |
| | | testing.tearDown() |
| | | |
| | | def test_it(self): |
| | | def test_passing_view(self): |
| | | from .views import my_view |
| | | request = testing.DummyRequest() |
| | | info = my_view(request) |
| | | self.assertEqual(info['one'].name, 'one') |
| | | self.assertEqual(info['project'], '{{project}}') |
| | | |
| | | |
| | | class TestMyViewFailureCondition(unittest.TestCase): |
| | | def setUp(self): |
| | | self.config = testing.setUp() |
| | | from sqlalchemy import create_engine |
| | | engine = create_engine('sqlite://') |
| | | from .models import ( |
| | | Base, |
| | | MyModel, |
| | | ) |
| | | DBSession.configure(bind=engine) |
| | | |
| | | def tearDown(self): |
| | | DBSession.remove() |
| | | testing.tearDown() |
| | | |
| | | def test_failing_view(self): |
| | | from .views import my_view |
| | | request = testing.DummyRequest() |
| | | info = my_view(request) |
| | | self.assertEqual(info.status_int, 500) |
New file |
| | |
| | | import sys |
| | | import platform |
| | | import pkg_resources |
| | | import optparse |
| | | from operator import itemgetter |
| | | |
| | | def out(*args): # pragma: no cover |
| | | for arg in args: |
| | | sys.stdout.write(arg) |
| | | sys.stdout.write(' ') |
| | | sys.stdout.write('\n') |
| | | |
| | | def main(argv=sys.argv, pkg_resources=pkg_resources, platform=platform.platform, |
| | | out=out): |
| | | # all args except argv are for unit testing purposes only |
| | | description = "Show Python distribution versions and locations in use" |
| | | usage = "usage: %prog" |
| | | parser = optparse.OptionParser(usage, description=description) |
| | | parser.parse_args(argv[1:]) |
| | | packages = [] |
| | | for distribution in pkg_resources.working_set: |
| | | name = distribution.project_name |
| | | packages.append( |
| | | {'version': distribution.version, |
| | | 'lowername': name.lower(), |
| | | 'name': name, |
| | | 'location':distribution.location} |
| | | ) |
| | | packages = sorted(packages, key=itemgetter('lowername')) |
| | | pyramid_version = pkg_resources.get_distribution('pyramid').version |
| | | plat = platform() |
| | | out('Pyramid version:', pyramid_version) |
| | | out('Platform:', plat) |
| | | out('Packages:') |
| | | for package in packages: |
| | | out(' ', package['name'], package['version']) |
| | | out(' ', package['location']) |
| | |
| | | import base64 |
| | | import optparse |
| | | import sys |
| | | import textwrap |
| | |
| | | |
| | | Use "prequest --method=PATCH config.ini /path < data" to do a |
| | | PATCH with the given request body. |
| | | |
| | | Use "prequest --method=OPTIONS config.ini /path" to do an |
| | | OPTIONS request. |
| | | |
| | | Use "prequest --method=PROPFIND config.ini /path" to do a |
| | | PROPFIND request. |
| | | |
| | | If the path is relative (doesn't begin with "/") it is interpreted as |
| | | relative to "/". The path passed to this script should be URL-quoted. |
| | |
| | | parser.add_option( |
| | | '-m', '--method', |
| | | dest='method', |
| | | choices=['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'], |
| | | choices=['GET', 'HEAD', 'POST', 'PUT', 'PATCH','DELETE', |
| | | 'PROPFIND', 'OPTIONS'], |
| | | type='choice', |
| | | help='Request method type', |
| | | help='Request method type (GET, POST, PUT, PATCH, DELETE, ' |
| | | 'PROPFIND, OPTIONS)', |
| | | ) |
| | | parser.add_option( |
| | | '-l', '--login', |
| | | dest='login', |
| | | type='string', |
| | | help='HTTP basic auth username:password pair', |
| | | ) |
| | | |
| | | get_app = staticmethod(get_app) |
| | |
| | | path = url_unquote(path) |
| | | |
| | | headers = {} |
| | | if self.options.login: |
| | | enc = base64.b64encode(self.options.login.encode('ascii')) |
| | | headers['Authorization'] = 'Basic ' + enc.decode('ascii') |
| | | |
| | | if self.options.headers: |
| | | for item in self.options.headers: |
| | | if ':' not in item: |
| | |
| | | You can also include variable assignments like 'http_port=8080' |
| | | and then use %(http_port)s in your config files. |
| | | """ |
| | | verbose = 1 |
| | | default_verbosity = 1 |
| | | |
| | | parser = optparse.OptionParser( |
| | | usage, |
| | |
| | | action='store_true', |
| | | dest='show_status', |
| | | help="Show the status of the (presumably daemonized) server") |
| | | parser.add_option( |
| | | '-v', '--verbose', |
| | | default=default_verbosity, |
| | | dest='verbose', |
| | | action='count', |
| | | help="Set verbose level (default "+str(default_verbosity)+")") |
| | | parser.add_option( |
| | | '-q', '--quiet', |
| | | action='store_const', |
| | | const=0, |
| | | dest='verbose', |
| | | help="Suppress verbose output") |
| | | |
| | | if hasattr(os, 'setuid'): |
| | | # I don't think these are available on Windows |
| | |
| | | |
| | | _scheme_re = re.compile(r'^[a-z][a-z]+:', re.I) |
| | | |
| | | default_verbosity = 1 |
| | | |
| | | _reloader_environ_key = 'PYTHON_RELOADER_SHOULD_RUN' |
| | | _monitor_environ_key = 'PASTE_MONITOR_SHOULD_RUN' |
| | | |
| | | possible_subcommands = ('start', 'stop', 'restart', 'status') |
| | | |
| | | def __init__(self, argv, quiet=False): |
| | | self.quiet = quiet |
| | | self.options, self.args = self.parser.parse_args(argv[1:]) |
| | | if quiet: |
| | | self.options.verbose = 0 |
| | | |
| | | def out(self, msg): # pragma: no cover |
| | | if not self.quiet: |
| | | if self.options.verbose > 0: |
| | | print(msg) |
| | | |
| | | def get_options(self): |
| | |
| | | |
| | | if self.options.reload: |
| | | if os.environ.get(self._reloader_environ_key): |
| | | if self.verbose > 1: |
| | | if self.options.verbose > 1: |
| | | self.out('Running reloading file monitor') |
| | | install_reloader(int(self.options.reload_interval), [app_spec]) |
| | | # if self.requires_config_file: |
| | |
| | | try: |
| | | self.daemonize() |
| | | except DaemonizeException as ex: |
| | | if self.verbose > 0: |
| | | if self.options.verbose > 0: |
| | | self.out(str(ex)) |
| | | return 2 |
| | | |
| | |
| | | app = self.loadapp(app_spec, name=app_name, relative_to=base, |
| | | global_conf=vars) |
| | | |
| | | if self.verbose > 0: |
| | | if self.options.verbose > 0: |
| | | if hasattr(os, 'getpid'): |
| | | msg = 'Starting server in PID %i.' % os.getpid() |
| | | else: |
| | |
| | | try: |
| | | server(app) |
| | | except (SystemExit, KeyboardInterrupt) as e: |
| | | if self.verbose > 1: |
| | | if self.options.verbose > 1: |
| | | raise |
| | | if str(e): |
| | | msg = ' ' + str(e) |
| | |
| | | "Daemon is already running (PID: %s from PID file %s)" |
| | | % (pid, self.options.pid_file)) |
| | | |
| | | if self.verbose > 0: |
| | | if self.options.verbose > 0: |
| | | self.out('Entering daemon mode') |
| | | pid = os.fork() |
| | | if pid: |
| | |
| | | |
| | | def record_pid(self, pid_file): |
| | | pid = os.getpid() |
| | | if self.verbose > 1: |
| | | if self.options.verbose > 1: |
| | | self.out('Writing PID %s to %s' % (pid, pid_file)) |
| | | with open(pid_file, 'w') as f: |
| | | f.write(str(pid)) |
| | | atexit.register(self._remove_pid_file, pid, pid_file, self.verbose) |
| | | atexit.register(self._remove_pid_file, pid, pid_file, self.options.verbose) |
| | | |
| | | def stop_daemon(self): # pragma: no cover |
| | | pid_file = self.options.pid_file or 'pyramid.pid' |
| | |
| | | self.restart_with_monitor(reloader=True) |
| | | |
| | | def restart_with_monitor(self, reloader=False): # pragma: no cover |
| | | if self.verbose > 0: |
| | | if self.options.verbose > 0: |
| | | if reloader: |
| | | self.out('Starting subprocess with file monitor') |
| | | else: |
| | |
| | | proc = None |
| | | except KeyboardInterrupt: |
| | | self.out('^C caught in monitor process') |
| | | if self.verbose > 1: |
| | | if self.options.verbose > 1: |
| | | raise |
| | | return 1 |
| | | finally: |
| | |
| | | # a monitor, any exit code will restart |
| | | if exit_code != 3: |
| | | return exit_code |
| | | if self.verbose > 0: |
| | | if self.options.verbose > 0: |
| | | self.out('%s %s %s' % ('-' * 20, 'Restarting', '-' * 20)) |
| | | |
| | | def change_user_group(self, user, group): # pragma: no cover |
| | |
| | | if not gid: |
| | | gid = entry.pw_gid |
| | | uid = entry.pw_uid |
| | | if self.verbose > 0: |
| | | if self.options.verbose > 0: |
| | | self.out('Changing user to %s:%s (%s:%s)' % ( |
| | | user, group or '(unknown)', uid, gid)) |
| | | if gid: |
| | |
| | | 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) . |
| | |
| | | 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() |
| | |
| | | def test_unknown_predicate(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | self.assertRaises(ConfigurationError, self._callFUT, unknown=1) |
| | | |
| | | def test_notted(self): |
| | | from pyramid.config import not_ |
| | | from pyramid.testing import DummyRequest |
| | | request = DummyRequest() |
| | | _, predicates, _ = self._callFUT( |
| | | xhr='xhr', |
| | | request_method=not_('POST'), |
| | | header=not_('header'), |
| | | ) |
| | | self.assertEqual(predicates[0].text(), 'xhr = True') |
| | | self.assertEqual(predicates[1].text(), |
| | | "!request_method = POST") |
| | | self.assertEqual(predicates[2].text(), '!header header') |
| | | self.assertEqual(predicates[1](None, request), True) |
| | | self.assertEqual(predicates[2](None, request), True) |
| | | |
| | | |
| | | class Test_takes_one_arg(unittest.TestCase): |
| | | def _callFUT(self, view, attr=None, argname=None): |
| | |
| | | foo = Foo() |
| | | self.assertTrue(self._callFUT(foo.method)) |
| | | |
| | | class TestNotted(unittest.TestCase): |
| | | def _makeOne(self, predicate): |
| | | from pyramid.config.util import Notted |
| | | return Notted(predicate) |
| | | |
| | | def test_it_with_phash_val(self): |
| | | pred = DummyPredicate('val') |
| | | inst = self._makeOne(pred) |
| | | self.assertEqual(inst.text(), '!val') |
| | | self.assertEqual(inst.phash(), '!val') |
| | | self.assertEqual(inst(None, None), False) |
| | | |
| | | def test_it_without_phash_val(self): |
| | | pred = DummyPredicate('') |
| | | inst = self._makeOne(pred) |
| | | self.assertEqual(inst.text(), '') |
| | | self.assertEqual(inst.phash(), '') |
| | | self.assertEqual(inst(None, None), True) |
| | | |
| | | class DummyPredicate(object): |
| | | def __init__(self, result): |
| | | self.result = result |
| | | |
| | | def text(self): |
| | | return self.result |
| | | |
| | | phash = text |
| | | |
| | | def __call__(self, context, request): |
| | | return True |
| | | |
| | | class DummyCustomPredicate(object): |
| | | def __init__(self): |
| | | self.__text__ = 'custom predicate' |
| | |
| | | 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) |
| | |
| | | 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) |
New file |
| | |
| | | import unittest |
| | | from pyramid.tests.test_scripts import dummy |
| | | |
| | | class TestPDistReportCommand(unittest.TestCase): |
| | | def _callFUT(self, **kw): |
| | | argv = [] |
| | | from pyramid.scripts.pdistreport import main |
| | | return main(argv, **kw) |
| | | |
| | | def test_no_dists(self): |
| | | def platform(): |
| | | return 'myplatform' |
| | | pkg_resources = DummyPkgResources() |
| | | L = [] |
| | | def out(*args): |
| | | L.extend(args) |
| | | result = self._callFUT(pkg_resources=pkg_resources, platform=platform, |
| | | out=out) |
| | | self.assertEqual(result, None) |
| | | self.assertEqual( |
| | | L, |
| | | ['Pyramid version:', '1', |
| | | 'Platform:', 'myplatform', |
| | | 'Packages:'] |
| | | ) |
| | | |
| | | def test_with_dists(self): |
| | | def platform(): |
| | | return 'myplatform' |
| | | working_set = (DummyDistribution('abc'), DummyDistribution('def')) |
| | | pkg_resources = DummyPkgResources(working_set) |
| | | L = [] |
| | | def out(*args): |
| | | L.extend(args) |
| | | result = self._callFUT(pkg_resources=pkg_resources, platform=platform, |
| | | out=out) |
| | | self.assertEqual(result, None) |
| | | self.assertEqual( |
| | | L, |
| | | ['Pyramid version:', |
| | | '1', |
| | | 'Platform:', |
| | | 'myplatform', |
| | | 'Packages:', |
| | | ' ', |
| | | 'abc', |
| | | '1', |
| | | ' ', |
| | | '/projects/abc', |
| | | ' ', |
| | | 'def', |
| | | '1', |
| | | ' ', |
| | | '/projects/def'] |
| | | ) |
| | | |
| | | class DummyPkgResources(object): |
| | | def __init__(self, working_set=()): |
| | | self.working_set = working_set |
| | | |
| | | def get_distribution(self, name): |
| | | return Version('1') |
| | | |
| | | class Version(object): |
| | | def __init__(self, version): |
| | | self.version = version |
| | | |
| | | class DummyDistribution(object): |
| | | def __init__(self, name): |
| | | self.project_name = name |
| | | self.version = '1' |
| | | self.location = '/projects/%s' % name |
| | | |
| | | |
| | |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_w_basic_auth(self): |
| | | command = self._makeOne( |
| | | ['', '--login=user:password', |
| | | '--header=name:value','development.ini', '/']) |
| | | command.run() |
| | | self.assertEqual(self._environ['HTTP_NAME'], 'value') |
| | | self.assertEqual(self._environ['HTTP_AUTHORIZATION'], |
| | | 'Basic dXNlcjpwYXNzd29yZA==') |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_has_content_type_header_var(self): |
| | | command = self._makeOne( |
| | | ['', '--header=content-type:app/foo','development.ini', '/']) |
| | |
| | | def test_command_method_get(self): |
| | | command = self._makeOne(['', '--method=GET', 'development.ini', '/']) |
| | | command.run() |
| | | self.assertEqual(self._environ['REQUEST_METHOD'], 'GET') |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | |
| | | stdin = NativeIO() |
| | | command.stdin = stdin |
| | | command.run() |
| | | self.assertEqual(self._environ['REQUEST_METHOD'], 'POST') |
| | | self.assertEqual(self._environ['CONTENT_LENGTH'], '-1') |
| | | self.assertEqual(self._environ['wsgi.input'], stdin) |
| | | self.assertEqual(self._path_info, '/') |
| | |
| | | stdin = NativeIO() |
| | | command.stdin = stdin |
| | | command.run() |
| | | self.assertEqual(self._environ['REQUEST_METHOD'], 'PUT') |
| | | self.assertEqual(self._environ['CONTENT_LENGTH'], '-1') |
| | | self.assertEqual(self._environ['wsgi.input'], stdin) |
| | | self.assertEqual(self._path_info, '/') |
| | |
| | | stdin = NativeIO() |
| | | command.stdin = stdin |
| | | command.run() |
| | | self.assertEqual(self._environ['REQUEST_METHOD'], 'PATCH') |
| | | self.assertEqual(self._environ['CONTENT_LENGTH'], '-1') |
| | | self.assertEqual(self._environ['wsgi.input'], stdin) |
| | | self.assertEqual(self._path_info, '/') |
| | |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_method_propfind(self): |
| | | from pyramid.compat import NativeIO |
| | | command = self._makeOne(['', '--method=PROPFIND', 'development.ini', |
| | | '/']) |
| | | stdin = NativeIO() |
| | | command.stdin = stdin |
| | | command.run() |
| | | self.assertEqual(self._environ['REQUEST_METHOD'], 'PROPFIND') |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_method_options(self): |
| | | from pyramid.compat import NativeIO |
| | | command = self._makeOne(['', '--method=OPTIONS', 'development.ini', |
| | | '/']) |
| | | stdin = NativeIO() |
| | | command.stdin = stdin |
| | | command.run() |
| | | self.assertEqual(self._environ['REQUEST_METHOD'], 'OPTIONS') |
| | | self.assertEqual(self._path_info, '/') |
| | | self.assertEqual(self._spec, 'development.ini') |
| | | self.assertEqual(self._app_name, None) |
| | | self.assertEqual(self._out, ['abc']) |
| | | |
| | | def test_command_with_query_string(self): |
| | | command = self._makeOne(['', 'development.ini', '/abc?a=1&b=2&c']) |
| | | command.run() |
| | |
| | | self.pid_file = tempfile.mktemp() |
| | | pid = os.getpid() |
| | | inst = self._makeOne() |
| | | inst.verbose = verbosity |
| | | inst.options.verbose = verbosity |
| | | |
| | | try: |
| | | atexit.register = fake_atexit |
| | |
| | | resulting url of a resource that has a path of ``/baz/bar`` will be |
| | | ``http://foo/baz/bar``. If you want to generate completely relative |
| | | URLs with no leading scheme, host, port, or initial path, you can |
| | | pass ``app_url=''`. Passing ``app_url=''` when the resource path is |
| | | pass ``app_url=''``. Passing ``app_url=''`` when the resource path is |
| | | ``/baz/bar`` will return ``/baz/bar``. |
| | | |
| | | .. versionadded:: 1.3 |
| | |
| | | ] |
| | | |
| | | setup(name='pyramid', |
| | | version='1.4', |
| | | version='1.5dev', |
| | | description=('The Pyramid Web Framework, a ' |
| | | 'Pylons project'), |
| | | long_description=README + '\n\n' + CHANGES, |
| | |
| | | pviews = pyramid.scripts.pviews:main |
| | | ptweens = pyramid.scripts.ptweens:main |
| | | prequest = pyramid.scripts.prequest:main |
| | | pdistreport = pyramid.scripts.pdistreport:main |
| | | [paste.server_runner] |
| | | wsgiref = pyramid.scripts.pserve:wsgiref_server_runner |
| | | cherrypy = pyramid.scripts.pserve:cherrypy_server_runner |