summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.rst5
-rw-r--r--CONTRIBUTORS.txt4
-rw-r--r--docs/narr/urldispatch.rst18
-rw-r--r--pyramid/config/__init__.py45
-rw-r--r--pyramid/config/routes.py51
-rw-r--r--pyramid/tests/test_url.py64
6 files changed, 158 insertions, 29 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 1771026fc..d24fb24e8 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -25,6 +25,11 @@ Features
imports from `cherrypy.wsgiserver`.
See https://github.com/Pylons/pyramid/pull/3235
+- Add a context manager ``route_prefix_context`` to the
+ ``pyramid.config.Configurator`` to allow for convenient setting of the
+ route_prefix for ``include`` and ``add_route`` calls inside the context.
+ See https://github.com/Pylons/pyramid/pull/3279
+
Bug Fixes
---------
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index b6dbcff2c..60e4e5732 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -316,3 +316,7 @@ Contributors
- Deneys Maartens, 2017/11/03
- Heron Rossi, 2018/03/08
+
+- Hunter Senft-Grupp, 2018/05/14
+
+- Junhak Lee, 2018/05/14 \ No newline at end of file
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 9ac01e24a..00c7bd3bf 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -1045,6 +1045,24 @@ may be added in the future. For example:
config = Configurator()
config.include(users_include, route_prefix='/users')
+A convenience context manager exists to set the route prefix for any
+:meth:`pyramid.config.Configurator.add_route` or
+:meth:`pyramid.config.Configurator.include` calls within the context.
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+
+ def timing_include(config):
+ config.add_route('timing.show_times', '/times')
+
+ def main(global_config, **settings)
+ config = Configurator()
+ with config.route_prefix_context('/timing'):
+ config.include(timing_include)
+ config.add_route('timing.average', '/average')
+
.. index::
single: route predicates (custom)
diff --git a/pyramid/config/__init__.py b/pyramid/config/__init__.py
index a34f0b4db..886eec0df 100644
--- a/pyramid/config/__init__.py
+++ b/pyramid/config/__init__.py
@@ -790,21 +790,6 @@ class Configurator(
action_state = self.action_state
- if route_prefix is None:
- route_prefix = ''
-
- old_route_prefix = self.route_prefix
- if old_route_prefix is None:
- old_route_prefix = ''
-
- route_prefix = '%s/%s' % (
- old_route_prefix.rstrip('/'),
- route_prefix.lstrip('/')
- )
- route_prefix = route_prefix.strip('/')
- if not route_prefix:
- route_prefix = None
-
c = self.maybe_dotted(callable)
module = self.inspect.getmodule(c)
if module is c:
@@ -825,20 +810,22 @@ class Configurator(
if action_state.processSpec(spec):
- configurator = self.__class__(
- registry=self.registry,
- package=package_of(module),
- root_package=self.root_package,
- autocommit=self.autocommit,
- route_prefix=route_prefix,
- )
- configurator.basepath = os.path.dirname(sourcefile)
- configurator.includepath = self.includepath + (spec,)
- self.begin()
- try:
- c(configurator)
- finally:
- self.end()
+ with self.route_prefix_context(route_prefix):
+ configurator = self.__class__(
+ registry=self.registry,
+ package=package_of(module),
+ root_package=self.root_package,
+ autocommit=self.autocommit,
+ route_prefix=self.route_prefix,
+ )
+ configurator.basepath = os.path.dirname(sourcefile)
+ configurator.includepath = self.includepath + (spec,)
+
+ self.begin()
+ try:
+ c(configurator)
+ finally:
+ self.end()
def add_directive(self, name, directive, action_wrap=True):
"""
diff --git a/pyramid/config/routes.py b/pyramid/config/routes.py
index 203baa128..598af300f 100644
--- a/pyramid/config/routes.py
+++ b/pyramid/config/routes.py
@@ -1,3 +1,4 @@
+import contextlib
import warnings
from pyramid.compat import urlparse
@@ -467,3 +468,53 @@ class RoutesConfiguratorMixin(object):
self.registry.registerUtility(mapper, IRoutesMapper)
return mapper
+ @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``.
+
+ When the context exits, the ``route_prefix`` is reset to the original.
+
+ Example Usage:
+
+ >>> config = Configurator()
+ >>> with config.route_prefix_context('foo'):
+ ... config.add_route('bar', '/bar')
+
+ Arguments
+
+ route_prefix
+
+ A string suitable to be used as a route prefix, or ``None``.
+
+ .. versionadded:: 1.10
+ """
+
+ original_route_prefix = self.route_prefix
+
+ if route_prefix is None:
+ route_prefix = ''
+
+ old_route_prefix = self.route_prefix
+ if old_route_prefix is None:
+ old_route_prefix = ''
+
+ route_prefix = '{}/{}'.format(
+ old_route_prefix.rstrip('/'),
+ route_prefix.lstrip('/'),
+ )
+
+ route_prefix = route_prefix.strip('/')
+
+ if not route_prefix:
+ route_prefix = None
+
+ self.begin()
+ try:
+ self.route_prefix = route_prefix
+ yield
+
+ finally:
+ self.route_prefix = original_route_prefix
+ self.end()
diff --git a/pyramid/tests/test_url.py b/pyramid/tests/test_url.py
index af2e5405c..31b3dd571 100644
--- a/pyramid/tests/test_url.py
+++ b/pyramid/tests/test_url.py
@@ -1251,6 +1251,70 @@ class Test_external_static_url_integration(unittest.TestCase):
request.route_url('acme', foo='bar'),
'http://acme.org/bar')
+class Test_with_route_prefix(unittest.TestCase):
+
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def _makeRequest(self, route):
+ from pyramid.request import Request
+ return Request.blank(route)
+
+ def test_old_route_is_preserved(self):
+ self.config.route_prefix = 'old_prefix'
+ with self.config.route_prefix_context('new_addon'):
+ assert 'new_addon' in self.config.route_prefix
+
+ assert 'old_prefix' == self.config.route_prefix
+
+ def test_route_prefix_none(self):
+ self.config.route_prefix = 'old_prefix'
+ with self.config.route_prefix_context(None):
+ assert 'old_prefix' == self.config.route_prefix
+
+ assert 'old_prefix' == self.config.route_prefix
+
+ def test_route_prefix_empty(self):
+ self.config.route_prefix = 'old_prefix'
+ with self.config.route_prefix_context(''):
+ assert 'old_prefix' == self.config.route_prefix
+
+ assert 'old_prefix' == self.config.route_prefix
+
+ def test_route_has_prefix(self):
+ with self.config.route_prefix_context('bar'):
+ self.config.add_route('acme', '/foo')
+ request = self._makeRequest('/')
+ self.assertEqual(
+ request.route_url('acme'),
+ 'http://localhost/bar/foo',
+ )
+
+ def test_route_does_not_have_prefix(self):
+ with self.config.route_prefix_context('bar'):
+ pass
+
+ self.config.add_route('acme', '/foo')
+ request = self._makeRequest('/')
+ self.assertEqual(
+ request.route_url('acme'),
+ 'http://localhost/foo',
+ )
+
+ def test_error_reset_prefix(self):
+ self.config.route_prefix = 'old_prefix'
+
+ try:
+ with self.config.route_prefix_context('new_prefix'):
+ raise RuntimeError
+ except RuntimeError:
+ pass
+
+ assert self.config.route_prefix == 'old_prefix'
+
class DummyContext(object):
def __init__(self, next=None):
self.next = next