Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/pyramid/config/__init__.py : 68%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import inspect
2import logging
3import os
4import threading
5import venusian
7from webob.exc import WSGIHTTPException as WebobWSGIHTTPException
9from pyramid.interfaces import (
10 IDebugLogger,
11 IExceptionResponse,
12 PHASE0_CONFIG,
13 PHASE1_CONFIG,
14 PHASE2_CONFIG,
15 PHASE3_CONFIG,
16)
18from pyramid.asset import resolve_asset_spec
20from pyramid.authorization import ACLAuthorizationPolicy
22from pyramid.compat import text_, string_types
24from pyramid.events import ApplicationCreated
26from pyramid.exceptions import ConfigurationError
28from pyramid.httpexceptions import default_exceptionresponse_view
30from pyramid.path import caller_package, package_of
32from pyramid.registry import Introspectable, Introspector, Registry
34from pyramid.router import Router
36from pyramid.settings import aslist
38from pyramid.threadlocal import manager
40from pyramid.util import WeakOrderedSet, object_description
42from pyramid.config.actions import action_method, ActionState
43from pyramid.config.predicates import not_
45from pyramid.config.actions import ActionConfiguratorMixin
46from pyramid.config.adapters import AdaptersConfiguratorMixin
47from pyramid.config.assets import AssetsConfiguratorMixin
48from pyramid.config.factories import FactoriesConfiguratorMixin
49from pyramid.config.i18n import I18NConfiguratorMixin
50from pyramid.config.predicates import PredicateConfiguratorMixin
51from pyramid.config.rendering import RenderingConfiguratorMixin
52from pyramid.config.routes import RoutesConfiguratorMixin
53from pyramid.config.security import SecurityConfiguratorMixin
54from pyramid.config.settings import SettingsConfiguratorMixin
55from pyramid.config.testing import TestingConfiguratorMixin
56from pyramid.config.tweens import TweensConfiguratorMixin
57from pyramid.config.views import ViewsConfiguratorMixin
58from pyramid.config.zca import ZCAConfiguratorMixin
60from pyramid.path import DottedNameResolver
62empty = text_('')
63_marker = object()
65not_ = not_ # api
67PHASE0_CONFIG = PHASE0_CONFIG # api
68PHASE1_CONFIG = PHASE1_CONFIG # api
69PHASE2_CONFIG = PHASE2_CONFIG # api
70PHASE3_CONFIG = PHASE3_CONFIG # api
72ActionState = ActionState # bw-compat for pyramid_zcml
75class Configurator(
76 ActionConfiguratorMixin,
77 PredicateConfiguratorMixin,
78 TestingConfiguratorMixin,
79 TweensConfiguratorMixin,
80 SecurityConfiguratorMixin,
81 ViewsConfiguratorMixin,
82 RoutesConfiguratorMixin,
83 ZCAConfiguratorMixin,
84 I18NConfiguratorMixin,
85 RenderingConfiguratorMixin,
86 AssetsConfiguratorMixin,
87 SettingsConfiguratorMixin,
88 FactoriesConfiguratorMixin,
89 AdaptersConfiguratorMixin,
90):
91 """
92 A Configurator is used to configure a :app:`Pyramid`
93 :term:`application registry`.
95 The Configurator lifecycle can be managed by using a context manager to
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`.
100 .. code-block:: python
102 with Configurator(settings=settings) as config:
103 config.add_route('home', '/')
104 app = config.make_wsgi_app()
106 If the ``registry`` argument is not ``None``, it must
107 be an instance of the :class:`pyramid.registry.Registry` class
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.
114 .. warning:: If ``registry`` is assigned the above-mentioned class
115 instance, all other constructor arguments are ignored,
116 with the exception of ``package``.
118 If the ``package`` argument is passed, it must be a reference to a Python
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.
126 If the ``root_package`` is passed, it will propagate through the
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.
134 If the ``settings`` argument is passed, it should be a Python dictionary
135 representing the :term:`deployment settings` for this application. These
136 are later retrievable using the
137 :attr:`pyramid.registry.Registry.settings` attribute (aka
138 ``request.registry.settings``).
140 If the ``root_factory`` argument is passed, it should be an object
141 representing the default :term:`root factory` for your application or a
142 :term:`dotted Python name` to the same. If it is ``None``, a default
143 root factory will be used.
145 If ``authentication_policy`` is passed, it should be an instance
146 of an :term:`authentication policy` or a :term:`dotted Python
147 name` to the same.
149 If ``authorization_policy`` is passed, it should be an instance of
150 an :term:`authorization policy` or a :term:`dotted Python name` to
151 the same.
153 .. note:: A ``ConfigurationError`` will be raised when an
154 authorization policy is supplied without also supplying an
155 authentication policy (authorization requires authentication).
157 If ``renderers`` is ``None`` (the default), a default set of
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
161 positional values that should be passed to
162 :meth:`pyramid.config.Configurator.add_renderer`.
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.
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`.
175 If ``request_factory`` is passed, it should be a :term:`request
176 factory` implementation or a :term:`dotted Python name` to the same.
177 See :ref:`changing_the_request_factory`. By default it is ``None``,
178 which means use the default request factory.
180 If ``response_factory`` is passed, it should be a :term:`response
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.
185 If ``default_permission`` is passed, it should be a
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
195 authorization policy in effect is ignored).
197 .. seealso::
199 See also :ref:`setting_a_default_permission`.
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.
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
219 ``autocommit`` is ``True``. If a conflict is detected, a
220 ``ConfigurationConflictError`` will be raised. Calling
221 :meth:`pyramid.config.Configurator.make_wsgi_app` always implies a final
222 commit.
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
226 specify one (see :class:`pyramid.interfaces.IViewMapperFactory`). If
227 ``default_view_mapper`` is not passed, a superdefault view mapper will be
228 used.
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``
237 function is used as the ``exceptionresponse_view``.
239 If ``route_prefix`` is passed, all routes added with
240 :meth:`pyramid.config.Configurator.add_route` will have the specified path
241 prepended to their pattern.
243 If ``introspection`` is passed, it must be a boolean value. If it's
244 ``True``, introspection values during actions will be kept for use
245 for tools like the debug toolbar. If it's ``False``, introspection
246 values provided by registrations will be ignored. By default, it is
247 ``True``.
249 .. versionadded:: 1.1
250 The ``exceptionresponse_view`` argument.
252 .. versionadded:: 1.2
253 The ``route_prefix`` argument.
255 .. versionadded:: 1.3
256 The ``introspection`` argument.
258 .. versionadded:: 1.6
259 The ``root_package`` argument.
260 The ``response_factory`` argument.
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.
266 """
268 manager = manager # for testing injection
269 venusian = venusian # for testing injection
270 _ainfo = None
271 basepath = None
272 includepath = ()
273 info = ''
274 object_description = staticmethod(object_description)
275 introspectable = Introspectable
276 inspect = inspect
278 def __init__(
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 ):
300 if package is None:
301 package = caller_package()
302 if root_package is None:
303 root_package = package
304 name_resolver = DottedNameResolver(package)
305 self.name_resolver = name_resolver
306 self.package_name = name_resolver.get_package_name()
307 self.package = name_resolver.get_package()
308 self.root_package = root_package
309 self.registry = registry
310 self.autocommit = autocommit
311 self.route_prefix = route_prefix
312 self.introspection = introspection
313 if registry is None:
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,
325 response_factory=response_factory,
326 default_permission=default_permission,
327 session_factory=session_factory,
328 default_view_mapper=default_view_mapper,
329 exceptionresponse_view=exceptionresponse_view,
330 )
332 def setup_registry(
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 ):
348 """ When you pass a non-``None`` ``registry`` argument to the
349 :term:`Configurator` constructor, no initial setup is performed
350 against the registry. This is because the registry you pass in may
351 have already been initialized for use under :app:`Pyramid` via a
352 different configurator. However, in some circumstances (such as when
353 you want to use a global registry instead of a registry created as a
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.
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."""
364 registry = self.registry
366 self._fix_registry()
368 self._set_settings(settings)
370 if isinstance(debug_logger, string_types):
371 debug_logger = logging.getLogger(debug_logger)
373 if debug_logger is None:
374 debug_logger = logging.getLogger(self.package_name)
376 registry.registerUtility(debug_logger, IDebugLogger)
378 self.add_default_response_adapters()
379 self.add_default_renderers()
380 self.add_default_accept_view_order()
381 self.add_default_view_predicates()
382 self.add_default_view_derivers()
383 self.add_default_route_predicates()
384 self.add_default_tweens()
385 self.add_default_security()
387 if exceptionresponse_view is not None:
388 exceptionresponse_view = self.maybe_dotted(exceptionresponse_view)
389 self.add_view(exceptionresponse_view, context=IExceptionResponse)
390 self.add_view(
391 exceptionresponse_view, context=WebobWSGIHTTPException
392 )
394 # commit below because:
395 #
396 # - the default exceptionresponse_view requires the superdefault view
397 # mapper, so we need to configure it before adding
398 # default_view_mapper
399 #
400 # - superdefault renderers should be overrideable without requiring
401 # the user to commit before calling config.add_renderer
403 self.commit()
405 # self.commit() should not be called within this method after this
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.
412 if authentication_policy and not authorization_policy:
413 authorization_policy = ACLAuthorizationPolicy() # default
415 if authorization_policy:
416 self.set_authorization_policy(authorization_policy)
418 if authentication_policy:
419 self.set_authentication_policy(authentication_policy)
421 if default_view_mapper is not None:
422 self.set_view_mapper(default_view_mapper)
424 if renderers:
425 for name, renderer in renderers:
426 self.add_renderer(name, renderer)
428 if root_factory is not None:
429 self.set_root_factory(root_factory)
431 if locale_negotiator:
432 self.set_locale_negotiator(locale_negotiator)
434 if request_factory:
435 self.set_request_factory(request_factory)
437 if response_factory:
438 self.set_response_factory(response_factory)
440 if default_permission:
441 self.set_default_permission(default_permission)
443 if session_factory is not None:
444 self.set_session_factory(session_factory)
446 tweens = aslist(registry.settings.get('pyramid.tweens', []))
447 for factory in tweens:
448 self._add_tween(factory, explicit=True)
450 includes = aslist(registry.settings.get('pyramid.includes', []))
451 for inc in includes:
452 self.include(inc)
454 def _make_spec(self, path_or_spec):
455 package, filename = resolve_asset_spec(path_or_spec, self.package_name)
456 if package is None:
457 return filename # absolute filename
458 return '%s:%s' % (package, filename)
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."""
466 _registry = self.registry
468 if not hasattr(_registry, 'notify'):
470 def notify(*events):
471 [_ for _ in _registry.subscribers(events, None)]
473 _registry.notify = notify
475 if not hasattr(_registry, 'has_listeners'):
476 _registry.has_listeners = True
478 if not hasattr(_registry, 'queryAdapterOrSelf'):
480 def queryAdapterOrSelf(object, interface, default=None):
481 if not interface.providedBy(object):
482 return _registry.queryAdapter(
483 object, interface, default=default
484 )
485 return object
487 _registry.queryAdapterOrSelf = queryAdapterOrSelf
489 if not hasattr(_registry, 'registerSelfAdapter'):
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 )
507 _registry.registerSelfAdapter = registerSelfAdapter
509 if not hasattr(_registry, '_lock'):
510 _registry._lock = threading.Lock()
512 if not hasattr(_registry, '_clear_view_lookup_cache'):
514 def _clear_view_lookup_cache():
515 _registry._view_lookup_cache = {}
517 _registry._clear_view_lookup_cache = _clear_view_lookup_cache
519 # API
521 def _get_introspector(self):
522 introspector = getattr(self.registry, 'introspector', _marker)
523 if introspector is _marker:
524 introspector = Introspector()
525 self._set_introspector(introspector)
526 return introspector
528 def _set_introspector(self, introspector):
529 self.registry.introspector = introspector
531 def _del_introspector(self):
532 del self.registry.introspector
534 introspector = property(
535 _get_introspector, _set_introspector, _del_introspector
536 )
538 def include(self, callable, route_prefix=None):
539 """Include a configuration callable, to support imperative
540 application extensibility.
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.
546 A configuration callable should be a callable that accepts a single
547 argument named ``config``, which will be an instance of a
548 :term:`Configurator`. However, be warned that it will not be the same
549 configurator instance on which you call this method. The
550 code which runs as a result of calling the callable should invoke
551 methods on the configurator passed to it which add configuration
552 state. The return value of a callable will be ignored.
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.
561 For example, if the ``includeme`` function below lives in a module
562 named ``myapp.myconfig``:
564 .. code-block:: python
565 :linenos:
567 # myapp.myconfig module
569 def my_view(request):
570 from pyramid.response import Response
571 return Response('OK')
573 def includeme(config):
574 config.add_view(my_view)
576 You might cause it to be included within your Pyramid application like
577 so:
579 .. code-block:: python
580 :linenos:
582 from pyramid.config import Configurator
584 def main(global_config, **settings):
585 config = Configurator()
586 config.include('myapp.myconfig.includeme')
588 Because the function is named ``includeme``, the function name can
589 also be omitted from the dotted name reference:
591 .. code-block:: python
592 :linenos:
594 from pyramid.config import Configurator
596 def main(global_config, **settings):
597 config = Configurator()
598 config.include('myapp.myconfig')
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.
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
609 different location than the included callable's author intended, while
610 still maintaining the same route names. For example:
612 .. code-block:: python
613 :linenos:
615 from pyramid.config import Configurator
617 def included(config):
618 config.add_route('show_users', '/show')
620 def main(global_config, **settings):
621 config = Configurator()
622 config.include(included, route_prefix='/users')
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.
629 .. versionadded:: 1.2
630 The ``route_prefix`` parameter.
632 .. versionchanged:: 1.9
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.
637 """
638 # """ <-- emacs
640 action_state = self.action_state
642 c = self.maybe_dotted(callable)
643 module = self.inspect.getmodule(c)
644 if module is c:
645 try:
646 c = getattr(module, 'includeme')
647 except AttributeError:
648 raise ConfigurationError(
649 "module %r has no attribute 'includeme'"
650 % (module.__name__)
651 )
653 spec = module.__name__ + ':' + c.__name__
654 sourcefile = self.inspect.getsourcefile(c)
656 if sourcefile is None:
657 raise ConfigurationError(
658 'No source file for module %r (.py file must exist, '
659 'refusing to use orphan .pyc or .pyo file).' % module.__name__
660 )
662 if action_state.processSpec(spec):
663 with self.route_prefix_context(route_prefix):
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,
670 )
671 configurator.basepath = os.path.dirname(sourcefile)
672 configurator.includepath = self.includepath + (spec,)
674 self.begin()
675 try:
676 c(configurator)
677 finally:
678 self.end()
680 def add_directive(self, name, directive, action_wrap=True):
681 """
682 Add a directive method to the configurator.
684 .. warning:: This method is typically only used by :app:`Pyramid`
685 framework extension authors, not by :app:`Pyramid` application
686 developers.
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.
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.
703 ``add_directive`` does not participate in conflict detection, and
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)
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)
720 # Create a bound method (works on both Py2 and Py3)
721 # http://stackoverflow.com/a/1015405/209039
722 m = c.__get__(self, self.__class__)
723 return m
725 def with_package(self, package):
726 """ Return a new Configurator instance with the same registry
727 as this configurator. ``package`` may be an actual Python package
728 object or a :term:`dotted Python name` representing a package."""
729 configurator = self.__class__(
730 registry=self.registry,
731 package=package,
732 root_package=self.root_package,
733 autocommit=self.autocommit,
734 route_prefix=self.route_prefix,
735 introspection=self.introspection,
736 )
737 configurator.basepath = self.basepath
738 configurator.includepath = self.includepath
739 configurator.info = self.info
740 return configurator
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)
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."""
760 if not isinstance(relative_spec, string_types):
761 return relative_spec
762 return self._make_spec(relative_spec)
764 absolute_resource_spec = absolute_asset_spec # b/w compat forever
766 def begin(self, request=_marker):
767 """ Indicate that application or test configuration has begun.
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
771 ``request`` argument onto the :term:`thread local` stack
772 consulted by various :mod:`pyramid.threadlocal` API
773 functions.
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.
779 .. versionchanged:: 1.8
780 The current threadlocal request is propagated if the current
781 threadlocal registry remains unchanged.
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
790 self.manager.push({'registry': self.registry, 'request': request})
792 def end(self):
793 """ Indicate that application or test configuration has ended.
794 This pops the last value pushed onto the :term:`thread local`
795 stack (usually by the ``begin`` method) and returns that
796 value.
797 """
798 return self.manager.pop()
800 def __enter__(self):
801 self.begin()
802 return self
804 def __exit__(self, exc_type, exc_value, exc_traceback):
805 self.end()
807 if exc_value is None:
808 self.commit()
810 # this is *not* an action method (uses caller_package)
811 def scan(
812 self, package=None, categories=None, onerror=None, ignore=None, **kw
813 ):
814 """Scan a Python package and any of its subpackages for objects
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.
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.
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.
834 The ``onerror`` argument, if provided, should be a Venusian
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.
841 The ``ignore`` argument, if provided, should be a Venusian ``ignore``
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.
853 To perform a ``scan``, Pyramid creates a Venusian ``Scanner`` object.
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.
864 .. versionadded:: 1.1
865 The ``**kw`` argument.
867 .. versionadded:: 1.3
868 The ``ignore`` argument.
870 """
871 package = self.maybe_dotted(package)
872 if package is None: # pragma: no cover
873 package = caller_package()
875 ctorkw = {'config': self}
876 ctorkw.update(kw)
878 scanner = self.venusian.Scanner(**ctorkw)
880 scanner.scan(
881 package, categories=categories, onerror=onerror, ignore=ignore
882 )
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)
894 # Allow tools like "pshell development.ini" to find the 'last'
895 # registry configured.
896 global_registries.add(self.registry)
898 # Push the registry onto the stack in case any code that depends on
899 # the registry threadlocal APIs used in listeners subscribed to the
900 # IApplicationCreated event.
901 self.begin()
902 try:
903 self.registry.notify(ApplicationCreated(app))
904 finally:
905 self.end()
907 return app
910global_registries = WeakOrderedSet()