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