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