summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Merickel <github@m.merickel.org>2018-11-12 20:07:15 -0600
committerGitHub <noreply@github.com>2018-11-12 20:07:15 -0600
commit7429fcb5a96aa10bbe86da08bd0b30c9292efdde (patch)
tree548defadbf50447b4e6a0b1f9363f3d08ded8bfc
parent420ea05bee3ad376c4369f401b2696b31312c5e1 (diff)
parent2d32ae81abc473fb21b4bc42aec479c656693f1c (diff)
downloadpyramid-7429fcb5a96aa10bbe86da08bd0b30c9292efdde.tar.gz
pyramid-7429fcb5a96aa10bbe86da08bd0b30c9292efdde.tar.bz2
pyramid-7429fcb5a96aa10bbe86da08bd0b30c9292efdde.zip
Merge pull request #3420 from mmerickel/bare-route-prefix-2
support inherit_slash=True on add_route
-rw-r--r--CHANGES.rst19
-rw-r--r--CONTRIBUTORS.txt2
-rw-r--r--docs/glossary.rst4
-rw-r--r--docs/narr/urldispatch.rst18
-rw-r--r--src/pyramid/config/__init__.py4
-rw-r--r--src/pyramid/config/routes.py39
-rw-r--r--tests/test_config/test_routes.py24
7 files changed, 104 insertions, 6 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 73562c003..7772ac7e2 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -12,6 +12,25 @@ Features
documentation for more information about why this change was made.
See https://github.com/Pylons/pyramid/pull/3413
+- It is now possible to control whether a route pattern contains a trailing
+ slash when it is composed with a route prefix using
+ ``config.include(..., route_prefix=...)`` or
+ ``with config.route_prefix_context(...)``. This can be done by specifying
+ an empty pattern and setting the new argument
+ ``inherit_slash=True``. For example:
+
+ .. code-block:: python
+
+ with config.route_prefix_context('/users'):
+ config.add_route('users', '', inherit_slash=True)
+
+ In the example, the resulting pattern will be ``/users``. Similarly, if the
+ route prefix were ``/users/`` then the final pattern would be ``/users/``.
+ If the ``pattern`` was ``'/'``, then the final pattern would always be
+ ``/users/``. This new setting is only available if the pattern supplied
+ to ``add_route`` is the empty string (``''``).
+ See https://github.com/Pylons/pyramid/pull/3420
+
Bug Fixes
---------
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 7256b66db..79e4287d2 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -297,6 +297,8 @@ Contributors
- Kirill Kuzminykh, 2017/03/01
+- Charlie Choiniere, 2017/04/03
+
- Aleph Melo, 2017/04/16
- Jeremy(Ching-Rui) Chen, 2017/04/19
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 4668efe6d..f42b298df 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -1203,3 +1203,7 @@ Glossary
A media type is a nested structure containing a top-level type and a subtype.
Optionally, a media type can also contain parameters specific to the type.
See :rfc:`6838` for more information about media types.
+
+ route prefix
+ A route prefix is a path prefix that is prepended to any routes that are configured while it is active.
+ A route prefix can be set via :meth:`pyramid.config.Configurator.include` or :meth:`pyramid.config.Configurator.route_prefix_context`.
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 52d64891c..3b737b46d 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -971,7 +971,7 @@ application from small and potentially reusable components.
The :meth:`pyramid.config.Configurator.include` method accepts an argument
named ``route_prefix`` which can be useful to authors of URL-dispatch-based
applications. If ``route_prefix`` is supplied to the include method, it must
-be a string. This string represents a route prefix that will be prepended to
+be a string. This string represents a :term:`route prefix` that will be prepended to
all route patterns added by the *included* configuration. Any calls to
:meth:`pyramid.config.Configurator.add_route` within the included callable will
have their pattern prefixed with the value of ``route_prefix``. This can be
@@ -998,6 +998,22 @@ then only match if the URL path is ``/users/show``, and when the
:meth:`pyramid.request.Request.route_url` function is called with the route
name ``show_users``, it will generate a URL with that same path.
+To create a route that matches requests to the ``route_prefix`` without a trailing slash, pass ``inherit_slash=True`` to the call to ``add_route``.
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+
+ def users_include(config):
+ config.add_route('show_users', '', inherit_slash=True)
+
+ def main(global_config, **settings):
+ config = Configurator()
+ config.include(users_include, route_prefix='/users')
+
+The above configuration will match ``/users`` instead of ``/users/``.
+
Route prefixes are recursive, so if a callable executed via an include itself
turns around and includes another callable, the second-level route prefix will
be prepended with the first:
diff --git a/src/pyramid/config/__init__.py b/src/pyramid/config/__init__.py
index 00c3e6a02..475f0d9a2 100644
--- a/src/pyramid/config/__init__.py
+++ b/src/pyramid/config/__init__.py
@@ -602,7 +602,9 @@ class Configurator(
configuration conflict by registering something with the same
configuration parameters.
- If the ``route_prefix`` is supplied, it must be a string. Any calls
+ If the ``route_prefix`` is supplied, it must be a string and will
+ have a similar effect to using
+ :meth:`pyramid.config.Configurator.route_prefix_context`. Any calls
to :meth:`pyramid.config.Configurator.add_route` within the included
callable will have their pattern prefixed with the value of
``route_prefix``. This can be used to help mount a set of routes at a
diff --git a/src/pyramid/config/routes.py b/src/pyramid/config/routes.py
index f9180bd76..52540c935 100644
--- a/src/pyramid/config/routes.py
+++ b/src/pyramid/config/routes.py
@@ -40,6 +40,7 @@ class RoutesConfiguratorMixin(object):
path=None,
pregenerator=None,
static=False,
+ inherit_slash=None,
**predicates
):
""" Add a :term:`route configuration` to the current
@@ -139,6 +140,27 @@ class RoutesConfiguratorMixin(object):
.. versionadded:: 1.1
+ inherit_slash
+
+ This argument can only be used when the ``pattern`` is an empty
+ string (``''``). By default, the composed route pattern will always
+ include a trailing slash, but this argument provides a way to
+ opt-out if both, you (the developer invoking ``add_route``) and the
+ integrator (the developer setting the :term:`route prefix`),
+ agree that the pattern should not contain a trailing slash.
+ For example:
+
+ .. code-block:: python
+
+ with config.route_prefix_context('/users'):
+ config.add_route('users', '', inherit_slash=True)
+
+ In this example, the resulting route pattern will be ``/users``.
+ Alternatively, if the route prefix were ``/users/``, then the
+ resulting route pattern would be ``/users/``.
+
+ .. versionadded:: 2.0
+
Predicate Arguments
pattern
@@ -329,6 +351,11 @@ class RoutesConfiguratorMixin(object):
if pattern is None:
raise ConfigurationError('"pattern" argument may not be None')
+ if inherit_slash and pattern != '':
+ raise ConfigurationError(
+ '"inherit_slash" may only be used with an empty pattern'
+ )
+
# check for an external route; an external route is one which is
# is a full url (e.g. 'http://example.com/{id}')
parsed = urlparse.urlparse(pattern)
@@ -364,7 +391,12 @@ class RoutesConfiguratorMixin(object):
static = True
elif self.route_prefix:
- pattern = self.route_prefix.rstrip('/') + '/' + pattern.lstrip('/')
+ if pattern == '' and inherit_slash:
+ pattern = self.route_prefix
+ else:
+ pattern = (
+ self.route_prefix.rstrip('/') + '/' + pattern.lstrip('/')
+ )
mapper = self.get_routes_mapper()
@@ -514,9 +546,8 @@ class RoutesConfiguratorMixin(object):
@contextlib.contextmanager
def route_prefix_context(self, route_prefix):
- """ Return this configurator with the
- :attr:`pyramid.config.Configurator.route_prefix` attribute mutated to
- include the new ``route_prefix``.
+ """
+ Return this configurator with a :term:`route prefix` temporarily set.
When the context exits, the ``route_prefix`` is reset to the original.
diff --git a/tests/test_config/test_routes.py b/tests/test_config/test_routes.py
index 32a64b4bd..e6540c343 100644
--- a/tests/test_config/test_routes.py
+++ b/tests/test_config/test_routes.py
@@ -54,6 +54,30 @@ class RoutesConfiguratorMixinTests(unittest.TestCase):
config.add_route('name', 'path')
self._assertRoute(config, 'name', 'root/path')
+ def test_add_route_with_inherit_errors(self):
+ from pyramid.exceptions import ConfigurationError
+
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(
+ ConfigurationError,
+ config.add_route,
+ 'name',
+ '/',
+ inherit_slash=True,
+ )
+
+ def test_add_route_with_route_prefix_with_inherit_slash(self):
+ config = self._makeOne(autocommit=True)
+ config.route_prefix = 'root'
+ config.add_route('name', '', inherit_slash=True)
+ self._assertRoute(config, 'name', 'root')
+
+ def test_add_route_with_root_slash_with_route_prefix(self):
+ config = self._makeOne(autocommit=True)
+ config.route_prefix = 'root'
+ config.add_route('name', '/')
+ self._assertRoute(config, 'name', 'root/')
+
def test_add_route_discriminator(self):
config = self._makeOne()
config.add_route('name', 'path')