Hide keyboard shortcuts

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 

6 

7from webob.exc import WSGIHTTPException as WebobWSGIHTTPException 

8 

9from pyramid.interfaces import ( 

10 IDebugLogger, 

11 IExceptionResponse, 

12 PHASE0_CONFIG, 

13 PHASE1_CONFIG, 

14 PHASE2_CONFIG, 

15 PHASE3_CONFIG, 

16) 

17 

18from pyramid.asset import resolve_asset_spec 

19 

20from pyramid.authorization import ACLAuthorizationPolicy 

21 

22from pyramid.compat import text_, string_types 

23 

24from pyramid.events import ApplicationCreated 

25 

26from pyramid.exceptions import ConfigurationError 

27 

28from pyramid.httpexceptions import default_exceptionresponse_view 

29 

30from pyramid.path import caller_package, package_of 

31 

32from pyramid.registry import Introspectable, Introspector, Registry 

33 

34from pyramid.router import Router 

35 

36from pyramid.settings import aslist 

37 

38from pyramid.threadlocal import manager 

39 

40from pyramid.util import WeakOrderedSet, object_description 

41 

42from pyramid.config.actions import action_method, ActionState 

43from pyramid.config.predicates import not_ 

44 

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 

59 

60from pyramid.path import DottedNameResolver 

61 

62empty = text_('') 

63_marker = object() 

64 

65not_ = not_ # api 

66 

67PHASE0_CONFIG = PHASE0_CONFIG # api 

68PHASE1_CONFIG = PHASE1_CONFIG # api 

69PHASE2_CONFIG = PHASE2_CONFIG # api 

70PHASE3_CONFIG = PHASE3_CONFIG # api 

71 

72ActionState = ActionState # bw-compat for pyramid_zcml 

73 

74 

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`. 

94 

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`. 

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 

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. 

113 

114 .. warning:: If ``registry`` is assigned the above-mentioned class 

115 instance, all other constructor arguments are ignored, 

116 with the exception of ``package``. 

117 

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. 

125 

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. 

133 

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``). 

139 

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. 

144 

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. 

148 

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. 

