Michael Merickel
2018-10-19 d579f2104de139e0b0fc5d6c81aabb2f826e5e54
commit | author | age
5bf23f 1 import inspect
CM 2 import logging
3 import os
c15cbc 4 import threading
5bf23f 5 import venusian
ea824f 6
CM 7 from webob.exc import WSGIHTTPException as WebobWSGIHTTPException
8
3b5ccb 9 from pyramid.interfaces import (
CM 10     IDebugLogger,
11     IExceptionResponse,
568a02 12     PHASE0_CONFIG,
95f766 13     PHASE1_CONFIG,
568a02 14     PHASE2_CONFIG,
MM 15     PHASE3_CONFIG,
0c29cf 16 )
5bf23f 17
cfbbd6 18 from pyramid.asset import resolve_asset_spec
ee117e 19
66da9b 20 from pyramid.authorization import ACLAuthorizationPolicy
ee117e 21
e4c057 22 from pyramid.compat import text_, string_types
ee117e 23
5bf23f 24 from pyramid.events import ApplicationCreated
ee117e 25
e4c057 26 from pyramid.exceptions import ConfigurationError
ee117e 27
5bf23f 28 from pyramid.httpexceptions import default_exceptionresponse_view
ee117e 29
0c29cf 30 from pyramid.path import caller_package, package_of
ee117e 31
e4c057 32 from pyramid.registry import Introspectable, Introspector, Registry
ee117e 33
cfbbd6 34 from pyramid.router import Router
ee117e 35
5bf23f 36 from pyramid.settings import aslist
ee117e 37
5bf23f 38 from pyramid.threadlocal import manager
ee117e 39
0c29cf 40 from pyramid.util import WeakOrderedSet, object_description
52fde9 41
d579f2 42 from pyramid.config.actions import action_method
MM 43 from pyramid.config.predicates import not_
5bf23f 44
e4c057 45 from pyramid.config.actions import ActionConfiguratorMixin
ea046b 46 from pyramid.config.adapters import AdaptersConfiguratorMixin
CM 47 from pyramid.config.assets import AssetsConfiguratorMixin
48 from pyramid.config.factories import FactoriesConfiguratorMixin
49 from pyramid.config.i18n import I18NConfiguratorMixin
d579f2 50 from pyramid.config.predicates import PredicateConfiguratorMixin
ea046b 51 from pyramid.config.rendering import RenderingConfiguratorMixin
CM 52 from pyramid.config.routes import RoutesConfiguratorMixin
53 from pyramid.config.security import SecurityConfiguratorMixin
54 from pyramid.config.settings import SettingsConfiguratorMixin
5bf23f 55 from pyramid.config.testing import TestingConfiguratorMixin
CM 56 from pyramid.config.tweens import TweensConfiguratorMixin
57 from pyramid.config.views import ViewsConfiguratorMixin
58 from pyramid.config.zca import ZCAConfiguratorMixin
e6c2d2 59
56df90 60 from pyramid.path import DottedNameResolver
CM 61
e6c2d2 62 empty = text_('')
e49638 63 _marker = object()
5bf23f 64
52fde9 65 not_ = not_  # api
32333e 66
568a02 67 PHASE0_CONFIG = PHASE0_CONFIG  # api
MM 68 PHASE1_CONFIG = PHASE1_CONFIG  # api
69 PHASE2_CONFIG = PHASE2_CONFIG  # api
70 PHASE3_CONFIG = PHASE3_CONFIG  # api
32333e 71
0c29cf 72
5bf23f 73 class Configurator(
e4c057 74     ActionConfiguratorMixin,
d579f2 75     PredicateConfiguratorMixin,
5bf23f 76     TestingConfiguratorMixin,
CM 77     TweensConfiguratorMixin,
78     SecurityConfiguratorMixin,
79     ViewsConfiguratorMixin,
80     RoutesConfiguratorMixin,
81     ZCAConfiguratorMixin,
82     I18NConfiguratorMixin,
83     RenderingConfiguratorMixin,
84     AssetsConfiguratorMixin,
85     SettingsConfiguratorMixin,
86     FactoriesConfiguratorMixin,
87     AdaptersConfiguratorMixin,
0c29cf 88 ):
5bf23f 89     """
CM 90     A Configurator is used to configure a :app:`Pyramid`
91     :term:`application registry`.
92
134ef7 93     The Configurator lifecycle can be managed by using a context manager to
MM 94     automatically handle calling :meth:`pyramid.config.Configurator.begin` and
95     :meth:`pyramid.config.Configurator.end` as well as
96     :meth:`pyramid.config.Configurator.commit`.
97
98     .. code-block:: python
99
100         with Configurator(settings=settings) as config:
101             config.add_route('home', '/')
102             app = config.make_wsgi_app()
103
0bf091 104     If the ``registry`` argument is not ``None``, it must
adfc23 105     be an instance of the :class:`pyramid.registry.Registry` class
CM 106     representing the registry to configure.  If ``registry`` is ``None``, the
107     configurator will create a :class:`pyramid.registry.Registry` instance
108     itself; it will also perform some default configuration that would not
109     otherwise be done.  After its construction, the configurator may be used
110     to add further configuration to the registry.
5bf23f 111
60270f 112     .. warning:: If ``registry`` is assigned the above-mentioned class
TL 113        instance, all other constructor arguments are ignored,
114        with the exception of ``package``.
5bf23f 115
adfc23 116     If the ``package`` argument is passed, it must be a reference to a Python
CM 117     :term:`package` (e.g. ``sys.modules['thepackage']``) or a :term:`dotted
118     Python name` to the same.  This value is used as a basis to convert
119     relative paths passed to various configuration methods, such as methods
120     which accept a ``renderer`` argument, into absolute paths.  If ``None``
121     is passed (the default), the package is assumed to be the Python package
122     in which the *caller* of the ``Configurator`` constructor lives.
5bf23f 123
ae6c88 124     If the ``root_package`` is passed, it will propagate through the
MM 125     configuration hierarchy as a way for included packages to locate
126     resources relative to the package in which the main ``Configurator`` was
127     created. If ``None`` is passed (the default), the ``root_package`` will
128     be derived from the ``package`` argument. The ``package`` attribute is
129     always pointing at the package being included when using :meth:`.include`,
130     whereas the ``root_package`` does not change.
131
5bf23f 132     If the ``settings`` argument is passed, it should be a Python dictionary
adfc23 133     representing the :term:`deployment settings` for this application.  These
CM 134     are later retrievable using the
135     :attr:`pyramid.registry.Registry.settings` attribute (aka
136     ``request.registry.settings``).
5bf23f 137
CM 138     If the ``root_factory`` argument is passed, it should be an object
adfc23 139     representing the default :term:`root factory` for your application or a
CM 140     :term:`dotted Python name` to the same.  If it is ``None``, a default
141     root factory will be used.
5bf23f 142
CM 143     If ``authentication_policy`` is passed, it should be an instance
144     of an :term:`authentication policy` or a :term:`dotted Python
adfc23 145     name` to the same.
5bf23f 146
CM 147     If ``authorization_policy`` is passed, it should be an instance of
148     an :term:`authorization policy` or a :term:`dotted Python name` to
adfc23 149     the same.
5bf23f 150
CM 151     .. note:: A ``ConfigurationError`` will be raised when an
152        authorization policy is supplied without also supplying an
153        authentication policy (authorization requires authentication).
154
3778e8 155     If ``renderers`` is ``None`` (the default), a default set of
TL 156     :term:`renderer` factories is used. Else, it should be a list of
157     tuples representing a set of renderer factories which should be
158     configured into this application, and each tuple representing a set of
5bf23f 159     positional values that should be passed to
3778e8 160     :meth:`pyramid.config.Configurator.add_renderer`.
5bf23f 161
CM 162     If ``debug_logger`` is not passed, a default debug logger that logs to a
163     logger will be used (the logger name will be the package name of the
164     *caller* of this configurator).  If it is passed, it should be an
165     instance of the :class:`logging.Logger` (PEP 282) standard library class
166     or a Python logger name.  The debug logger is used by :app:`Pyramid`
167     itself to log warnings and authorization debugging information.
168
169     If ``locale_negotiator`` is passed, it should be a :term:`locale
170     negotiator` implementation or a :term:`dotted Python name` to
171     same.  See :ref:`custom_locale_negotiator`.
172
173     If ``request_factory`` is passed, it should be a :term:`request
adfc23 174     factory` implementation or a :term:`dotted Python name` to the same.
5bf23f 175     See :ref:`changing_the_request_factory`.  By default it is ``None``,
CM 176     which means use the default request factory.
177
1236de 178     If ``response_factory`` is passed, it should be a :term:`response
JA 179     factory` implementation or a :term:`dotted Python name` to the same.
180     See :ref:`changing_the_response_factory`.  By default it is ``None``,
181     which means use the default response factory.
182
5bf23f 183     If ``default_permission`` is passed, it should be a
CM 184     :term:`permission` string to be used as the default permission for
185     all view configuration registrations performed against this
186     Configurator.  An example of a permission string:``'view'``.
187     Adding a default permission makes it unnecessary to protect each
188     view configuration with an explicit permission, unless your
189     application policy requires some exception for a particular view.
190     By default, ``default_permission`` is ``None``, meaning that view
191     configurations which do not explicitly declare a permission will
192     always be executable by entirely anonymous users (any
2033ee 193     authorization policy in effect is ignored).
1236de 194
2033ee 195     .. seealso::
SP 196
197         See also :ref:`setting_a_default_permission`.
5bf23f 198
CM 199     If ``session_factory`` is passed, it should be an object which
200     implements the :term:`session factory` interface.  If a nondefault
201     value is passed, the ``session_factory`` will be used to create a
202     session object when ``request.session`` is accessed.  Note that
203     the same outcome can be achieved by calling
204     :meth:`pyramid.config.Configurator.set_session_factory`.  By
205     default, this argument is ``None``, indicating that no session
206     factory will be configured (and thus accessing ``request.session``
207     will throw an error) unless ``set_session_factory`` is called later
208     during configuration.
209
210     If ``autocommit`` is ``True``, every method called on the configurator
211     will cause an immediate action, and no configuration conflict detection
212     will be used. If ``autocommit`` is ``False``, most methods of the
213     configurator will defer their action until
214     :meth:`pyramid.config.Configurator.commit` is called.  When
215     :meth:`pyramid.config.Configurator.commit` is called, the actions implied
216     by the called methods will be checked for configuration conflicts unless
5c351a 217     ``autocommit`` is ``True``.  If a conflict is detected, a
5bf23f 218     ``ConfigurationConflictError`` will be raised.  Calling
CM 219     :meth:`pyramid.config.Configurator.make_wsgi_app` always implies a final
220     commit.
221
222     If ``default_view_mapper`` is passed, it will be used as the default
223     :term:`view mapper` factory for view configurations that don't otherwise
a3f67c 224     specify one (see :class:`pyramid.interfaces.IViewMapperFactory`).  If
d0e652 225     ``default_view_mapper`` is not passed, a superdefault view mapper will be
5bf23f 226     used.
CM 227
228     If ``exceptionresponse_view`` is passed, it must be a :term:`view
229     callable` or ``None``.  If it is a view callable, it will be used as an
230     exception view callable when an :term:`exception response` is raised. If
231     ``exceptionresponse_view`` is ``None``, no exception response view will
232     be registered, and all raised exception responses will be bubbled up to
233     Pyramid's caller.  By
234     default, the ``pyramid.httpexceptions.default_exceptionresponse_view``
0b23b3 235     function is used as the ``exceptionresponse_view``.
5bf23f 236
CM 237     If ``route_prefix`` is passed, all routes added with
238     :meth:`pyramid.config.Configurator.add_route` will have the specified path
0b23b3 239     prepended to their pattern.
5bf23f 240
844ed9 241     If ``introspection`` is passed, it must be a boolean value.  If it's
043ccd 242     ``True``, introspection values during actions will be kept for use
844ed9 243     for tools like the debug toolbar.  If it's ``False``, introspection
CM 244     values provided by registrations will be ignored.  By default, it is
0b23b3 245     ``True``.
TL 246
247     .. versionadded:: 1.1
248        The ``exceptionresponse_view`` argument.
249
250     .. versionadded:: 1.2
251        The ``route_prefix`` argument.
252
253     .. versionadded:: 1.3
254        The ``introspection`` argument.
ae6c88 255
MM 256     .. versionadded:: 1.6
257        The ``root_package`` argument.
1236de 258        The ``response_factory`` argument.
134ef7 259
MM 260     .. versionadded:: 1.9
261        The ability to use the configurator as a context manager with the
262        ``with``-statement to make threadlocal configuration available for
263        further configuration with an implicit commit.
e49638 264     """
0c29cf 265
MM 266     manager = manager  # for testing injection
267     venusian = venusian  # for testing injection
5bf23f 268     _ainfo = None
b86fa9 269     basepath = None
CM 270     includepath = ()
271     info = ''
8b6f09 272     object_description = staticmethod(object_description)
e49638 273     introspectable = Introspectable
5ad401 274     inspect = inspect
5bf23f 275
0c29cf 276     def __init__(
MM 277         self,
278         registry=None,
279         package=None,
280         settings=None,
281         root_factory=None,
282         authentication_policy=None,
283         authorization_policy=None,
284         renderers=None,
285         debug_logger=None,
286         locale_negotiator=None,
287         request_factory=None,
288         response_factory=None,
289         default_permission=None,
290         session_factory=None,
291         default_view_mapper=None,
292         autocommit=False,
293         exceptionresponse_view=default_exceptionresponse_view,
294         route_prefix=None,
295         introspection=True,
296         root_package=None,
297     ):
5bf23f 298         if package is None:
CM 299             package = caller_package()
ae6c88 300         if root_package is None:
MM 301             root_package = package
5bf23f 302         name_resolver = DottedNameResolver(package)
CM 303         self.name_resolver = name_resolver
078859 304         self.package_name = name_resolver.get_package_name()
CM 305         self.package = name_resolver.get_package()
ae6c88 306         self.root_package = root_package
5bf23f 307         self.registry = registry
CM 308         self.autocommit = autocommit
309         self.route_prefix = route_prefix
844ed9 310         self.introspection = introspection
5bf23f 311         if registry is None:
CM 312             registry = Registry(self.package_name)
313             self.registry = registry
314             self.setup_registry(
315                 settings=settings,
316                 root_factory=root_factory,
317                 authentication_policy=authentication_policy,
318                 authorization_policy=authorization_policy,
319                 renderers=renderers,
320                 debug_logger=debug_logger,
321                 locale_negotiator=locale_negotiator,
322                 request_factory=request_factory,
1236de 323                 response_factory=response_factory,
5bf23f 324                 default_permission=default_permission,
CM 325                 session_factory=session_factory,
326                 default_view_mapper=default_view_mapper,
327                 exceptionresponse_view=exceptionresponse_view,
0c29cf 328             )
5bf23f 329
0c29cf 330     def setup_registry(
MM 331         self,
332         settings=None,
333         root_factory=None,
334         authentication_policy=None,
335         authorization_policy=None,
336         renderers=None,
337         debug_logger=None,
338         locale_negotiator=None,
339         request_factory=None,
340         response_factory=None,
341         default_permission=None,
342         session_factory=None,
343         default_view_mapper=None,
344         exceptionresponse_view=default_exceptionresponse_view,
345     ):
5bf23f 346         """ When you pass a non-``None`` ``registry`` argument to the
adfc23 347         :term:`Configurator` constructor, no initial setup is performed
5bf23f 348         against the registry.  This is because the registry you pass in may
CM 349         have already been initialized for use under :app:`Pyramid` via a
350         different configurator.  However, in some circumstances (such as when
adfc23 351         you want to use a global registry instead of a registry created as a
CM 352         result of the Configurator constructor), or when you want to reset
353         the initial setup of a registry, you *do* want to explicitly
354         initialize the registry associated with a Configurator for use under
355         :app:`Pyramid`.  Use ``setup_registry`` to do this initialization.
5bf23f 356
CM 357         ``setup_registry`` configures settings, a root factory, security
358         policies, renderers, a debug logger, a locale negotiator, and various
359         other settings using the configurator's current registry, as per the
360         descriptions in the Configurator constructor."""
c1624c 361
5bf23f 362         registry = self.registry
c1624c 363
5bf23f 364         self._fix_registry()
e49638 365
5bf23f 366         self._set_settings(settings)
CM 367
e6c2d2 368         if isinstance(debug_logger, string_types):
c1624c 369             debug_logger = logging.getLogger(debug_logger)
CM 370
5bf23f 371         if debug_logger is None:
CM 372             debug_logger = logging.getLogger(self.package_name)
012b97 373
5bf23f 374         registry.registerUtility(debug_logger, IDebugLogger)
CM 375
27190e 376         self.add_default_response_adapters()
b7e92d 377         self.add_default_renderers()
121f45 378         self.add_default_accept_view_order()
a00621 379         self.add_default_view_predicates()
ceb1f2 380         self.add_default_view_derivers()
9c8ec5 381         self.add_default_route_predicates()
35b0e3 382         self.add_default_tweens()
7c0f09 383         self.add_default_security()
a00621 384
5bf23f 385         if exceptionresponse_view is not None:
CM 386             exceptionresponse_view = self.maybe_dotted(exceptionresponse_view)
387             self.add_view(exceptionresponse_view, context=IExceptionResponse)
0c29cf 388             self.add_view(
MM 389                 exceptionresponse_view, context=WebobWSGIHTTPException
390             )
5bf23f 391
0ded4e 392         # commit below because:
CM 393         #
394         # - the default exceptionresponse_view requires the superdefault view
a54bc1 395         #   mapper, so we need to configure it before adding
MM 396         #   default_view_mapper
0ded4e 397         #
257f2c 398         # - superdefault renderers should be overrideable without requiring
0ded4e 399         #   the user to commit before calling config.add_renderer
ea824f 400
CM 401         self.commit()
402
27190e 403         # self.commit() should not be called within this method after this
CM 404         # point because the following registrations should be treated as
405         # analogues of methods called by the user after configurator
406         # construction.  Rationale: user-supplied implementations should be
407         # preferred rather than add-on author implementations with the help of
408         # automatic conflict resolution.
ea824f 409
66da9b 410         if authentication_policy and not authorization_policy:
0c29cf 411             authorization_policy = ACLAuthorizationPolicy()  # default
66da9b 412
ea824f 413         if authorization_policy:
CM 414             self.set_authorization_policy(authorization_policy)
637bda 415
eb2fee 416         if authentication_policy:
CM 417             self.set_authentication_policy(authentication_policy)
418
419         if default_view_mapper is not None:
420             self.set_view_mapper(default_view_mapper)
f67ba4 421
637bda 422         if renderers:
CM 423             for name, renderer in renderers:
424                 self.add_renderer(name, renderer)
cfbbd6 425
2a818a 426         if root_factory is not None:
CM 427             self.set_root_factory(root_factory)
ea824f 428
5bf23f 429         if locale_negotiator:
ea824f 430             self.set_locale_negotiator(locale_negotiator)
5bf23f 431
CM 432         if request_factory:
433             self.set_request_factory(request_factory)
434
1236de 435         if response_factory:
JA 436             self.set_response_factory(response_factory)
437
5bf23f 438         if default_permission:
CM 439             self.set_default_permission(default_permission)
440
441         if session_factory is not None:
442             self.set_session_factory(session_factory)
443
25c64c 444         tweens = aslist(registry.settings.get('pyramid.tweens', []))
5bf23f 445         for factory in tweens:
CM 446             self._add_tween(factory, explicit=True)
012b97 447
ea824f 448         includes = aslist(registry.settings.get('pyramid.includes', []))
CM 449         for inc in includes:
450             self.include(inc)
451
5bf23f 452     def _make_spec(self, path_or_spec):
79ef3d 453         package, filename = resolve_asset_spec(path_or_spec, self.package_name)
5bf23f 454         if package is None:
0c29cf 455             return filename  # absolute filename
5bf23f 456         return '%s:%s' % (package, filename)
CM 457
458     def _fix_registry(self):
459         """ Fix up a ZCA component registry that is not a
460         pyramid.registry.Registry by adding analogues of ``has_listeners``,
461         ``notify``, ``queryAdapterOrSelf``, and ``registerSelfAdapter``
462         through monkey-patching."""
463
464         _registry = self.registry
465
466         if not hasattr(_registry, 'notify'):
0c29cf 467
5bf23f 468             def notify(*events):
0c29cf 469                 [_ for _ in _registry.subscribers(events, None)]
MM 470
5bf23f 471             _registry.notify = notify
CM 472
473         if not hasattr(_registry, 'has_listeners'):
474             _registry.has_listeners = True
475
476         if not hasattr(_registry, 'queryAdapterOrSelf'):
0c29cf 477
5bf23f 478             def queryAdapterOrSelf(object, interface, default=None):
CM 479                 if not interface.providedBy(object):
0c29cf 480                     return _registry.queryAdapter(
MM 481                         object, interface, default=default
482                     )
5bf23f 483                 return object
0c29cf 484
5bf23f 485             _registry.queryAdapterOrSelf = queryAdapterOrSelf
CM 486
487         if not hasattr(_registry, 'registerSelfAdapter'):
0c29cf 488
MM 489             def registerSelfAdapter(
490                 required=None,
491                 provided=None,
492                 name=empty,
493                 info=empty,
494                 event=True,
495             ):
496                 return _registry.registerAdapter(
497                     lambda x: x,
498                     required=required,
499                     provided=provided,
500                     name=name,
501                     info=info,
502                     event=event,
503                 )
504
5bf23f 505             _registry.registerSelfAdapter = registerSelfAdapter
CM 506
c15cbc 507         if not hasattr(_registry, '_lock'):
CM 508             _registry._lock = threading.Lock()
509
510         if not hasattr(_registry, '_clear_view_lookup_cache'):
0c29cf 511
c15cbc 512             def _clear_view_lookup_cache():
CM 513                 _registry._view_lookup_cache = {}
514
0c29cf 515             _registry._clear_view_lookup_cache = _clear_view_lookup_cache
c15cbc 516
5bf23f 517     # API
1236de 518
e49638 519     def _get_introspector(self):
CM 520         introspector = getattr(self.registry, 'introspector', _marker)
521         if introspector is _marker:
522             introspector = Introspector()
523             self._set_introspector(introspector)
524         return introspector
525
526     def _set_introspector(self, introspector):
527         self.registry.introspector = introspector
528
529     def _del_introspector(self):
530         del self.registry.introspector
531
078859 532     introspector = property(
CM 533         _get_introspector, _set_introspector, _del_introspector
0c29cf 534     )
95f766 535
5bf23f 536     def include(self, callable, route_prefix=None):
f7c173 537         """Include a configuration callable, to support imperative
5bf23f 538         application extensibility.
CM 539
540         .. warning:: In versions of :app:`Pyramid` prior to 1.2, this
541             function accepted ``*callables``, but this has been changed
542             to support only a single callable.
543
544         A configuration callable should be a callable that accepts a single
545         argument named ``config``, which will be an instance of a
2e95ac 546         :term:`Configurator`.  However, be warned that it will not be the same
TL 547         configurator instance on which you call this method.  The
e09e08 548         code which runs as a result of calling the callable should invoke
5bf23f 549         methods on the configurator passed to it which add configuration
CM 550         state.  The return value of a callable will be ignored.
551
552         Values allowed to be presented via the ``callable`` argument to
553         this method: any callable Python object or any :term:`dotted Python
554         name` which resolves to a callable Python object.  It may also be a
555         Python :term:`module`, in which case, the module will be searched for
556         a callable named ``includeme``, which will be treated as the
557         configuration callable.
b86fa9 558
5bf23f 559         For example, if the ``includeme`` function below lives in a module
CM 560         named ``myapp.myconfig``:
561
562         .. code-block:: python
563            :linenos:
564
565            # myapp.myconfig module
566
567            def my_view(request):
568                from pyramid.response import Response
569                return Response('OK')
570
571            def includeme(config):
572                config.add_view(my_view)
573
026ac8 574         You might cause it to be included within your Pyramid application like
5bf23f 575         so:
CM 576
577         .. code-block:: python
578            :linenos:
579
580            from pyramid.config import Configurator
581
582            def main(global_config, **settings):
583                config = Configurator()
584                config.include('myapp.myconfig.includeme')
585
586         Because the function is named ``includeme``, the function name can
587         also be omitted from the dotted name reference:
588
589         .. code-block:: python
590            :linenos:
591
592            from pyramid.config import Configurator
593
594            def main(global_config, **settings):
595                config = Configurator()
596                config.include('myapp.myconfig')
597
598         Included configuration statements will be overridden by local
599         configuration statements if an included callable causes a
600         configuration conflict by registering something with the same
601         configuration parameters.
602
603         If the ``route_prefix`` is supplied, it must be a string.  Any calls
604         to :meth:`pyramid.config.Configurator.add_route` within the included
605         callable will have their pattern prefixed with the value of
606         ``route_prefix``. This can be used to help mount a set of routes at a
2e95ac 607         different location than the included callable's author intended, while
5bf23f 608         still maintaining the same route names.  For example:
012b97 609
5bf23f 610         .. code-block:: python
CM 611            :linenos:
612
613            from pyramid.config import Configurator
614
615            def included(config):
616                config.add_route('show_users', '/show')
012b97 617
5bf23f 618            def main(global_config, **settings):
CM 619                config = Configurator()
620                config.include(included, route_prefix='/users')
621
622         In the above configuration, the ``show_users`` route will have an
623         effective route pattern of ``/users/show``, instead of ``/show``
624         because the ``route_prefix`` argument will be prepended to the
625         pattern.
626
0b23b3 627         .. versionadded:: 1.2
TL 628            The ``route_prefix`` parameter.
629
f5ff7e 630         .. versionchanged:: 1.9
MM 631            The included function is wrapped with a call to
632            :meth:`pyramid.config.Configurator.begin` and
633            :meth:`pyramid.config.Configurator.end` while it is executed.
634
5bf23f 635         """
7a7c8c 636         # """ <-- emacs
5bf23f 637
b86fa9 638         action_state = self.action_state
5bf23f 639
CM 640         c = self.maybe_dotted(callable)
5ad401 641         module = self.inspect.getmodule(c)
5bf23f 642         if module is c:
f8bfc6 643             try:
CM 644                 c = getattr(module, 'includeme')
645             except AttributeError:
646                 raise ConfigurationError(
0c29cf 647                     "module %r has no attribute 'includeme'"
MM 648                     % (module.__name__)
649                 )
650
5bf23f 651         spec = module.__name__ + ':' + c.__name__
5ad401 652         sourcefile = self.inspect.getsourcefile(c)
CM 653
654         if sourcefile is None:
655             raise ConfigurationError(
656                 'No source file for module %r (.py file must exist, '
0c29cf 657                 'refusing to use orphan .pyc or .pyo file).' % module.__name__
MM 658             )
5bf23f 659
b86fa9 660         if action_state.processSpec(spec):
efd61e 661             with self.route_prefix_context(route_prefix):
HS 662                 configurator = self.__class__(
663                     registry=self.registry,
664                     package=package_of(module),
665                     root_package=self.root_package,
666                     autocommit=self.autocommit,
667                     route_prefix=self.route_prefix,
0c29cf 668                 )
efd61e 669                 configurator.basepath = os.path.dirname(sourcefile)
HS 670                 configurator.includepath = self.includepath + (spec,)
671
672                 self.begin()
673                 try:
674                     c(configurator)
675                 finally:
676                     self.end()
012b97 677
5bf23f 678     def add_directive(self, name, directive, action_wrap=True):
CM 679         """
680         Add a directive method to the configurator.
681
682         .. warning:: This method is typically only used by :app:`Pyramid`
683            framework extension authors, not by :app:`Pyramid` application
684            developers.
685
686         Framework extenders can add directive methods to a configurator by
687         instructing their users to call ``config.add_directive('somename',
688         'some.callable')``.  This will make ``some.callable`` accessible as
689         ``config.somename``.  ``some.callable`` should be a function which
690         accepts ``config`` as a first argument, and arbitrary positional and
691         keyword arguments following.  It should use config.action as
692         necessary to perform actions.  Directive methods can then be invoked
693         like 'built-in' directives such as ``add_view``, ``add_route``, etc.
694
695         The ``action_wrap`` argument should be ``True`` for directives which
696         perform ``config.action`` with potentially conflicting
697         discriminators.  ``action_wrap`` will cause the directive to be
698         wrapped in a decorator which provides more accurate conflict
699         cause information.
012b97 700
5bf23f 701         ``add_directive`` does not participate in conflict detection, and
CM 702         later calls to ``add_directive`` will override earlier calls.
703         """
704         c = self.maybe_dotted(directive)
705         if not hasattr(self.registry, '_directives'):
706             self.registry._directives = {}
707         self.registry._directives[name] = (c, action_wrap)
708
709     def __getattr__(self, name):
710         # allow directive extension names to work
711         directives = getattr(self.registry, '_directives', {})
712         c = directives.get(name)
713         if c is None:
714             raise AttributeError(name)
715         c, action_wrap = c
716         if action_wrap:
717             c = action_method(c)
c7cc88 718         # Create a bound method (works on both Py2 and Py3)
CM 719         # http://stackoverflow.com/a/1015405/209039
720         m = c.__get__(self, self.__class__)
5bf23f 721         return m
CM 722
723     def with_package(self, package):
724         """ Return a new Configurator instance with the same registry
80281d 725         as this configurator. ``package`` may be an actual Python package
TL 726         object or a :term:`dotted Python name` representing a package."""
b86fa9 727         configurator = self.__class__(
CM 728             registry=self.registry,
729             package=package,
ae6c88 730             root_package=self.root_package,
b86fa9 731             autocommit=self.autocommit,
CM 732             route_prefix=self.route_prefix,
844ed9 733             introspection=self.introspection,
0c29cf 734         )
b86fa9 735         configurator.basepath = self.basepath
CM 736         configurator.includepath = self.includepath
737         configurator.info = self.info
738         return configurator
5bf23f 739
CM 740     def maybe_dotted(self, dotted):
741         """ Resolve the :term:`dotted Python name` ``dotted`` to a
742         global Python object.  If ``dotted`` is not a string, return
743         it without attempting to do any name resolution.  If
744         ``dotted`` is a relative dotted name (e.g. ``.foo.bar``,
745         consider it relative to the ``package`` argument supplied to
746         this Configurator's constructor."""
747         return self.name_resolver.maybe_resolve(dotted)
748
749     def absolute_asset_spec(self, relative_spec):
750         """ Resolve the potentially relative :term:`asset
751         specification` string passed as ``relative_spec`` into an
752         absolute asset specification string and return the string.
753         Use the ``package`` of this configurator as the package to
754         which the asset specification will be considered relative
755         when generating an absolute asset specification.  If the
756         provided ``relative_spec`` argument is already absolute, or if
757         the ``relative_spec`` is not a string, it is simply returned."""
e6c2d2 758         if not isinstance(relative_spec, string_types):
5bf23f 759             return relative_spec
CM 760         return self._make_spec(relative_spec)
761
0c29cf 762     absolute_resource_spec = absolute_asset_spec  # b/w compat forever
5bf23f 763
804eb0 764     def begin(self, request=_marker):
5bf23f 765         """ Indicate that application or test configuration has begun.
CM 766         This pushes a dictionary containing the :term:`application
767         registry` implied by ``registry`` attribute of this
768         configurator and the :term:`request` implied by the
f271a6 769         ``request`` argument onto the :term:`thread local` stack
5bf23f 770         consulted by various :mod:`pyramid.threadlocal` API
804eb0 771         functions.
MM 772
773         If ``request`` is not specified and the registry owned by the
774         configurator is already pushed as the current threadlocal registry
775         then this method will keep the current threadlocal request unchanged.
776
777         .. versionchanged:: 1.8
778            The current threadlocal request is propagated if the current
779            threadlocal registry remains unchanged.
780
781         """
782         if request is _marker:
783             current = self.manager.get()
784             if current['registry'] == self.registry:
785                 request = current['request']
786             else:
787                 request = None
0c29cf 788         self.manager.push({'registry': self.registry, 'request': request})
5bf23f 789
CM 790     def end(self):
791         """ Indicate that application or test configuration has ended.
f271a6 792         This pops the last value pushed onto the :term:`thread local`
5bf23f 793         stack (usually by the ``begin`` method) and returns that
CM 794         value.
795         """
796         return self.manager.pop()
797
134ef7 798     def __enter__(self):
MM 799         self.begin()
800         return self
801
802     def __exit__(self, exc_type, exc_value, exc_traceback):
803         self.end()
804
805         if exc_value is None:
806             self.commit()
807
5bf23f 808     # this is *not* an action method (uses caller_package)
0c29cf 809     def scan(
MM 810         self, package=None, categories=None, onerror=None, ignore=None, **kw
811     ):
5bf23f 812         """Scan a Python package and any of its subpackages for objects
CM 813         marked with :term:`configuration decoration` such as
814         :class:`pyramid.view.view_config`.  Any decorated object found will
815         influence the current configuration state.
816
817         The ``package`` argument should be a Python :term:`package` or module
818         object (or a :term:`dotted Python name` which refers to such a
819         package or module).  If ``package`` is ``None``, the package of the
820         *caller* is used.
821
822         The ``categories`` argument, if provided, should be the
823         :term:`Venusian` 'scan categories' to use during scanning.  Providing
824         this argument is not often necessary; specifying scan categories is
825         an extremely advanced usage.  By default, ``categories`` is ``None``
826         which will execute *all* Venusian decorator callbacks including
827         :app:`Pyramid`-related decorators such as
828         :class:`pyramid.view.view_config`.  See the :term:`Venusian`
829         documentation for more information about limiting a scan by using an
830         explicit set of categories.
831
1aeae3 832         The ``onerror`` argument, if provided, should be a Venusian
CM 833         ``onerror`` callback function.  The onerror function is passed to
834         :meth:`venusian.Scanner.scan` to influence error behavior when an
835         exception is raised during the scanning process.  See the
836         :term:`Venusian` documentation for more information about ``onerror``
837         callbacks.
838
e4b8fa 839         The ``ignore`` argument, if provided, should be a Venusian ``ignore``
CM 840         value.  Providing an ``ignore`` argument allows the scan to ignore
841         particular modules, packages, or global objects during a scan.
842         ``ignore`` can be a string or a callable, or a list containing
843         strings or callables.  The simplest usage of ``ignore`` is to provide
844         a module or package by providing a full path to its dotted name.  For
845         example: ``config.scan(ignore='my.module.subpackage')`` would ignore
846         the ``my.module.subpackage`` package during a scan, which would
847         prevent the subpackage and any of its submodules from being imported
848         and scanned.  See the :term:`Venusian` documentation for more
849         information about the ``ignore`` argument.
850
5bf23f 851         To perform a ``scan``, Pyramid creates a Venusian ``Scanner`` object.
CM 852         The ``kw`` argument represents a set of keyword arguments to pass to
853         the Venusian ``Scanner`` object's constructor.  See the
854         :term:`venusian` documentation (its ``Scanner`` class) for more
855         information about the constructor.  By default, the only keyword
856         arguments passed to the Scanner constructor are ``{'config':self}``
857         where ``self`` is this configurator object.  This services the
858         requirement of all built-in Pyramid decorators, but extension systems
859         may require additional arguments.  Providing this argument is not
860         often necessary; it's an advanced usage.
861
0b23b3 862         .. versionadded:: 1.1
TL 863            The ``**kw`` argument.
864
865         .. versionadded:: 1.3
866            The ``ignore`` argument.
867
5bf23f 868         """
CM 869         package = self.maybe_dotted(package)
0c29cf 870         if package is None:  # pragma: no cover
5bf23f 871             package = caller_package()
CM 872
25c64c 873         ctorkw = {'config': self}
1aeae3 874         ctorkw.update(kw)
5bf23f 875
1aeae3 876         scanner = self.venusian.Scanner(**ctorkw)
25c64c 877
0c29cf 878         scanner.scan(
MM 879             package, categories=categories, onerror=onerror, ignore=ignore
880         )
5bf23f 881
CM 882     def make_wsgi_app(self):
883         """ Commits any pending configuration statements, sends a
884         :class:`pyramid.events.ApplicationCreated` event to all listeners,
885         adds this configuration's registry to
886         :attr:`pyramid.config.global_registries`, and returns a
887         :app:`Pyramid` WSGI application representing the committed
888         configuration state."""
889         self.commit()
890         app = Router(self.registry)
cfbbd6 891
cfb2b5 892         # Allow tools like "pshell development.ini" to find the 'last'
cfbbd6 893         # registry configured.
5bf23f 894         global_registries.add(self.registry)
cfbbd6 895
f271a6 896         # Push the registry onto the stack in case any code that depends on
cfbbd6 897         # the registry threadlocal APIs used in listeners subscribed to the
CM 898         # IApplicationCreated event.
0c1c58 899         self.begin()
5bf23f 900         try:
CM 901             self.registry.notify(ApplicationCreated(app))
902         finally:
0c1c58 903             self.end()
5bf23f 904
CM 905         return app
79ef3d 906
0f9a56 907
5bf23f 908 global_registries = WeakOrderedSet()