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() |