summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-08-14 04:58:34 -0400
committerChris McDonough <chrism@plope.com>2011-08-14 04:58:34 -0400
commitfb90f0166728af40142ed9a31039d26ca3f97c73 (patch)
tree16129d464b3533bfd782f53196dd0052f10c1f57
parentb8a946f9278ead62c38732e7237278adb65303be (diff)
downloadpyramid-fb90f0166728af40142ed9a31039d26ca3f97c73.tar.gz
pyramid-fb90f0166728af40142ed9a31039d26ca3f97c73.tar.bz2
pyramid-fb90f0166728af40142ed9a31039d26ca3f97c73.zip
- The ``route_url``, ``route_path``, ``resource_url``, ``static_url``, and
``current_route_url`` functions in the ``pyramid.url`` package now delegate to a method on the request they've been passed, instead of the other way around. The pyramid.request.Request object now inherits from a mixin named pyramid.url.URLMethodsMixin to make this possible, and all url/path generation logic is embedded in this mixin. - Narrative and API documentation which used the ``route_url``, ``route_path``, ``resource_url``, ``static_url``, and ``current_route_url`` functions in the ``pyramid.url`` package have now been changed to use eponymous methods of the request instead.
-rw-r--r--CHANGES.txt12
-rw-r--r--docs/narr/assets.rst60
-rw-r--r--docs/narr/commandline.rst2
-rw-r--r--docs/narr/hooks.rst19
-rw-r--r--docs/narr/resources.rst92
-rw-r--r--docs/narr/traversal.rst4
-rw-r--r--docs/narr/urldispatch.rst15
-rw-r--r--docs/narr/vhosting.rst4
-rw-r--r--pyramid/config.py57
-rw-r--r--pyramid/interfaces.py13
-rw-r--r--pyramid/request.py139
-rw-r--r--pyramid/testing.py3
-rw-r--r--pyramid/tests/test_testing.py9
-rw-r--r--pyramid/tests/test_url.py426
-rw-r--r--pyramid/url.py830
15 files changed, 838 insertions, 847 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 3432f3954..f420b5299 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -71,6 +71,13 @@ Internal
(it inherits from ``dict``), and it's the value that is passed to templates
as a top-level dictionary.
+- The ``route_url``, ``route_path``, ``resource_url``, ``static_url``, and
+ ``current_route_url`` functions in the ``pyramid.url`` package now delegate
+ to a method on the request they've been passed, instead of the other way
+ around. The pyramid.request.Request object now inherits from a mixin named
+ pyramid.url.URLMethodsMixin to make this possible, and all url/path
+ generation logic is embedded in this mixin.
+
Deprecations
------------
@@ -101,6 +108,11 @@ Backwards Incompatibilities
Documentation
-------------
+- Narrative and API documentation which used the ``route_url``,
+ ``route_path``, ``resource_url``, ``static_url``, and ``current_route_url``
+ functions in the ``pyramid.url`` package have now been changed to use
+ eponymous methods of the request instead.
+
- Added a section entitled "Using a Route Prefix to Compose Applications" to
the "URL Dispatch" narrative documentation chapter.
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index e609a3eab..c8508f1b5 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -165,7 +165,8 @@ Instead of representing a URL prefix, the ``name`` argument of a call to
*URL*. Each of examples we've seen so far have shown usage of the ``name``
argument as a URL prefix. However, when ``name`` is a *URL*, static assets
can be served from an external webserver. In this mode, the ``name`` is used
-as the URL prefix when generating a URL using :func:`pyramid.url.static_url`.
+as the URL prefix when generating a URL using
+:meth:`pyramid.request.Request.static_url`.
For example, :meth:`~pyramid.config.Configurator.add_static_view` may
be fed a ``name`` argument which is ``http://example.com/images``:
@@ -179,13 +180,13 @@ be fed a ``name`` argument which is ``http://example.com/images``:
Because :meth:`~pyramid.config.Configurator.add_static_view` is provided with
a ``name`` argument that is the URL ``http://example.com/images``, subsequent
-calls to :func:`~pyramid.url.static_url` with paths that start with the
-``path`` argument passed to
+calls to :meth:`~pyramid.request.Request.static_url` with paths that start
+with the ``path`` argument passed to
:meth:`~pyramid.config.Configurator.add_static_view` will generate a URL
something like ``http://example.com/images/logo.png``. The external
webserver listening on ``example.com`` must be itself configured to respond
-properly to such a request. The :func:`~pyramid.url.static_url` API is
-discussed in more detail later in this chapter.
+properly to such a request. The :meth:`~pyramid.request.Request.static_url`
+API is discussed in more detail later in this chapter.
.. index::
single: generating static asset urls
@@ -199,9 +200,9 @@ Generating Static Asset URLs
When a :meth:`~pyramid.config.Configurator.add_static_view` method is used to
register a static asset directory, a special helper API named
-:func:`pyramid.url.static_url` can be used to generate the appropriate URL
-for an asset that lives in one of the directories named by the static
-registration ``path`` attribute.
+:meth:`pyramid.request.Request.static_url` can be used to generate the
+appropriate URL for an asset that lives in one of the directories named by
+the static registration ``path`` attribute.
For example, let's assume you create a set of static declarations like so:
@@ -219,18 +220,17 @@ visits a URL which begins with ``/static1``, and the assets in the
visits a URL which begins with ``/static2``.
You needn't generate the URLs to static assets "by hand" in such a
-configuration. Instead, use the :func:`~pyramid.url.static_url` API to
-generate them for you. For example:
+configuration. Instead, use the :meth:`~pyramid.request.Request.static_url`
+API to generate them for you. For example:
.. code-block:: python
:linenos:
- from pyramid.url import static_url
from pyramid.chameleon_zpt import render_template_to_response
def my_view(request):
- css_url = static_url('mypackage:assets/1/foo.css', request)
- js_url = static_url('mypackage:assets/2/foo.js', request)
+ css_url = request.static_url('mypackage:assets/1/foo.css')
+ js_url = request.static_url('mypackage:assets/2/foo.js')
return render_template_to_response('templates/my_template.pt',
css_url = css_url,
js_url = js_url)
@@ -240,17 +240,18 @@ If the request "application URL" of the running system is
``http://example.com/static1/foo.css``. The ``js_url`` generated
above would be ``http://example.com/static2/foo.js``.
-One benefit of using the :func:`~pyramid.url.static_url` function rather than
-constructing static URLs "by hand" is that if you need to change the ``name``
-of a static URL declaration, the generated URLs will continue to resolve
-properly after the rename.
+One benefit of using the :meth:`~pyramid.request.Request.static_url` function
+rather than constructing static URLs "by hand" is that if you need to change
+the ``name`` of a static URL declaration, the generated URLs will continue to
+resolve properly after the rename.
-URLs may also be generated by :func:`~pyramid.url.static_url` to static assets
-that live *outside* the :app:`Pyramid` application. This will happen when
-the :meth:`~pyramid.config.Configurator.add_static_view` API associated with
-the path fed to :func:`~pyramid.url.static_url` is a *URL* instead of a view
-name. For example, the ``name`` argument may be ``http://example.com`` while
-the the ``path`` given may be ``mypackage:images``:
+URLs may also be generated by :meth:`~pyramid.request.Request.static_url` to
+static assets that live *outside* the :app:`Pyramid` application. This will
+happen when the :meth:`~pyramid.config.Configurator.add_static_view` API
+associated with the path fed to :meth:`~pyramid.request.Request.static_url`
+is a *URL* instead of a view name. For example, the ``name`` argument may be
+``http://example.com`` while the the ``path`` given may be
+``mypackage:images``:
.. code-block:: python
:linenos:
@@ -265,14 +266,14 @@ assets which begin with ``mypackage:images`` will be prefixed with
.. code-block:: python
:linenos:
- static_url('mypackage:images/logo.png', request)
+ request.static_url('mypackage:images/logo.png')
# -> http://example.com/images/logo.png
-Using :func:`~pyramid.url.static_url` in conjunction with a
+Using :meth:`~pyramid.request.Request.static_url` in conjunction with a
:meth:`~pyramid.configuration.Configurator.add_static_view` makes it possible
to put static media on a separate webserver during production (if the
-``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is a
-URL), while keeping static media package-internal and served by the
+``name`` argument to :meth:`~pyramid.config.Configurator.add_static_view` is
+a URL), while keeping static media package-internal and served by the
development webserver during development (if the ``name`` argument to
:meth:`~pyramid.config.Configurator.add_static_view` is a URL prefix). To
create such a circumstance, we suggest using the
@@ -298,8 +299,9 @@ dispatch`, you may want static assets to only be available as a fallback if
no previous route matches. Alternately, you might like to serve a particular
static asset manually, because its download requires authentication.
-Note that you cannot use the :func:`~pyramid.url.static_url` API to generate
-URLs against assets made accessible by registering a custom static view.
+Note that you cannot use the :meth:`~pyramid.request.Request.static_url` API
+to generate URLs against assets made accessible by registering a custom
+static view.
Root-Relative Custom Static View (URL Dispatch Only)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst
index 97004d2b8..1c9d0b15c 100644
--- a/docs/narr/commandline.rst
+++ b/docs/narr/commandline.rst
@@ -532,7 +532,7 @@ Now you can readily use Pyramid's APIs for generating URLs:
.. code-block:: python
- route_url('verify', env['request'], code='1337')
+ env['request'].route_url('verify', code='1337')
# will return 'https://example.com/prefix/verify/1337'
Cleanup
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 50758f327..df5339c8a 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -468,17 +468,18 @@ when the application :term:`root factory` returned an instance of the
.. _changing_resource_url:
-Changing How :mod:`pyramid.url.resource_url` Generates a URL
-------------------------------------------------------------
+Changing How :meth:`pyramid.request.Request.resource_url` Generates a URL
+-------------------------------------------------------------------------
When you add a traverser as described in :ref:`changing_the_traverser`, it's
-often convenient to continue to use the :func:`pyramid.url.resource_url` API.
-However, since the way traversal is done will have been modified, the URLs it
-generates by default may be incorrect.
+often convenient to continue to use the
+:meth:`pyramid.request.Request.resource_url` API. However, since the way
+traversal is done will have been modified, the URLs it generates by default
+may be incorrect.
If you've added a traverser, you can change how
-:func:`~pyramid.url.resource_url` generates a URL for a specific type of
-resource by adding a registerAdapter call for
+:meth:`~pyramid.request.Request.resource_url` generates a URL for a specific
+type of resource by adding a registerAdapter call for
:class:`pyramid.interfaces.IContextURL` to your application:
.. code-block:: python
@@ -493,8 +494,8 @@ resource by adding a registerAdapter call for
IContextURL)
In the above example, the ``myapp.traversal.URLGenerator`` class will be used
-to provide services to :func:`~pyramid.url.resource_url` any time the
-:term:`context` passed to ``resource_url`` is of class
+to provide services to :meth:`~pyramid.request.Request.resource_url` any time
+the :term:`context` passed to ``resource_url`` is of class
``myapp.resources.MyRoot``. The second argument in the ``(MyRoot,
Interface)`` tuple represents the type of interface that must be possessed by
the :term:`request` (in this case, any interface, represented by
diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst
index 0e0d00020..9335906a0 100644
--- a/docs/narr/resources.rst
+++ b/docs/narr/resources.rst
@@ -45,8 +45,8 @@ Also:
- A resource is exposed to :term:`view` code as the :term:`context` of a
view.
-- Various helpful :app:`Pyramid` API methods expect a resource as an
- argument (e.g. :func:`~pyramid.url.resource_url` and others).
+- Various helpful :app:`Pyramid` API methods expect a resource as an argument
+ (e.g. :meth:`~pyramid.request.Request.resource_url` and others).
.. index::
single: resource tree
@@ -160,14 +160,14 @@ resource in the resource tree, you will eventually come to the root resource,
just like if you keep executing the ``cd ..`` filesystem command, eventually
you will reach the filesystem root directory.
-.. warning:: If your root resource has a ``__name__`` argument
- that is not ``None`` or the empty string, URLs returned by the
- :func:`~pyramid.url.resource_url` function and paths generated by
- the :func:`~pyramid.traversal.resource_path` and
- :func:`~pyramid.traversal.resource_path_tuple` APIs will be
- generated improperly. The value of ``__name__`` will be prepended
- to every path and URL generated (as opposed to a single leading
- slash or empty tuple element).
+.. warning:: If your root resource has a ``__name__`` argument that is not
+ ``None`` or the empty string, URLs returned by the
+ :func:`~pyramid.request.Request.resource_url` function and paths generated
+ by the :func:`~pyramid.traversal.resource_path` and
+ :func:`~pyramid.traversal.resource_path_tuple` APIs will be generated
+ improperly. The value of ``__name__`` will be prepended to every path and
+ URL generated (as opposed to a single leading slash or empty tuple
+ element).
.. sidebar:: Using :mod:`pyramid_traversalwrapper`
@@ -192,7 +192,8 @@ you will reach the filesystem root directory.
Applications which use tree-walking :app:`Pyramid` APIs require
location-aware resources. These APIs include (but are not limited to)
-:func:`~pyramid.url.resource_url`, :func:`~pyramid.traversal.find_resource`,
+:meth:`~pyramid.request.Request.resource_url`,
+:func:`~pyramid.traversal.find_resource`,
:func:`~pyramid.traversal.find_root`,
:func:`~pyramid.traversal.find_interface`,
:func:`~pyramid.traversal.resource_path`,
@@ -215,23 +216,23 @@ Generating The URL Of A Resource
--------------------------------
If your resources are :term:`location` aware, you can use the
-:func:`pyramid.url.resource_url` API to generate a URL for the resource.
-This URL will use the resource's position in the parent tree to create a
-resource path, and it will prefix the path with the current application URL
-to form a fully-qualified URL with the scheme, host, port, and path. You can
-also pass extra arguments to :func:`~pyramid.url.resource_url` to influence
-the generated URL.
+:meth:`pyramid.request.Request.resource_url` API to generate a URL for the
+resource. This URL will use the resource's position in the parent tree to
+create a resource path, and it will prefix the path with the current
+application URL to form a fully-qualified URL with the scheme, host, port,
+and path. You can also pass extra arguments to
+:meth:`~pyramid.request.Request.resource_url` to influence the generated URL.
-The simplest call to :func:`~pyramid.url.resource_url` looks like this:
+The simplest call to :meth:`~pyramid.request.Request.resource_url` looks like
+this:
.. code-block:: python
:linenos:
- from pyramid.url import resource_url
- url = resource_url(resource, request)
+ url = request.resource_url(resource, request)
-The ``request`` passed to ``resource_url`` in the above example is an
-instance of a :app:`Pyramid` :term:`request` object.
+The ``request`` in the above example is an instance of a :app:`Pyramid`
+:term:`request` object.
If the resource referred to as ``resource`` in the above example was the root
resource, and the host that was used to contact the server was
@@ -240,51 +241,46 @@ However, if the resource was a child of the root resource named ``a``, the
generated URL would be ``http://example.com/a/``.
A slash is appended to all resource URLs when
-:func:`~pyramid.url.resource_url` is used to generate them in this simple
-manner, because resources are "places" in the hierarchy, and URLs are meant
-to be clicked on to be visited. Relative URLs that you include on HTML pages
-rendered as the result of the default view of a resource are more
+:meth:`~pyramid.request.Request.resource_url` is used to generate them in
+this simple manner, because resources are "places" in the hierarchy, and URLs
+are meant to be clicked on to be visited. Relative URLs that you include on
+HTML pages rendered as the result of the default view of a resource are more
apt to be relative to these resources than relative to their parent.
-You can also pass extra elements to :func:`~pyramid.url.resource_url`:
+You can also pass extra elements to
+:meth:`~pyramid.request.Request.resource_url`:
.. code-block:: python
:linenos:
- from pyramid.url import resource_url
- url = resource_url(resource, request, 'foo', 'bar')
+ url = request.resource_url(resource, 'foo', 'bar')
If the resource referred to as ``resource`` in the above example was the root
resource, and the host that was used to contact the server was
``example.com``, the URL generated would be ``http://example.com/foo/bar``.
Any number of extra elements can be passed to
-:func:`~pyramid.url.resource_url` as extra positional arguments. When extra
-elements are passed, they are appended to the resource's URL. A slash is not
-appended to the final segment when elements are passed.
+:meth:`~pyramid.request.Request.resource_url` as extra positional arguments.
+When extra elements are passed, they are appended to the resource's URL. A
+slash is not appended to the final segment when elements are passed.
You can also pass a query string:
.. code-block:: python
:linenos:
- from pyramid.url import resource_url
- url = resource_url(resource, request, query={'a':'1'})
+ url = request.resource_url(resource, query={'a':'1'})
If the resource referred to as ``resource`` in the above example was the root
resource, and the host that was used to contact the server was
``example.com``, the URL generated would be ``http://example.com/?a=1``.
When a :term:`virtual root` is active, the URL generated by
-:func:`~pyramid.url.resource_url` for a resource may be "shorter" than its
-physical tree path. See :ref:`virtual_root_support` for more information
-about virtually rooting a resource.
-
-The shortcut method of the :term:`request` named
-:meth:`pyramid.request.Request.resource_url` can be used instead of
-:func:`~pyramid.url.resource_url` to generate a resource URL.
+:meth:`~pyramid.request.Request.resource_url` for a resource may be "shorter"
+than its physical tree path. See :ref:`virtual_root_support` for more
+information about virtually rooting a resource.
For more information about generating resource URLs, see the documentation
-for :func:`pyramid.url.resource_url`.
+for :meth:`pyramid.request.Request.resource_url`.
.. index::
pair: resource URL generation; overriding
@@ -295,14 +291,14 @@ Overriding Resource URL Generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If a resource object implements a ``__resource_url__`` method, this method
-will be called when :func:`~pyramid.url.resource_url` is called to generate a
-URL for the resource, overriding the default URL returned for the resource by
-:func:`~pyramid.url.resource_url`.
+will be called when :meth:`~pyramid.request.Request.resource_url` is called
+to generate a URL for the resource, overriding the default URL returned for
+the resource by :meth:`~pyramid.request.Request.resource_url`.
The ``__resource_url__`` hook is passed two arguments: ``request`` and
``info``. ``request`` is the :term:`request` object passed to
-:func:`~pyramid.url.resource_url`. ``info`` is a dictionary with two
-keys:
+:meth:`~pyramid.request.Request.resource_url`. ``info`` is a dictionary with
+two keys:
``physical_path``
The "physical path" computed for the resource, as defined by
@@ -334,7 +330,7 @@ or port number of the generated URL.
Note that the URL generated by ``__resource_url__`` should be fully
qualified, should end in a slash, and should not contain any query string or
anchor elements (only path elements) to work best with
-:func:`~pyramid.url.resource_url`.
+:meth:`~pyramid.request.Request.resource_url`.
.. index::
single: resource path generation
diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst
index aa36b4455..ef875c8f0 100644
--- a/docs/narr/traversal.rst
+++ b/docs/narr/traversal.rst
@@ -565,6 +565,6 @@ See the :ref:`view_config_chapter` chapter for detailed information about
The :mod:`pyramid.traversal` module contains API functions that deal with
traversal, such as traversal invocation from within application code.
-The :func:`pyramid.url.resource_url` function generates a URL when given a
-resource retrieved from a resource tree.
+The :meth:`pyramid.request.Request.resource_url` method generates a URL when
+given a resource retrieved from a resource tree.
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index c0197743b..00d36cc76 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -765,20 +765,19 @@ Or provide the literal string ``/`` as the pattern:
Generating Route URLs
---------------------
-Use the :func:`pyramid.url.route_url` function to generate URLs based on
-route patterns. For example, if you've configured a route with the ``name``
-"foo" and the ``pattern`` "{a}/{b}/{c}", you might do this.
+Use the :meth:`pyramid.request.Request.route_url` method to generate URLs
+based on route patterns. For example, if you've configured a route with the
+``name`` "foo" and the ``pattern`` "{a}/{b}/{c}", you might do this.
.. ignore-next-block
.. code-block:: python
:linenos:
- from pyramid.url import route_url
- url = route_url('foo', request, a='1', b='2', c='3')
+ url = request.route_url('foo', a='1', b='2', c='3')
This would return something like the string ``http://example.com/1/2/3`` (at
least if the current protocol and hostname implied ``http://example.com``).
-See the :func:`~pyramid.url.route_url` API documentation for more
+See the :meth:`~pyramid.request.Request.route_url` API documentation for more
information.
.. index::
@@ -1122,8 +1121,8 @@ In the above configuration, the ``show_users`` route will have an effective
route pattern of ``/users/show``, instead of ``/show`` because the
``route_prefix`` argument will be prepended to the pattern. The route will
then only match if the URL path is ``/users/show``, and when the
-:func:`pyramid.url.route_url` function is called with the route name
-``show_users``, it will generate a URL with that same path.
+:meth:`pyramid.request.Request.route_url` function is called with the route
+name ``show_users``, it will generate a URL with that same path.
Route prefixes are recursive, so if a callable executed via an include itself
turns around and includes another callable, the second-level route prefix
diff --git a/docs/narr/vhosting.rst b/docs/narr/vhosting.rst
index 5679cc2e2..ddbf1fb4d 100644
--- a/docs/narr/vhosting.rst
+++ b/docs/narr/vhosting.rst
@@ -101,8 +101,8 @@ the WSGI environ named ``HTTP_X_VHM_ROOT`` with a value that is the absolute
pathname to the resource object in the resource tree that should behave as
the "root" resource. As a result, the traversal machinery will respect this
value during traversal (prepending it to the PATH_INFO before traversal
-starts), and the :func:`pyramid.url.resource_url` API will generate the
-"correct" virtually-rooted URLs.
+starts), and the :meth:`pyramid.request.Request.resource_url` API will
+generate the "correct" virtually-rooted URLs.
An example of an Apache ``mod_proxy`` configuration that will host the
``/cms`` subobject as ``http://www.example.com/`` using this facility
diff --git a/pyramid/config.py b/pyramid/config.py
index c68648a5f..fc00e2ffa 100644
--- a/pyramid/config.py
+++ b/pyramid/config.py
@@ -1881,13 +1881,13 @@ class Configurator(object):
pregenerator
This option should be a callable object that implements the
- :class:`pyramid.interfaces.IRoutePregenerator`
- interface. A :term:`pregenerator` is a callable called by
- the :mod:`pyramid.url.route_url` function to augment or
- replace the arguments it is passed when generating a URL
- for the route. This is a feature not often used directly
- by applications, it is meant to be hooked by frameworks
- that use :app:`Pyramid` as a base.
+ :class:`pyramid.interfaces.IRoutePregenerator` interface. A
+ :term:`pregenerator` is a callable called by the
+ :meth:`pyramid.request.Request.route_url` function to augment or
+ replace the arguments it is passed when generating a URL for the
+ route. This is a feature not often used directly by applications,
+ it is meant to be hooked by frameworks that use :app:`Pyramid` as
+ a base.
use_global_views
@@ -2637,50 +2637,51 @@ class Configurator(object):
*Usage*
The ``add_static_view`` function is typically used in conjunction
- with the :func:`pyramid.url.static_url` function.
+ with the :meth:`pyramid.request.Request.static_url` method.
``add_static_view`` adds a view which renders a static asset when
- some URL is visited; :func:`pyramid.url.static_url` generates a URL
- to that asset.
+ some URL is visited; :meth:`pyramid.request.Request.static_url`
+ generates a URL to that asset.
The ``name`` argument to ``add_static_view`` is usually a :term:`view
- name`. When this is the case, the :func:`pyramid.url.static_url` API
- will generate a URL which points to a Pyramid view, which will serve
- up a set of assets that live in the package itself. For example:
+ name`. When this is the case, the
+ :meth:`pyramid.request.Request.static_url` API will generate a URL
+ which points to a Pyramid view, which will serve up a set of assets
+ that live in the package itself. For example:
.. code-block:: python
add_static_view('images', 'mypackage:images/')
Code that registers such a view can generate URLs to the view via
- :func:`pyramid.url.static_url`:
+ :meth:`pyramid.request.Request.static_url`:
.. code-block:: python
- static_url('mypackage:images/logo.png', request)
+ request.static_url('mypackage:images/logo.png')
When ``add_static_view`` is called with a ``name`` argument that
represents a URL prefix, as it is above, subsequent calls to
- :func:`pyramid.url.static_url` with paths that start with the
- ``path`` argument passed to ``add_static_view`` will generate a URL
- something like ``http://<Pyramid app URL>/images/logo.png``, which
- will cause the ``logo.png`` file in the ``images`` subdirectory of
- the ``mypackage`` package to be served.
+ :meth:`pyramid.request.Request.static_url` with paths that start with
+ the ``path`` argument passed to ``add_static_view`` will generate a
+ URL something like ``http://<Pyramid app URL>/images/logo.png``,
+ which will cause the ``logo.png`` file in the ``images`` subdirectory
+ of the ``mypackage`` package to be served.
``add_static_view`` can alternately be used with a ``name`` argument
which is a *URL*, causing static assets to be served from an external
webserver. This happens when the ``name`` argument is a fully
qualified URL (e.g. starts with ``http://`` or similar). In this
mode, the ``name`` is used as the prefix of the full URL when
- generating a URL using :func:`pyramid.url.static_url`. For example,
- if ``add_static_view`` is called like so:
+ generating a URL using :meth:`pyramid.request.Request.static_url`.
+ For example, if ``add_static_view`` is called like so:
.. code-block:: python
add_static_view('http://example.com/images', 'mypackage:images/')
- Subsequently, the URLs generated by :func:`pyramid.url.static_url`
- for that static view will be prefixed with
- ``http://example.com/images``:
+ Subsequently, the URLs generated by
+ :meth:`pyramid.request.Request.static_url` for that static view will
+ be prefixed with ``http://example.com/images``:
.. code-block:: python
@@ -2688,9 +2689,9 @@ class Configurator(object):
When ``add_static_view`` is called with a ``name`` argument that is
the URL ``http://example.com/images``, subsequent calls to
- :func:`pyramid.url.static_url` with paths that start with the
- ``path`` argument passed to ``add_static_view`` will generate a URL
- something like ``http://example.com/logo.png``. The external
+ :meth:`pyramid.request.Request.static_url` with paths that start with
+ the ``path`` argument passed to ``add_static_view`` will generate a
+ URL something like ``http://example.com/logo.png``. The external
webserver listening on ``example.com`` must be itself configured to
respond properly to such a request.
diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py
index 61462bb5e..4055db08a 100644
--- a/pyramid/interfaces.py
+++ b/pyramid/interfaces.py
@@ -634,12 +634,13 @@ ILogger = IDebugLogger # b/c
class IRoutePregenerator(Interface):
def __call__(request, elements, kw):
- """ A pregenerator is a function associated by a developer
- with a :term:`route`. The pregenerator for a route is called
- by :func:`pyramid.url.route_url` in order to adjust the set
- of arguments passed to it by the user for special purposes,
- such as Pylons 'subdomain' support. It will influence the URL
- returned by ``route_url``.
+
+ """ A pregenerator is a function associated by a developer with a
+ :term:`route`. The pregenerator for a route is called by
+ :meth:`pyramid.request.Request.route_url` in order to adjust the set
+ of arguments passed to it by the user for special purposes, such as
+ Pylons 'subdomain' support. It will influence the URL returned by
+ ``route_url``.
A pregenerator should return a two-tuple of ``(elements, kw)``
after examining the originals passed to this function, which
diff --git a/pyramid/request.py b/pyramid/request.py
index 2a654d218..640b0bd97 100644
--- a/pyramid/request.py
+++ b/pyramid/request.py
@@ -14,10 +14,7 @@ from pyramid.compat import json
from pyramid.exceptions import ConfigurationError
from pyramid.decorator import reify
from pyramid.response import Response
-from pyramid.url import resource_url
-from pyramid.url import route_url
-from pyramid.url import static_url
-from pyramid.url import route_path
+from pyramid.url import URLMethodsMixin
class TemplateContext(object):
pass
@@ -179,7 +176,7 @@ class DeprecatedRequestMethods(object):
rr_dep % ('cache_for', 'cache_expires'))
-class Request(BaseRequest, DeprecatedRequestMethods):
+class Request(BaseRequest, DeprecatedRequestMethods, URLMethodsMixin):
"""
A subclass of the :term:`WebOb` Request class. An instance of
this class is created by the :term:`router` and is provided to a
@@ -331,137 +328,6 @@ class Request(BaseRequest, DeprecatedRequestMethods):
'(see the Sessions chapter of the Pyramid documentation)')
return factory(self)
- def route_url(self, route_name, *elements, **kw):
- """ Return the URL for the route named ``route_name``, using
- ``*elements`` and ``**kw`` as modifiers.
-
- This is a convenience method. The result of calling
- :meth:`pyramid.request.Request.route_url` is the same as calling
- :func:`pyramid.url.route_url` with an explicit ``request``
- parameter.
-
- The :meth:`pyramid.request.Request.route_url` method calls the
- :func:`pyramid.url.route_url` function using the Request object as
- the ``request`` argument. The ``route_name``, ``*elements`` and
- ``*kw`` arguments passed to :meth:`pyramid.request.Request.route_url`
- are passed through to :func:`pyramid.url.route_url` unchanged and its
- result is returned.
-
- This call to :meth:`pyramid.request.Request.route_url`::
-
- request.route_url('route_name')
-
- Is completely equivalent to calling :func:`pyramid.url.route_url`
- like this::
-
- from pyramid.url import route_url
- route_url('route_name', request)
- """
- return route_url(route_name, self, *elements, **kw)
-
- def resource_url(self, resource, *elements, **kw):
- """ Return the URL for the :term:`resource` object named ``resource``,
- using ``*elements`` and ``**kw`` as modifiers.
-
- This is a convenience method. The result of calling
- :meth:`pyramid.request.Request.resource_url` is the same as calling
- :func:`pyramid.url.resource_url` with an explicit ``request`` parameter.
-
- The :meth:`pyramid.request.Request.resource_url` method calls the
- :func:`pyramid.url.resource_url` function using the Request object as
- the ``request`` argument. The ``resource``, ``*elements`` and ``*kw``
- arguments passed to :meth:`pyramid.request.Request.resource_url` are
- passed through to :func:`pyramid.url.resource_url` unchanged and its
- result is returned.
-
- This call to :meth:`pyramid.request.Request.resource_url`::
-
- request.resource_url(myresource)
-
- Is completely equivalent to calling :func:`pyramid.url.resource_url`
- like this::
-
- from pyramid.url import resource_url
- resource_url(resource, request)
-
- .. note:: For backwards compatibility purposes, this method can also
- be called as :meth:`pyramid.request.Request.model_url`.
- """
- return resource_url(resource, self, *elements, **kw)
-
- model_url = resource_url # b/w compat forever
-
- def static_url(self, path, **kw):
- """
- Generates a fully qualified URL for a static :term:`asset`. The
- asset must live within a location defined via the
- :meth:`pyramid.config.Configurator.add_static_view`
- :term:`configuration declaration` directive (see
- :ref:`static_assets_section`).
-
- This is a convenience method. The result of calling
- :meth:`pyramid.request.Request.static_url` is the same as calling
- :func:`pyramid.url.static_url` with an explicit ``request`` parameter.
-
- The :meth:`pyramid.request.Request.static_url` method calls the
- :func:`pyramid.url.static_url` function using the Request object as
- the ``request`` argument. The ``*kw`` arguments passed to
- :meth:`pyramid.request.Request.static_url` are passed through to
- :func:`pyramid.url.static_url` unchanged and its result is returned.
-
- This call to :meth:`pyramid.request.Request.static_url`::
-
- request.static_url('mypackage:static/foo.css')
-
- Is completely equivalent to calling :func:`pyramid.url.static_url`
- like this::
-
- from pyramid.url import static_url
- static_url('mypackage:static/foo.css', request)
-
- See :func:`pyramid.url.static_url` for more information
-
- """
- return static_url(path, self, **kw)
-
- def route_path(self, route_name, *elements, **kw):
- """Generates a path (aka a 'relative URL', a URL minus the host,
- scheme, and port) for a named :app:`Pyramid`
- :term:`route configuration`.
-
- This is a convenience method. The result of calling
- :meth:`pyramid.request.Request.route_path` is the same as calling
- :func:`pyramid.url.route_path` with an explicit ``request``
- parameter.
-
- This method accepts the same arguments as
- :meth:`pyramid.request.Request.route_url` and performs the same duty.
- It just omits the host, port, and scheme information in the return
- value; only the script name, path, query parameters, and anchor data
- are present in the returned string.
-
- The :meth:`pyramid.request.Request.route_path` method calls the
- :func:`pyramid.url.route_path` function using the Request object as
- the ``request`` argument. The ``*elements`` and ``*kw`` arguments
- passed to :meth:`pyramid.request.Request.route_path` are passed
- through to :func:`pyramid.url.route_path` unchanged and its result is
- returned.
-
- This call to :meth:`pyramid.request.Request.route_path`::
-
- request.route_path('foobar')
-
- Is completely equivalent to calling :func:`pyramid.url.route_path`
- like this::
-
- from pyramid.url import route_path
- route_path('foobar', request)
-
- See :func:`pyramid.url.route_path` for more information
-
- """
- return route_path(route_name, self, *elements, **kw)
-
@reify
def response(self):
"""This attribute is actually a "reified" property which returns an
@@ -495,7 +361,6 @@ class Request(BaseRequest, DeprecatedRequestMethods):
def json_body(self):
return json.loads(self.body, encoding=self.charset)
-
def route_request_iface(name, bases=()):
# zope.interface treats the __name__ as the __doc__ and changes __name__
# to None for interfaces that contain spaces if you do not pass a
diff --git a/pyramid/testing.py b/pyramid/testing.py
index 5b0f37f45..7e5bb50d1 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -26,6 +26,7 @@ from pyramid.security import has_permission
from pyramid.threadlocal import get_current_registry
from pyramid.threadlocal import manager
from pyramid.request import DeprecatedRequestMethods
+from pyramid.url import URLMethodsMixin
_marker = object()
@@ -620,7 +621,7 @@ class DummySession(dict):
def get_csrf_token(self):
return self.get('_csrft_', None)
-class DummyRequest(DeprecatedRequestMethods):
+class DummyRequest(DeprecatedRequestMethods, URLMethodsMixin):
""" A DummyRequest object (incompletely) imitates a :term:`request` object.
The ``params``, ``environ``, ``headers``, ``path``, and
diff --git a/pyramid/tests/test_testing.py b/pyramid/tests/test_testing.py
index 159a88ebd..41a4788ec 100644
--- a/pyramid/tests/test_testing.py
+++ b/pyramid/tests/test_testing.py
@@ -251,15 +251,16 @@ class Test_registerSubscriber(TestBase):
class Test_registerRoute(TestBase):
def test_registerRoute(self):
- from pyramid.url import route_url
+ from pyramid.request import Request
from pyramid.interfaces import IRoutesMapper
from pyramid.testing import registerRoute
registerRoute(':pagename', 'home', DummyFactory)
mapper = self.registry.getUtility(IRoutesMapper)
self.assertEqual(len(mapper.routelist), 1)
- request = DummyRequest()
- self.assertEqual(route_url('home', request, pagename='abc'),
- 'http://example.com/abc')
+ request = Request.blank('/')
+ request.registry = self.registry
+ self.assertEqual(request.route_url('home', pagename='abc'),
+ 'http://localhost/abc')
class Test_registerSettings(TestBase):
def test_registerSettings(self):
diff --git a/pyramid/tests/test_url.py b/pyramid/tests/test_url.py
index cb8326114..652e5a8d2 100644
--- a/pyramid/tests/test_url.py
+++ b/pyramid/tests/test_url.py
@@ -3,16 +3,20 @@ import unittest
from pyramid.testing import setUp
from pyramid.testing import tearDown
-class ResourceURLTests(unittest.TestCase):
+class TestURLMethodsMixin(unittest.TestCase):
def setUp(self):
- setUp()
+ self.config = setUp()
def tearDown(self):
tearDown()
- def _callFUT(self, resource, request, *elements, **kw):
- from pyramid.url import resource_url
- return resource_url(resource, request, *elements, **kw)
+ def _makeOne(self):
+ from pyramid.url import URLMethodsMixin
+ class Request(URLMethodsMixin):
+ application_url = 'http://example.com:5432'
+ request = Request()
+ request.registry = self.config.registry
+ return request
def _registerContextURL(self, reg):
from pyramid.interfaces import IContextURL
@@ -25,247 +29,233 @@ class ResourceURLTests(unittest.TestCase):
reg.registerAdapter(DummyContextURL, (Interface, Interface),
IContextURL)
- def test_root_default(self):
- request = _makeRequest()
+ def test_resource_url_root_default(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
root = DummyContext()
- result = self._callFUT(root, request)
+ result = request.resource_url(root)
self.assertEqual(result, 'http://example.com/context/')
- def test_extra_args(self):
- request = _makeRequest()
+ def test_resource_url_extra_args(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- result = self._callFUT(context, request, 'this/theotherthing', 'that')
+ result = request.resource_url(context, 'this/theotherthing', 'that')
self.assertEqual(
result,
'http://example.com/context/this%2Ftheotherthing/that')
- def test_unicode_in_element_names(self):
- request = _makeRequest()
+ def test_resource_url_unicode_in_element_names(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
uc = unicode('La Pe\xc3\xb1a', 'utf-8')
context = DummyContext()
- result = self._callFUT(context, request, uc)
+ result = request.resource_url(context, uc)
self.assertEqual(result,
'http://example.com/context/La%20Pe%C3%B1a')
- def test_at_sign_in_element_names(self):
- request = _makeRequest()
+ def test_resource_url_at_sign_in_element_names(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- result = self._callFUT(context, request, '@@myview')
+ result = request.resource_url(context, '@@myview')
self.assertEqual(result,
'http://example.com/context/@@myview')
- def test_element_names_url_quoted(self):
- request = _makeRequest()
+ def test_resource_url_element_names_url_quoted(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- result = self._callFUT(context, request, 'a b c')
+ result = request.resource_url(context, 'a b c')
self.assertEqual(result, 'http://example.com/context/a%20b%20c')
- def test_with_query_dict(self):
- request = _makeRequest()
+ def test_resource_url_with_query_dict(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
uc = unicode('La Pe\xc3\xb1a', 'utf-8')
- result = self._callFUT(context, request, 'a', query={'a':uc})
+ result = request.resource_url(context, 'a', query={'a':uc})
self.assertEqual(result,
'http://example.com/context/a?a=La+Pe%C3%B1a')
- def test_with_query_seq(self):
- request = _makeRequest()
+ def test_resource_url_with_query_seq(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
uc = unicode('La Pe\xc3\xb1a', 'utf-8')
- result = self._callFUT(context, request, 'a', query=[('a', 'hi there'),
+ result = request.resource_url(context, 'a', query=[('a', 'hi there'),
('b', uc)])
self.assertEqual(result,
'http://example.com/context/a?a=hi+there&b=La+Pe%C3%B1a')
- def test_anchor_is_after_root_when_no_elements(self):
- request = _makeRequest()
+ def test_resource_url_anchor_is_after_root_when_no_elements(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- result = self._callFUT(context, request, anchor='a')
+ result = request.resource_url(context, anchor='a')
self.assertEqual(result,
'http://example.com/context/#a')
- def test_anchor_is_after_elements_when_no_qs(self):
- request = _makeRequest()
+ def test_resource_url_anchor_is_after_elements_when_no_qs(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- result = self._callFUT(context, request, 'a', anchor='b')
+ result = request.resource_url(context, 'a', anchor='b')
self.assertEqual(result,
'http://example.com/context/a#b')
- def test_anchor_is_after_qs_when_qs_is_present(self):
- request = _makeRequest()
+ def test_resource_url_anchor_is_after_qs_when_qs_is_present(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- result = self._callFUT(context, request, 'a',
- query={'b':'c'}, anchor='d')
+ result = request.resource_url(context, 'a',
+ query={'b':'c'}, anchor='d')
self.assertEqual(result,
'http://example.com/context/a?b=c#d')
- def test_anchor_is_encoded_utf8_if_unicode(self):
- request = _makeRequest()
+ def test_resource_url_anchor_is_encoded_utf8_if_unicode(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
uc = unicode('La Pe\xc3\xb1a', 'utf-8')
- result = self._callFUT(context, request, anchor=uc)
+ result = request.resource_url(context, anchor=uc)
self.assertEqual(result,
'http://example.com/context/#La Pe\xc3\xb1a')
- def test_anchor_is_not_urlencoded(self):
- request = _makeRequest()
+ def test_resource_url_anchor_is_not_urlencoded(self):
+ request = self._makeOne()
self._registerContextURL(request.registry)
context = DummyContext()
- result = self._callFUT(context, request, anchor=' /#')
+ result = request.resource_url(context, anchor=' /#')
self.assertEqual(result,
'http://example.com/context/# /#')
- def test_no_IContextURL_registered(self):
+ def test_resource_url_no_IContextURL_registered(self):
# falls back to TraversalContextURL
root = DummyContext()
root.__name__ = ''
root.__parent__ = None
- request = _makeRequest()
+ request = self._makeOne()
request.environ = {}
- result = self._callFUT(root, request)
+ result = request.resource_url(root)
self.assertEqual(result, 'http://example.com:5432/')
- def test_no_registry_on_request(self):
- from pyramid.threadlocal import get_current_registry
- reg = get_current_registry()
- request = DummyRequest()
- self._registerContextURL(reg)
+ def test_resource_url_no_registry_on_request(self):
+ request = self._makeOne()
+ self._registerContextURL(request.registry)
+ del request.registry
root = DummyContext()
- result = self._callFUT(root, request)
+ result = request.resource_url(root)
self.assertEqual(result, 'http://example.com/context/')
-class TestRouteUrl(unittest.TestCase):
- def setUp(self):
- self.config = setUp()
-
- def tearDown(self):
- tearDown()
-
- def _callFUT(self, *arg, **kw):
- from pyramid.url import route_url
- return route_url(*arg, **kw)
-
- def test_with_elements(self):
+ def test_route_url_with_elements(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, 'extra1', 'extra2')
+ result = request.route_url('flub', 'extra1', 'extra2')
self.assertEqual(result,
'http://example.com:5432/1/2/3/extra1/extra2')
- def test_with_elements_path_endswith_slash(self):
+ def test_route_url_with_elements_path_endswith_slash(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3/'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, 'extra1', 'extra2')
+ result = request.route_url('flub', 'extra1', 'extra2')
self.assertEqual(result,
'http://example.com:5432/1/2/3/extra1/extra2')
- def test_no_elements(self):
+ def test_route_url_no_elements(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, a=1, b=2, c=3, _query={'a':1},
- _anchor=u"foo")
+ result = request.route_url('flub', a=1, b=2, c=3, _query={'a':1},
+ _anchor=u"foo")
self.assertEqual(result,
'http://example.com:5432/1/2/3?a=1#foo')
- def test_with_anchor_string(self):
+ def test_route_url_with_anchor_string(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, _anchor="La Pe\xc3\xb1a")
+ result = request.route_url('flub', _anchor="La Pe\xc3\xb1a")
self.assertEqual(result,
'http://example.com:5432/1/2/3#La Pe\xc3\xb1a')
- def test_with_anchor_unicode(self):
+ def test_route_url_with_anchor_unicode(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
anchor = unicode('La Pe\xc3\xb1a', 'utf-8')
- result = self._callFUT('flub', request, _anchor=anchor)
+ result = request.route_url('flub', _anchor=anchor)
self.assertEqual(result,
'http://example.com:5432/1/2/3#La Pe\xc3\xb1a')
- def test_with_query(self):
+ def test_route_url_with_query(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, _query={'q':'1'})
+ result = request.route_url('flub', _query={'q':'1'})
self.assertEqual(result,
'http://example.com:5432/1/2/3?q=1')
- def test_with_app_url(self):
+ def test_route_url_with_app_url(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, _app_url='http://example2.com')
+ result = request.route_url('flub', _app_url='http://example2.com')
self.assertEqual(result,
'http://example2.com/1/2/3')
- def test_it_generation_error(self):
+ def test_route_url_generation_error(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(raise_exc=KeyError)
request.registry.registerUtility(mapper, IRoutesMapper)
mapper.raise_exc = KeyError
- self.assertRaises(KeyError, self._callFUT, 'flub', request, a=1)
+ self.assertRaises(KeyError, request.route_url, 'flub', request, a=1)
- def test_generate_doesnt_receive_query_or_anchor(self):
+ def test_route_url_generate_doesnt_receive_query_or_anchor(self):
from pyramid.interfaces import IRoutesMapper
+ request = self._makeOne()
route = DummyRoute(result='')
mapper = DummyRoutesMapper(route=route)
- from zope.component import getSiteManager
- sm = getSiteManager()
- sm.registerUtility(mapper, IRoutesMapper)
- request = DummyRequest()
- result = self._callFUT('flub', request, _query=dict(name='some_name'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = request.route_url('flub', _query=dict(name='some_name'))
self.assertEqual(route.kw, {}) # shouldnt have anchor/query
self.assertEqual(result, 'http://example.com:5432?name=some_name')
- def test_with_pregenerator(self):
+ def test_route_url_with_pregenerator(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
route = DummyRoute(result='/1/2/3')
def pregenerator(request, elements, kw):
return ('a',), {'_app_url':'http://example2.com'}
route.pregenerator = pregenerator
mapper = DummyRoutesMapper(route=route)
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request)
+ result = request.route_url('flub')
self.assertEqual(result, 'http://example2.com/1/2/3/a')
self.assertEqual(route.kw, {}) # shouldnt have anchor/query
- def test_with_anchor_app_url_elements_and_query(self):
+ def test_route_url_with_anchor_app_url_elements_and_query(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute(result='/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, 'element1',
- _app_url='http://example2.com',
- _anchor='anchor', _query={'q':'1'})
+ result = request.route_url('flub', 'element1',
+ _app_url='http://example2.com',
+ _anchor='anchor', _query={'q':'1'})
self.assertEqual(result,
'http://example2.com/1/2/3/element1?q=1#anchor')
- def test_integration_with_real_request(self):
+ def test_route_url_integration_with_real_request(self):
# to try to replicate https://github.com/Pylons/pyramid/issues/213
from pyramid.interfaces import IRoutesMapper
from pyramid.request import Request
@@ -273,147 +263,213 @@ class TestRouteUrl(unittest.TestCase):
request.registry = self.config.registry
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, 'extra1', 'extra2')
+ result = request.route_url('flub', 'extra1', 'extra2')
self.assertEqual(result,
'http://localhost/1/2/3/extra1/extra2')
-class TestCurrentRouteUrl(unittest.TestCase):
- def setUp(self):
- setUp()
-
- def tearDown(self):
- tearDown()
-
- def _callFUT(self, *arg, **kw):
- from pyramid.url import current_route_url
- return current_route_url(*arg, **kw)
-
- def test_current_request_has_no_route(self):
- request = _makeRequest()
- self.assertRaises(ValueError, self._callFUT, request)
+ def test_current_route_url_current_request_has_no_route(self):
+ request = self._makeOne()
+ self.assertRaises(ValueError, request.current_route_url)
- def test_with_elements_query_and_anchor(self):
+ def test_current_route_url_with_elements_query_and_anchor(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
route = DummyRoute('/1/2/3')
mapper = DummyRoutesMapper(route=route)
request.matched_route = route
request.matchdict = {}
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT(request, 'extra1', 'extra2', _query={'a':1},
- _anchor=u"foo")
+ result = request.current_route_url('extra1', 'extra2', _query={'a':1},
+ _anchor=u"foo")
self.assertEqual(result,
'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo')
- def test_with__route_name(self):
+ def test_current_route_url_with_route_name(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
route = DummyRoute('/1/2/3')
mapper = DummyRoutesMapper(route=route)
request.matched_route = route
request.matchdict = {}
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT(request, 'extra1', 'extra2', _query={'a':1},
- _anchor=u"foo", _route_name='bar')
+ result = request.current_route_url('extra1', 'extra2', _query={'a':1},
+ _anchor=u"foo", _route_name='bar')
self.assertEqual(result,
'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo')
-class TestRoutePath(unittest.TestCase):
- def setUp(self):
- setUp()
-
- def tearDown(self):
- tearDown()
-
- def _callFUT(self, *arg, **kw):
- from pyramid.url import route_path
- return route_path(*arg, **kw)
-
- def test_with_elements(self):
+ def test_route_path_with_elements(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, 'extra1', 'extra2',
- a=1, b=2, c=3, _query={'a':1},
- _anchor=u"foo")
+ request.script_name = ''
+ result = request.route_path('flub', 'extra1', 'extra2',
+ a=1, b=2, c=3, _query={'a':1},
+ _anchor=u"foo")
self.assertEqual(result, '/1/2/3/extra1/extra2?a=1#foo')
- def test_with_script_name(self):
+ def test_route_path_with_script_name(self):
from pyramid.interfaces import IRoutesMapper
- request = _makeRequest()
+ request = self._makeOne()
request.script_name = '/foo'
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, 'extra1', 'extra2',
- a=1, b=2, c=3, _query={'a':1},
- _anchor=u"foo")
+ result = request.route_path('flub', 'extra1', 'extra2',
+ a=1, b=2, c=3, _query={'a':1},
+ _anchor=u"foo")
self.assertEqual(result, '/foo/1/2/3/extra1/extra2?a=1#foo')
-class TestStaticUrl(unittest.TestCase):
- def setUp(self):
- setUp()
-
- def tearDown(self):
- tearDown()
-
- def _callFUT(self, *arg, **kw):
- from pyramid.url import static_url
- return static_url(*arg, **kw)
-
- def test_staticurlinfo_notfound(self):
- request = _makeRequest()
- self.assertRaises(ValueError, self._callFUT, 'static/foo.css', request)
+ def test_static_url_staticurlinfo_notfound(self):
+ request = self._makeOne()
+ self.assertRaises(ValueError, request.static_url, 'static/foo.css')
- def test_abspath(self):
- request = _makeRequest()
- self.assertRaises(ValueError, self._callFUT, '/static/foo.css', request)
+ def test_static_url_abspath(self):
+ request = self._makeOne()
+ self.assertRaises(ValueError, request.static_url, '/static/foo.css')
- def test_found_rel(self):
+ def test_static_url_found_rel(self):
from pyramid.interfaces import IStaticURLInfo
- request = _makeRequest()
+ request = self._makeOne()
info = DummyStaticURLInfo('abc')
request.registry.registerUtility(info, IStaticURLInfo)
- result = self._callFUT('static/foo.css', request)
+ result = request.static_url('static/foo.css')
self.assertEqual(result, 'abc')
self.assertEqual(info.args,
('pyramid.tests:static/foo.css', request, {}) )
- def test_found_abs(self):
+ def test_static_url_abs(self):
from pyramid.interfaces import IStaticURLInfo
- request = _makeRequest()
+ request = self._makeOne()
info = DummyStaticURLInfo('abc')
request.registry.registerUtility(info, IStaticURLInfo)
- result = self._callFUT('pyramid.tests:static/foo.css', request)
+ result = request.static_url('pyramid.tests:static/foo.css')
self.assertEqual(result, 'abc')
self.assertEqual(info.args,
('pyramid.tests:static/foo.css', request, {}) )
- def test_found_abs_no_registry_on_request(self):
- from pyramid.threadlocal import get_current_registry
+ def test_static_url_found_abs_no_registry_on_request(self):
from pyramid.interfaces import IStaticURLInfo
- request = DummyRequest()
- registry = get_current_registry()
+ request = self._makeOne()
+ registry = request.registry
info = DummyStaticURLInfo('abc')
registry.registerUtility(info, IStaticURLInfo)
- result = self._callFUT('pyramid.tests:static/foo.css', request)
+ del request.registry
+ result = request.static_url('pyramid.tests:static/foo.css')
self.assertEqual(result, 'abc')
self.assertEqual(info.args,
('pyramid.tests:static/foo.css', request, {}) )
+class Test_route_url(unittest.TestCase):
+ def _callFUT(self, route_name, request, *elements, **kw):
+ from pyramid.url import route_url
+ return route_url(route_name, request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def route_url(self, route_name, *elements, **kw):
+ self.route_name = route_name
+ self.elements = elements
+ self.kw = kw
+ return 'route url'
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, 'a', _app_url='')
+ self.assertEqual(result, 'route url')
+ self.assertEqual(request.route_name, 'abc')
+ self.assertEqual(request.elements, ('a',))
+ self.assertEqual(request.kw, {'_app_url':''})
+
+class Test_route_path(unittest.TestCase):
+ def _callFUT(self, route_name, request, *elements, **kw):
+ from pyramid.url import route_path
+ return route_path(route_name, request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def route_path(self, route_name, *elements, **kw):
+ self.route_name = route_name
+ self.elements = elements
+ self.kw = kw
+ return 'route path'
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, 'a', _app_url='')
+ self.assertEqual(result, 'route path')
+ self.assertEqual(request.route_name, 'abc')
+ self.assertEqual(request.elements, ('a',))
+ self.assertEqual(request.kw, {'_app_url':''})
+
+class Test_resource_url(unittest.TestCase):
+ def _callFUT(self, resource, request, *elements, **kw):
+ from pyramid.url import resource_url
+ return resource_url(resource, request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def resource_url(self, resource, *elements, **kw):
+ self.resource = resource
+ self.elements = elements
+ self.kw = kw
+ return 'resource url'
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, 'a', _app_url='')
+ self.assertEqual(result, 'resource url')
+ self.assertEqual(request.resource, 'abc')
+ self.assertEqual(request.elements, ('a',))
+ self.assertEqual(request.kw, {'_app_url':''})
+
+class Test_static_url(unittest.TestCase):
+ def _callFUT(self, path, request, **kw):
+ from pyramid.url import static_url
+ return static_url(path, request, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def static_url(self, path, **kw):
+ self.path = path
+ self.kw = kw
+ return 'static url'
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT('abc', request, _app_url='')
+ self.assertEqual(result, 'static url')
+ self.assertEqual(request.path, 'abc')
+ self.assertEqual(request.kw, {'_app_url':''})
+
+class Test_current_route_url(unittest.TestCase):
+ def _callFUT(self, request, *elements, **kw):
+ from pyramid.url import current_route_url
+ return current_route_url(request, *elements, **kw)
+
+ def _makeRequest(self):
+ class Request(object):
+ def current_route_url(self, *elements, **kw):
+ self.elements = elements
+ self.kw = kw
+ return 'current route url'
+ return Request()
+
+ def test_it(self):
+ request = self._makeRequest()
+ result = self._callFUT(request, 'abc', _app_url='')
+ self.assertEqual(result, 'current route url')
+ self.assertEqual(request.elements, ('abc',))
+ self.assertEqual(request.kw, {'_app_url':''})
+
class DummyContext(object):
def __init__(self, next=None):
self.next = next
-class DummyRequest:
- application_url = 'http://example.com:5432' # app_url never ends with slash
- script_name = ''
- def __init__(self, environ=None):
- if environ is None:
- environ = {}
- self.environ = environ
-
class DummyRoutesMapper:
raise_exc = None
def __init__(self, route=None, raise_exc=False):
@@ -432,12 +488,6 @@ class DummyRoute:
self.kw = kw
return self.result
-def _makeRequest(environ=None):
- from pyramid.registry import Registry
- request = DummyRequest(environ)
- request.registry = Registry()
- return request
-
class DummyStaticURLInfo:
def __init__(self, result):
self.result = result
diff --git a/pyramid/url.py b/pyramid/url.py
index 548d5e9d9..254cd6d0e 100644
--- a/pyramid/url.py
+++ b/pyramid/url.py
@@ -16,419 +16,481 @@ from pyramid.threadlocal import get_current_registry
from pyramid.traversal import TraversalContextURL
from pyramid.traversal import quote_path_segment
+class URLMethodsMixin(object):
+ """ Request methods mixin for BaseRequest having to do with URL
+ generation """
+
+ def route_url(self, route_name, *elements, **kw):
+ """Generates a fully qualified URL for a named :app:`Pyramid`
+ :term:`route configuration`.
+
+ Use the route's ``name`` as the first positional argument.
+ Additional positional arguments (``*elements``) are appended to the
+ URL as path segments after it is generated.
+
+ Use keyword arguments to supply values which match any dynamic
+ path elements in the route definition. Raises a :exc:`KeyError`
+ exception if the URL cannot be generated for any reason (not
+ enough arguments, for example).
+
+ For example, if you've defined a route named "foobar" with the path
+ ``{foo}/{bar}/*traverse``::
+
+ request.route_url('foobar',
+ foo='1') => <KeyError exception>
+ request.route_url('foobar',
+ foo='1',
+ bar='2') => <KeyError exception>
+ request.route_url('foobar',
+ foo='1',
+ bar='2',
+ traverse=('a','b')) => http://e.com/1/2/a/b
+ request.route_url('foobar',
+ foo='1',
+ bar='2',
+ traverse='/a/b') => http://e.com/1/2/a/b
+
+ Values replacing ``:segment`` arguments can be passed as strings
+ or Unicode objects. They will be encoded to UTF-8 and URL-quoted
+ before being placed into the generated URL.
+
+ Values replacing ``*remainder`` arguments can be passed as strings
+ *or* tuples of Unicode/string values. If a tuple is passed as a
+ ``*remainder`` replacement value, its values are URL-quoted and
+ encoded to UTF-8. The resulting strings are joined with slashes
+ and rendered into the URL. If a string is passed as a
+ ``*remainder`` replacement value, it is tacked on to the URL
+ untouched.
+
+ If a keyword argument ``_query`` is present, it will be used to
+ compose a query string that will be tacked on to the end of the
+ URL. The value of ``_query`` must be a sequence of two-tuples
+ *or* a data structure with an ``.items()`` method that returns a
+ sequence of two-tuples (presumably a dictionary). This data
+ structure will be turned into a query string per the documentation
+ of :func:`pyramid.encode.urlencode` function. After the query
+ data is turned into a query string, a leading ``?`` is prepended,
+ and the resulting string is appended to the generated URL.
+
+ .. note:: Python data structures that are passed as ``_query``
+ which are sequences or dictionaries are turned into a
+ string under the same rules as when run through
+ :func:`urllib.urlencode` with the ``doseq`` argument
+ equal to ``True``. This means that sequences can be
+ passed as values, and a k=v pair will be placed into the
+ query string for each value.
+
+ If a keyword argument ``_anchor`` is present, its string
+ representation will be used as a named anchor in the generated URL
+ (e.g. if ``_anchor`` is passed as ``foo`` and the route URL is
+ ``http://example.com/route/url``, the resulting generated URL will
+ be ``http://example.com/route/url#foo``).
+
+ .. note:: If ``_anchor`` is passed as a string, it should be UTF-8
+ encoded. If ``_anchor`` is passed as a Unicode object, it
+ will be converted to UTF-8 before being appended to the
+ URL. The anchor value is not quoted in any way before
+ being appended to the generated URL.
+
+ If both ``_anchor`` and ``_query`` are specified, the anchor
+ element will always follow the query element,
+ e.g. ``http://example.com?foo=1#bar``.
+
+ If a keyword ``_app_url`` is present, it will be used as the
+ protocol/hostname/port/leading path prefix of the generated URL.
+ For example, using an ``_app_url`` of
+ ``http://example.com:8080/foo`` would cause the URL
+ ``http://example.com:8080/foo/fleeb/flub`` to be returned from
+ this function if the expansion of the route pattern associated
+ with the ``route_name`` expanded to ``/fleeb/flub``. If
+ ``_app_url`` is not specified, the result of
+ ``request.application_url`` will be used as the prefix (the
+ default).
+
+ This function raises a :exc:`KeyError` if the URL cannot be
+ generated due to missing replacement names. Extra replacement
+ names are ignored.
+
+ If the route object which matches the ``route_name`` argument has
+ a :term:`pregenerator`, the ``*elements`` and ``**kw`` arguments
+ arguments passed to this function might be augmented or changed.
+ """
+ try:
+ reg = self.registry
+ except AttributeError:
+ reg = get_current_registry() # b/c
+ mapper = reg.getUtility(IRoutesMapper)
+ route = mapper.get_route(route_name)
+
+ if route is None:
+ raise KeyError('No such route named %s' % route_name)
+
+ if route.pregenerator is not None:
+ elements, kw = route.pregenerator(self, elements, kw)
+
+ anchor = ''
+ qs = ''
+ app_url = None
+
+ if '_query' in kw:
+ qs = '?' + urlencode(kw.pop('_query'), doseq=True)
+
+ if '_anchor' in kw:
+ anchor = kw.pop('_anchor')
+ if isinstance(anchor, unicode):
+ anchor = anchor.encode('utf-8')
+ anchor = '#' + anchor
+
+ if '_app_url' in kw:
+ app_url = kw.pop('_app_url')
+
+ path = route.generate(kw) # raises KeyError if generate fails
+
+ if elements:
+ suffix = _join_elements(elements)
+ if not path.endswith('/'):
+ suffix = '/' + suffix
+ else:
+ suffix = ''
+
+ if app_url is None:
+ # we only defer lookup of application_url until here because
+ # it's somewhat expensive; we won't need to do it if we've
+ # been passed _app_url
+ app_url = self.application_url
+
+ return app_url + path + suffix + qs + anchor
+
+ def route_path(self, route_name, *elements, **kw):
+ """
+ Generates a path (aka a 'relative URL', a URL minus the host, scheme,
+ and port) for a named :app:`Pyramid` :term:`route configuration`.
+
+ This function accepts the same argument as
+ :meth:`pyramid.request.Request.route_url` and performs the same duty.
+ It just omits the host, port, and scheme information in the return
+ value; only the script_name, path, query parameters, and anchor data
+ are present in the returned string.
+
+ For example, if you've defined a route named 'foobar' with the path
+ ``/{foo}/{bar}``, this call to ``route_path``::
+
+ request.route_path('foobar', foo='1', bar='2')
+
+ Will return the string ``/1/2``.
+
+ .. note:: Calling ``request.route_path('route')`` is the same as
+ calling ``request.route_url('route',
+ _app_url=request.script_name)``.
+ :meth:`pyramid.request.Request.route_path` is, in fact,
+ implemented in terms of `:meth:`pyramid.request.Request.route_url`
+ in just this way. As a result, any ``_app_url`` passed within the
+ ``**kw`` values to ``route_path`` will be ignored.
+ """
+ kw['_app_url'] = self.script_name
+ return self.route_url(route_name, *elements, **kw)
+
+ def resource_url(self, resource, *elements, **kw):
+ """
+
+ Generate a string representing the absolute URL of the
+ :term:`resource` object based on the ``wsgi.url_scheme``,
+ ``HTTP_HOST`` or ``SERVER_NAME`` in the request, plus any
+ ``SCRIPT_NAME``. The overall result of this method is always a
+ UTF-8 encoded string (never Unicode).
+
+ Examples::
+
+ request.resource_url(resource) =>
+
+ http://example.com/
+
+ request.resource_url(resource, 'a.html') =>
+
+ http://example.com/a.html
+
+ request.resource_url(resource, 'a.html', query={'q':'1'}) =>
+
+ http://example.com/a.html?q=1
+
+ request.resource_url(resource, 'a.html', anchor='abc') =>
+
+ http://example.com/a.html#abc
+
+ Any positional arguments passed in as ``elements`` must be strings
+ Unicode objects, or integer objects. These will be joined by slashes
+ and appended to the generated resource URL. Each of the elements
+ passed in is URL-quoted before being appended; if any element is
+ Unicode, it will converted to a UTF-8 bytestring before being
+ URL-quoted. If any element is an integer, it will be converted to its
+ string representation before being URL-quoted.
+
+ .. warning:: if no ``elements`` arguments are specified, the resource
+ URL will end with a trailing slash. If any
+ ``elements`` are used, the generated URL will *not*
+ end in trailing a slash.
+
+ If a keyword argument ``query`` is present, it will be used to
+ compose a query string that will be tacked on to the end of the URL.
+ The value of ``query`` must be a sequence of two-tuples *or* a data
+ structure with an ``.items()`` method that returns a sequence of
+ two-tuples (presumably a dictionary). This data structure will be
+ turned into a query string per the documentation of
+ ``pyramid.url.urlencode`` function. After the query data is turned
+ into a query string, a leading ``?`` is prepended, and the resulting
+ string is appended to the generated URL.
+
+ .. note:: Python data structures that are passed as ``query`` which
+ are sequences or dictionaries are turned into a string
+ under the same rules as when run through
+ :func:`urllib.urlencode` with the ``doseq`` argument equal
+ to ``True``. This means that sequences can be passed as
+ values, and a k=v pair will be placed into the query string
+ for each value.
+
+ If a keyword argument ``anchor`` is present, its string
+ representation will be used as a named anchor in the generated URL
+ (e.g. if ``anchor`` is passed as ``foo`` and the resource URL is
+ ``http://example.com/resource/url``, the resulting generated URL will
+ be ``http://example.com/resource/url#foo``).
+
+ .. note:: If ``anchor`` is passed as a string, it should be UTF-8
+ encoded. If ``anchor`` is passed as a Unicode object, it
+ will be converted to UTF-8 before being appended to the
+ URL. The anchor value is not quoted in any way before
+ being appended to the generated URL.
+
+ If both ``anchor`` and ``query`` are specified, the anchor element
+ will always follow the query element,
+ e.g. ``http://example.com?foo=1#bar``.
+
+ If the ``resource`` passed in has a ``__resource_url__`` method, it
+ will be used to generate the URL (scheme, host, port, path) that for
+ the base resource which is operated upon by this function. See also
+ :ref:`overriding_resource_url_generation`.
+
+ .. note:: If the :term:`resource` used is the result of a
+ :term:`traversal`, it must be :term:`location`-aware. The
+ resource can also be the context of a :term:`URL dispatch`;
+ contexts found this way do not need to be location-aware.
+
+ .. note:: If a 'virtual root path' is present in the request
+ environment (the value of the WSGI environ key
+ ``HTTP_X_VHM_ROOT``), and the resource was obtained via
+ :term:`traversal`, the URL path will not include the
+ virtual root prefix (it will be stripped off the left hand
+ side of the generated URL).
+
+ .. note:: For backwards compatibility purposes, this method is also
+ aliased as the ``model_url`` method of request.
+ """
+ try:
+ reg = self.registry
+ except AttributeError:
+ reg = get_current_registry() # b/c
+
+ context_url = reg.queryMultiAdapter((resource, self), IContextURL)
+ if context_url is None:
+ context_url = TraversalContextURL(resource, self)
+ resource_url = context_url()
+
+ qs = ''
+ anchor = ''
+
+ if 'query' in kw:
+ qs = '?' + urlencode(kw['query'], doseq=True)
+
+ if 'anchor' in kw:
+ anchor = kw['anchor']
+ if isinstance(anchor, unicode):
+ anchor = anchor.encode('utf-8')
+ anchor = '#' + anchor
+
+ if elements:
+ suffix = _join_elements(elements)
+ else:
+ suffix = ''
+
+ return resource_url + suffix + qs + anchor
+
+ model_url = resource_url # b/w compat forever
+
+ def static_url(self, path, **kw):
+ """
+ Generates a fully qualified URL for a static :term:`asset`.
+ The asset must live within a location defined via the
+ :meth:`pyramid.config.Configurator.add_static_view`
+ :term:`configuration declaration` (see :ref:`static_assets_section`).
+
+ Example::
+
+ request.static_url('mypackage:static/foo.css') =>
+
+ http://example.com/static/foo.css
+
+
+ The ``path`` argument points at a file or directory on disk which
+ a URL should be generated for. The ``path`` may be either a
+ relative path (e.g. ``static/foo.css``) or a :term:`asset
+ specification` (e.g. ``mypackage:static/foo.css``). A ``path``
+ may not be an absolute filesystem path (a :exc:`ValueError` will
+ be raised if this function is supplied with an absolute path).
+
+ The purpose of the ``**kw`` argument is the same as the purpose of
+ the :meth:`pyramid.request.Request.route_url` ``**kw`` argument. See
+ the documentation for that function to understand the arguments which
+ you can provide to it. However, typically, you don't need to pass
+ anything as ``*kw`` when generating a static asset URL.
+
+ This function raises a :exc:`ValueError` if a static view
+ definition cannot be found which matches the path specification.
+
+ """
+ if os.path.isabs(path):
+ raise ValueError('Absolute paths cannot be used to generate static '
+ 'urls (use a package-relative path or an asset '
+ 'specification).')
+ if not ':' in path:
+ # if it's not a package:relative/name and it's not an
+ # /absolute/path it's a relative/path; this means its relative
+ # to the package in which the caller's module is defined.
+ package = caller_package()
+ path = '%s:%s' % (package.__name__, path)
+
+ try:
+ reg = self.registry
+ except AttributeError:
+ reg = get_current_registry() # b/c
+
+ info = reg.queryUtility(IStaticURLInfo)
+ if info is None:
+ raise ValueError('No static URL definition matching %s' % path)
+
+ return info.generate(path, self, **kw)
+
+ def current_route_url(self, *elements, **kw):
+
+ """
+ Generates a fully qualified URL for a named :app:`Pyramid`
+ :term:`route configuration` based on the 'current route'.
+
+ This function supplements
+ :meth:`pyramid.request.Request.route_url`. It presents an easy way to
+ generate a URL for the 'current route' (defined as the route which
+ matched when the request was generated).
+
+ The arguments to this method have the same meaning as those with the
+ same names passed to :meth:`pyramid.request.Request.route_url`. It
+ also understands an extra argument which ``route_url`` does not named
+ ``_route_name``.
+
+ The route name used to generate a URL is taken from either the
+ ``_route_name`` keyword argument or the name of the route which is
+ currently associated with the request if ``_route_name`` was not
+ passed. Keys and values from the current request :term:`matchdict`
+ are combined with the ``kw`` arguments to form a set of defaults
+ named ``newkw``. Then ``request.route_url(route_name, *elements,
+ **newkw)`` is called, returning a URL.
+
+ Examples follow.
+
+ If the 'current route' has the route pattern ``/foo/{page}`` and the
+ current url path is ``/foo/1`` , the matchdict will be
+ ``{'page':'1'}``. The result of ``request.current_route_url()`` in
+ this situation will be ``/foo/1``.
+
+ If the 'current route' has the route pattern ``/foo/{page}`` and the
+ current url path is ``/foo/1``, the matchdict will be
+ ``{'page':'1'}``. The result of
+ ``request.current_route_url(page='2')`` in this situation will be
+ ``/foo/2``.
+
+ Usage of the ``_route_name`` keyword argument: if our routing table
+ defines routes ``/foo/{action}`` named 'foo' and
+ ``/foo/{action}/{page}`` named ``fooaction``, and the current url
+ pattern is ``/foo/view`` (which has matched the ``/foo/{action}``
+ route), we may want to use the matchdict args to generate a URL to
+ the ``fooaction`` route. In this scenario,
+ ``request.current_route_url(_route_name='fooaction', page='5')``
+ Will return string like: ``/foo/view/5``.
+
+ """
+ if '_route_name' in kw:
+ route_name = kw.pop('_route_name')
+ else:
+ route = getattr(self, 'matched_route', None)
+ route_name = getattr(route, 'name', None)
+ if route_name is None:
+ raise ValueError('Current request matches no route')
+
+ newkw = {}
+ newkw.update(self.matchdict)
+ newkw.update(kw)
+ return self.route_url(route_name, *elements, **newkw)
+
def route_url(route_name, request, *elements, **kw):
- """Generates a fully qualified URL for a named :app:`Pyramid`
- :term:`route configuration`.
-
- .. note:: Calling :meth:`pyramid.Request.route_url` can be used to
- achieve the same result as :func:`pyramid.url.route_url`.
-
- Use the route's ``name`` as the first positional argument. Use a
- request object as the second positional argument. Additional
- positional arguments are appended to the URL as path segments
- after it is generated.
-
- Use keyword arguments to supply values which match any dynamic
- path elements in the route definition. Raises a :exc:`KeyError`
- exception if the URL cannot be generated for any reason (not
- enough arguments, for example).
-
- For example, if you've defined a route named "foobar" with the path
- ``{foo}/{bar}/*traverse``::
-
- route_url('foobar', request, foo='1') => <KeyError exception>
- route_url('foobar', request, foo='1', bar='2') => <KeyError exception>
- route_url('foobar', request, foo='1', bar='2',
- traverse=('a','b')) => http://e.com/1/2/a/b
- route_url('foobar', request, foo='1', bar='2',
- traverse='/a/b') => http://e.com/1/2/a/b
-
- Values replacing ``:segment`` arguments can be passed as strings
- or Unicode objects. They will be encoded to UTF-8 and URL-quoted
- before being placed into the generated URL.
-
- Values replacing ``*remainder`` arguments can be passed as strings
- *or* tuples of Unicode/string values. If a tuple is passed as a
- ``*remainder`` replacement value, its values are URL-quoted and
- encoded to UTF-8. The resulting strings are joined with slashes
- and rendered into the URL. If a string is passed as a
- ``*remainder`` replacement value, it is tacked on to the URL
- untouched.
-
- If a keyword argument ``_query`` is present, it will be used to
- compose a query string that will be tacked on to the end of the
- URL. The value of ``_query`` must be a sequence of two-tuples
- *or* a data structure with an ``.items()`` method that returns a
- sequence of two-tuples (presumably a dictionary). This data
- structure will be turned into a query string per the documentation
- of :func:`pyramid.encode.urlencode` function. After the query
- data is turned into a query string, a leading ``?`` is prepended,
- and the resulting string is appended to the generated URL.
-
- .. note:: Python data structures that are passed as ``_query``
- which are sequences or dictionaries are turned into a
- string under the same rules as when run through
- :func:`urllib.urlencode` with the ``doseq`` argument
- equal to ``True``. This means that sequences can be
- passed as values, and a k=v pair will be placed into the
- query string for each value.
-
- If a keyword argument ``_anchor`` is present, its string
- representation will be used as a named anchor in the generated URL
- (e.g. if ``_anchor`` is passed as ``foo`` and the route URL is
- ``http://example.com/route/url``, the resulting generated URL will
- be ``http://example.com/route/url#foo``).
-
- .. note:: If ``_anchor`` is passed as a string, it should be UTF-8
- encoded. If ``_anchor`` is passed as a Unicode object, it
- will be converted to UTF-8 before being appended to the
- URL. The anchor value is not quoted in any way before
- being appended to the generated URL.
-
- If both ``_anchor`` and ``_query`` are specified, the anchor
- element will always follow the query element,
- e.g. ``http://example.com?foo=1#bar``.
-
- If a keyword ``_app_url`` is present, it will be used as the
- protocol/hostname/port/leading path prefix of the generated URL.
- For example, using an ``_app_url`` of
- ``http://example.com:8080/foo`` would cause the URL
- ``http://example.com:8080/foo/fleeb/flub`` to be returned from
- this function if the expansion of the route pattern associated
- with the ``route_name`` expanded to ``/fleeb/flub``. If
- ``_app_url`` is not specified, the result of
- ``request.application_url`` will be used as the prefix (the
- default).
-
- This function raises a :exc:`KeyError` if the URL cannot be
- generated due to missing replacement names. Extra replacement
- names are ignored.
-
- If the route object which matches the ``route_name`` argument has
- a :term:`pregenerator`, the ``*elements`` and ``**kw`` arguments
- arguments passed to this function might be augmented or changed.
-
"""
- try:
- reg = request.registry
- except AttributeError:
- reg = get_current_registry() # b/c
- mapper = reg.getUtility(IRoutesMapper)
- route = mapper.get_route(route_name)
-
- if route is None:
- raise KeyError('No such route named %s' % route_name)
-
- if route.pregenerator is not None:
- elements, kw = route.pregenerator(request, elements, kw)
-
- anchor = ''
- qs = ''
- app_url = None
-
- if '_query' in kw:
- qs = '?' + urlencode(kw.pop('_query'), doseq=True)
-
- if '_anchor' in kw:
- anchor = kw.pop('_anchor')
- if isinstance(anchor, unicode):
- anchor = anchor.encode('utf-8')
- anchor = '#' + anchor
-
- if '_app_url' in kw:
- app_url = kw.pop('_app_url')
+ This is a backwards compatibility function. Its result is the same as
+ calling::
- path = route.generate(kw) # raises KeyError if generate fails
+ request.route_url(route_name, *elements, **kw)
- if elements:
- suffix = _join_elements(elements)
- if not path.endswith('/'):
- suffix = '/' + suffix
- else:
- suffix = ''
-
- if app_url is None:
- # we only defer lookup of application_url until here because
- # it's somewhat expensive; we won't need to do it if we've
- # been passed _app_url
- app_url = request.application_url
-
- return app_url + path + suffix + qs + anchor
+ See :meth:`pyramid.request.Request.route_url` for more information.
+ """
+ return request.route_url(route_name, *elements, **kw)
def route_path(route_name, request, *elements, **kw):
- """Generates a path (aka a 'relative URL', a URL minus the host, scheme,
- and port) for a named :app:`Pyramid` :term:`route configuration`.
-
- .. note:: Calling :meth:`pyramid.Request.route_path` can be used to
- achieve the same result as :func:`pyramid.url.route_path`.
-
- This function accepts the same argument as :func:`pyramid.url.route_url`
- and performs the same duty. It just omits the host, port, and scheme
- information in the return value; only the script_name, path,
- query parameters, and anchor data are present in the returned string.
-
- For example, if you've defined a route named 'foobar' with the path
- ``/{foo}/{bar}``, this call to ``route_path``::
-
- route_path('foobar', request, foo='1', bar='2')
+ """
+ This is a backwards compatibility function. Its result is the same as
+ calling::
- Will return the string ``/1/2``.
+ request.route_path(route_name, *elements, **kw)
- .. note:: Calling ``route_path('route', request)`` is the same as calling
- ``route_url('route', request, _app_url=request.script_name)``.
- ``route_path`` is, in fact, implemented in terms of ``route_url``
- in just this way. As a result, any ``_app_url`` passed within the
- ``**kw`` values to ``route_path`` will be ignored.
+ See :meth:`pyramid.request.Request.route_path` for more information.
"""
- kw['_app_url'] = request.script_name
- return route_url(route_name, request, *elements, **kw)
+ return request.route_path(route_name, *elements, **kw)
def resource_url(resource, request, *elements, **kw):
"""
- Generate a string representing the absolute URL of the :term:`resource`
- object based on the ``wsgi.url_scheme``, ``HTTP_HOST`` or
- ``SERVER_NAME`` in the ``request``, plus any ``SCRIPT_NAME``. The
- overall result of this function is always a UTF-8 encoded string
- (never Unicode).
-
- .. note:: Calling :meth:`pyramid.Request.resource_url` can be used to
- achieve the same result as :func:`pyramid.url.resource_url`.
-
- Examples::
-
- resource_url(context, request) =>
-
- http://example.com/
-
- resource_url(context, request, 'a.html') =>
-
- http://example.com/a.html
-
- resource_url(context, request, 'a.html', query={'q':'1'}) =>
-
- http://example.com/a.html?q=1
-
- resource_url(context, request, 'a.html', anchor='abc') =>
-
- http://example.com/a.html#abc
-
- Any positional arguments passed in as ``elements`` must be strings
- Unicode objects, or integer objects. These will be joined by slashes and
- appended to the generated resource URL. Each of the elements passed in
- is URL-quoted before being appended; if any element is Unicode, it will
- converted to a UTF-8 bytestring before being URL-quoted. If any element
- is an integer, it will be converted to its string representation before
- being URL-quoted.
-
- .. warning:: if no ``elements`` arguments are specified, the resource
- URL will end with a trailing slash. If any
- ``elements`` are used, the generated URL will *not*
- end in trailing a slash.
-
- If a keyword argument ``query`` is present, it will be used to
- compose a query string that will be tacked on to the end of the
- URL. The value of ``query`` must be a sequence of two-tuples *or*
- a data structure with an ``.items()`` method that returns a
- sequence of two-tuples (presumably a dictionary). This data
- structure will be turned into a query string per the documentation
- of ``pyramid.url.urlencode`` function. After the query data is
- turned into a query string, a leading ``?`` is prepended, and the
- resulting string is appended to the generated URL.
-
- .. note:: Python data structures that are passed as ``query``
- which are sequences or dictionaries are turned into a
- string under the same rules as when run through
- :func:`urllib.urlencode` with the ``doseq`` argument
- equal to ``True``. This means that sequences can be
- passed as values, and a k=v pair will be placed into the
- query string for each value.
-
- If a keyword argument ``anchor`` is present, its string
- representation will be used as a named anchor in the generated URL
- (e.g. if ``anchor`` is passed as ``foo`` and the resource URL is
- ``http://example.com/resource/url``, the resulting generated URL will
- be ``http://example.com/resource/url#foo``).
-
- .. note:: If ``anchor`` is passed as a string, it should be UTF-8
- encoded. If ``anchor`` is passed as a Unicode object, it
- will be converted to UTF-8 before being appended to the
- URL. The anchor value is not quoted in any way before
- being appended to the generated URL.
-
- If both ``anchor`` and ``query`` are specified, the anchor element
- will always follow the query element,
- e.g. ``http://example.com?foo=1#bar``.
-
- If the ``resource`` passed in has a ``__resource_url__`` method, it will
- be used to generate the URL (scheme, host, port, path) that for the base
- resource which is operated upon by this function. See also
- :ref:`overriding_resource_url_generation`.
-
- .. note:: If the :term:`resource` used is the result of a
- :term:`traversal`, it must be :term:`location`-aware.
- The resource can also be the context of a :term:`URL
- dispatch`; contexts found this way do not need to be
- location-aware.
-
- .. note:: If a 'virtual root path' is present in the request
- environment (the value of the WSGI environ key
- ``HTTP_X_VHM_ROOT``), and the resource was obtained via
- :term:`traversal`, the URL path will not include the
- virtual root prefix (it will be stripped off the
- left hand side of the generated URL).
-
- .. note:: For backwards compatibility purposes, this function can also be
- imported as ``model_url``, although doing so will emit a deprecation
- warning.
+ This is a backwards compatibility function. Its result is the same as
+ calling::
+
+ request.resource_url(resource, *elements, **kw)
+
+ See :meth:`pyramid.request.Request.resource_url` for more information.
"""
- try:
- reg = request.registry
- except AttributeError:
- reg = get_current_registry() # b/c
-
- context_url = reg.queryMultiAdapter((resource, request), IContextURL)
- if context_url is None:
- context_url = TraversalContextURL(resource, request)
- resource_url = context_url()
-
- qs = ''
- anchor = ''
-
- if 'query' in kw:
- qs = '?' + urlencode(kw['query'], doseq=True)
-
- if 'anchor' in kw:
- anchor = kw['anchor']
- if isinstance(anchor, unicode):
- anchor = anchor.encode('utf-8')
- anchor = '#' + anchor
-
- if elements:
- suffix = _join_elements(elements)
- else:
- suffix = ''
-
- return resource_url + suffix + qs + anchor
+ return request.resource_url(resource, *elements, **kw)
model_url = resource_url # b/w compat (forever)
deprecated(
'model_url',
- 'pyramid.url.model_url is deprecated as of Pyramid 1.0. Use'
+ 'pyramid.url.model_url is deprecated as of Pyramid 1.0. Use '
'``pyramid.url.resource_url`` instead (API-compat, simple '
- 'rename).')
+ 'rename) or the ``pyramid.request.Request.resource_url`` method.')
def static_url(path, request, **kw):
"""
- Generates a fully qualified URL for a static :term:`asset`.
- The asset must live within a location defined via the
- :meth:`pyramid.config.Configurator.add_static_view`
- :term:`configuration declaration` (see :ref:`static_assets_section`).
-
- .. note:: Calling :meth:`pyramid.Request.static_url` can be used to
- achieve the same result as :func:`pyramid.url.static_url`.
-
- Example::
-
- static_url('mypackage:static/foo.css', request) =>
-
- http://example.com/static/foo.css
-
+ This is a backwards compatibility function. Its result is the same as
+ calling::
- The ``path`` argument points at a file or directory on disk which
- a URL should be generated for. The ``path`` may be either a
- relative path (e.g. ``static/foo.css``) or a :term:`asset
- specification` (e.g. ``mypackage:static/foo.css``). A ``path``
- may not be an absolute filesystem path (a :exc:`ValueError` will
- be raised if this function is supplied with an absolute path).
-
- The ``request`` argument should be a :term:`request` object.
-
- The purpose of the ``**kw`` argument is the same as the purpose of
- the :func:`pyramid.url.route_url` ``**kw`` argument. See the
- documentation for that function to understand the arguments which
- you can provide to it. However, typically, you don't need to pass
- anything as ``*kw`` when generating a static asset URL.
-
- This function raises a :exc:`ValueError` if a static view
- definition cannot be found which matches the path specification.
+ request.static_url(path, **kw)
+ See :meth:`pyramid.request.Request.static_url` for more information.
"""
- if os.path.isabs(path):
- raise ValueError('Absolute paths cannot be used to generate static '
- 'urls (use a package-relative path or an asset '
- 'specification).')
- if not ':' in path:
- # if it's not a package:relative/name and it's not an
- # /absolute/path it's a relative/path; this means its relative
- # to the package in which the caller's module is defined.
- package = caller_package()
- path = '%s:%s' % (package.__name__, path)
-
- try:
- reg = request.registry
- except AttributeError:
- reg = get_current_registry() # b/c
-
- info = reg.queryUtility(IStaticURLInfo)
- if info is None:
- raise ValueError('No static URL definition matching %s' % path)
-
- return info.generate(path, request, **kw)
+ return request.static_url(path, **kw)
def current_route_url(request, *elements, **kw):
- """Generates a fully qualified URL for a named :app:`Pyramid`
- :term:`route configuration` based on the 'current route'.
-
- This function supplements :func:`pyramid.url.route_url`. It presents an
- easy way to generate a URL for the 'current route' (defined as the route
- which matched when the request was generated).
-
- The arguments to this function have the same meaning as those with the
- same names passed to :func:`pyramid.url.route_url`. It also understands
- an extra argument which ``route_url`` does not named ``_route_name``.
-
- The route name used to generate a URL is taken from either the
- ``_route_name`` keyword argument or the name of the route which is
- currently associated with the request if ``_route_name`` was not passed.
- Keys and values from the current request :term:`matchdict` are combined
- with the ``kw`` arguments to form a set of defaults named ``newkw``.
- Then ``route_url(route_name, request, *elements, **newkw)`` is called,
- returning a URL.
-
- Examples follow.
-
- If the 'current route' has the route pattern ``/foo/{page}`` and the
- current url path is ``/foo/1`` , the matchdict will be ``{'page':'1'}``.
- The result of ``current_route_url(request)`` in this situation will be
- ``/foo/1``.
-
- If the 'current route' has the route pattern ``/foo/{page}`` and the
- current url path is ``/foo/1``, the matchdict will be
- ``{'page':'1'}``. The result of ``current_route_url(request, page='2')``
- in this situation will be ``/foo/2``.
-
- Usage of the ``_route_name`` keyword argument: if our routing table
- defines routes ``/foo/{action}`` named 'foo' and ``/foo/{action}/{page}``
- named ``fooaction``, and the current url pattern is ``/foo/view`` (which
- has matched the ``/foo/{action}`` route), we may want to use the
- matchdict args to generate a URL to the ``fooaction`` route. In this
- scenario, ``current_route_url(request, _route_name='fooaction', page='5')``
- Will return string like: ``/foo/view/5``.
"""
+ This is a backwards compatibility function. Its result is the same as
+ calling::
+
+ request.current_route_url(*elements, **kw)
- if '_route_name' in kw:
- route_name = kw.pop('_route_name')
- else:
- route = getattr(request, 'matched_route', None)
- route_name = getattr(route, 'name', None)
- if route_name is None:
- raise ValueError('Current request matches no route')
-
- newkw = {}
- newkw.update(request.matchdict)
- newkw.update(kw)
- return route_url(route_name, request, *elements, **newkw)
+ See :meth:`pyramid.request.Request.current_route_url` for more
+ information.
+ """
+ return request.current_route_url(*elements, **kw)
@lru_cache(1000)
def _join_elements(elements):