152 

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 

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`. 

163 

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 

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. 

179 

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. 

184 

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

196 

197 .. seealso:: 

198 

199 See also :ref:`setting_a_default_permission`. 

200 

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 

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. 

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 

226 specify one (see :class:`pyramid.interfaces.IViewMapperFactory`). If 

227 ``default_view_mapper`` is not passed, a superdefault view mapper will be 

228 used. 

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`` 

237 function is used as the ``exceptionresponse_view``. 

238 

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. 

242 

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``. 

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. 

257 

258 .. versionadded:: 1.6 

259 The ``root_package`` argument. 

260 The ``response_factory`` argument. 

261 

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 """ 

267 

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 

277 

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 ) 

331 

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. 

358 

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.""" 

363 

364 registry = self.registry 

365 

366 self._fix_registry() 

367 

368 self._set_settings(settings) 

369 

370 if isinstance(debug_logger, string_types): 

371 debug_logger = logging.getLogger(debug_logger) 

372 

373 if debug_logger is None: 

374 debug_logger = logging.getLogger(self.package_name) 

375 

376 registry.registerUtility(debug_logger, IDebugLogger) 

377 

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

386 

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 ) 

393 

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 

402 

403 self.commit() 

404 

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. 

411 

412 if authentication_policy and not authorization_policy: 

413 authorization_policy = ACLAuthorizationPolicy() # default 

414 

415 if authorization_policy: 

416 self.set_authorization_policy(authorization_policy) 

417 

418 if authentication_policy: 

419 self.set_authentication_policy(authentication_policy) 

420 

421 if default_view_mapper is not None: 

422 self.set_view_mapper(default_view_mapper) 

423 

424 if renderers: 

425 for name, renderer in renderers: 

426 self.add_renderer(name, renderer) 

427 

428 if root_factory is not None: 

429 self.set_root_factory(root_factory) 

430 

431 if locale_negotiator: 

432 self.set_locale_negotiator(locale_negotiator) 

433 

434 if request_factory: 

435 self.set_request_factory(request_factory) 

436 

437 if response_factory: 

438 self.set_response_factory(response_factory) 

439 

440 if default_permission: 

441 self.set_default_permission(default_permission) 

442 

443 if session_factory is not None: 

444 self.set_session_factory(session_factory) 

445 

446 tweens = aslist(registry.settings.get('pyramid.tweens', [])) 

447 for factory in tweens: 

448 self._add_tween(factory, explicit=True) 

449 

450 includes = aslist(registry.settings.get('pyramid.includes', [])) 

451 for inc in includes: 

452 self.include(inc) 

453 

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) 

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'): 

469 

470 def notify(*events): 

471 [_ for _ in _registry.subscribers(events, None)] 

472 

473 _registry.notify = notify 

474 

475 if not hasattr(_registry, 'has_listeners'): 

476 _registry.has_listeners = True 

477 

478 if not hasattr(_registry, 'queryAdapterOrSelf'): 

479 

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 

486 

487 _registry.queryAdapterOrSelf = queryAdapterOrSelf 

488 

489 if not hasattr(_registry, 'registerSelfAdapter'): 

490 

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 

507 _registry.registerSelfAdapter = registerSelfAdapter 

508 

509 if not hasattr(_registry, '_lock'): 

510 _registry._lock = threading.Lock() 

511 

512 if not hasattr(_registry, '_clear_view_lookup_cache'): 

513 

514 def _clear_view_lookup_cache(): 

515 _registry._view_lookup_cache = {} 

516 

517 _registry._clear_view_lookup_cache = _clear_view_lookup_cache 

518 

519 # API 

520 

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 

527 

528 def _set_introspector(self, introspector): 

529 self.registry.introspector = introspector 

530 

531 def _del_introspector(self): 

532 del self.registry.introspector 

533 

534 introspector = property( 

535 _get_introspector, _set_introspector, _del_introspector 

536 ) 

537 

538 def include(self, callable, route_prefix=None): 

539 """Include a configuration callable, to support imperative 

540 application extensibility. 

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 

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. 

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. 

560 

561 For example, if the ``includeme`` function below lives in a module 

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 

576 You might cause it to be included within your Pyramid application like 

577 so: 

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 

609 different location than the included callable's author intended, while 

610 still maintaining the same route names. For example: 

611 

612 .. code-block:: python 

613 :linenos: 

614 

615 from pyramid.config import Configurator 

616 

617 def included(config): 

618 config.add_route('show_users', '/show') 

619 

620 def main(global_config, **settings): 

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 

629 .. versionadded:: 1.2 

630 The ``route_prefix`` parameter. 

631 

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. 

636 

637 """ 

638 # """ <-- emacs 

639 

640 action_state = self.action_state 

641 

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 ) 

652 

653 spec = module.__name__ + ':' + c.__name__ 

654 sourcefile = self.inspect.getsourcefile(c) 

655 

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 ) 

661 

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

673 

674 self.begin() 

675 try: 

676 c(configurator) 

677 finally: 

678 self.end() 

679 

680 def add_directive(self, name, directive, action_wrap=True): 

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. 

702 

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) 

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) 

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 

724 

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 

741 

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.""" 

760 if not isinstance(relative_spec, string_types): 

761 return relative_spec 

762 return self._make_spec(relative_spec) 

763 

764 absolute_resource_spec = absolute_asset_spec # b/w compat forever 

765 

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. 

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 

790 self.manager.push({'registry': self.registry, 'request': request}) 

791 

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

799 

800 def __enter__(self): 

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 

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. 

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 

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. 

840 

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. 

852 

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. 

863 

864 .. versionadded:: 1.1 

865 The ``**kw`` argument. 

866 

867 .. versionadded:: 1.3 

868 The ``ignore`` argument. 

869 

870 """ 

871 package = self.maybe_dotted(package) 

872 if package is None: # pragma: no cover 

873 package = caller_package() 

874 

875 ctorkw = {'config': self} 

876 ctorkw.update(kw) 

877 

878 scanner = self.venusian.Scanner(**ctorkw) 

879 

880 scanner.scan( 

881 package, categories=categories, onerror=onerror, ignore=ignore 

882 ) 

883 

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) 

893 

894 # Allow tools like "pshell development.ini" to find the 'last' 

895 # registry configured. 

896 global_registries.add(self.registry) 

897 

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

906 

907 return app 

908 

909 

910global_registries = WeakOrderedSet()