# Pyramid events tracing ###### tags: `SED` In the module, event, there are a [subsciber](#Subscriber) class and six [event types](#[EventType]). ContextFound is assigned as AfterTraversal ApplicationCreated is assigned as WSGIApplicationCreatedEvent ```graphviz digraph hierarchy { node [shape=record] Sub[label="{ Subscriber| -venusian: venusian\l -ifcas\l -predicates\l -depth\l -category\l | +__init__()\l +register()\l +call()\l }"] Sub->venusian[arrowhead=vee] } ``` ```graphviz digraph hierarchy { node [shape=record] Irequest[label="{ \<\<interface\>\>\nINewRequest }"] request[label="{ NewRequest| -request\l| +__init__()\l }"] Irequest->request[dir=back, style=dashed, arrowtail=onormal] Iresponse[label="{ \<\<interface\>\>\nINewResponse }"] response[label="{ NewResponse| -request\l -response\l| +__init__()\l }"] Iresponse->response[dir=back, style=dashed, arrowtail=onormal] Itraverse[label="{ \<\<interface\>\>\nIBeforeTraversal }"] traverse[label="{ BeforeTraversal| -request\l| +__init__()\l }"] Itraverse->traverse[dir=back, style=dashed, arrowtail=onormal] } ``` ```graphviz digraph hierarchy { node [shape=record] Icontext[label="{ \<\<interface\>\>\nIContextFound }"] context[label="{ ContextFound| -request\l| +__init__()\l }"] Icontext->context[dir=back, style=dashed, arrowtail=onormal] Iapp[label="{ \<\<interface\>\>\nIApplicationCreated }"] app[label="{ ApplicationCreated| -app\l -object\l| +__init__()\l }"] Iapp->app[dir=back, style=dashed, arrowtail=onormal] Irender[label="{ \<\<interface\>\>\nIBeforeRender }"] render[label="{ BeforeRender| -dict\l -render_val\l| +__init__()\l }"] Irender->render[dir=back, style=dashed, arrowtail=onormal] } ``` ## Who called events? ### Router ```graphviz digraph hierarchy { node [shape=record] router[label="{ Router| -registry\l| +handle_request()\l +invoke_request()\l }"] router->ContextFound[style=dashed, arrowhead=vee, label="<<use>>"] router->NewRequest[style=dashed, arrowhead=vee, label="<<use>>"] router->NewResponse[style=dashed, arrowhead=vee, label="<<use>>"] router->BeforeTraversal[style=dashed, arrowhead=vee, label="<<use>>"] registry[label="{registry||+notify()}"] router->registry[arrowhead=vee] } ``` ```c++ handle_request(){ notify = registry.notify; notify(NewRequest(request)); ... notify(BeforeTraversal(request)); ... notify(ContextFound(request)); } ``` ```c++ invoke_request(){ notify = registry.notify; notify(NewResponse(request, response)); } ``` ### Configurator ```graphviz digraph hierarchy{ node [shape=record] Configurator->ApplicationCreated[style=dashed, arrowhead=vee, label="<<use>>"] registry[label="{registry||+notify()}"] Configurator->registry[arrowhead=vee] } ``` ```c++ make_wsgi_app(){ ... app = Router(self.registry); ... self.registry.notify(ApplicationCreated(app)); ... } ``` ### Renderers ```graphviz digraph hierarchy{ node [shape=record] renderH[label="{ RendererHelper| | +__init__()\l +settings()\l +renderer()\l +get_renderer()\l +render_view()\l +render()\l +render_to_response()\l -make_response()\l +clone()\l }"] renderH->BeforeRender[style=dashed, arrowhead=vee, label="<<use>>"] registry[label="{registry||+notify()}"] renderH->registry[arrowhead=vee] } ``` ```c++ render(value, system_values, request){ ... system_values = BeforeRender(system_values, value); registry = self.registry registry.notify(system_values); } ``` ```graphviz digraph hierarchy { node [shape=record] Irequest[label="{ \<\<interface\>\>\nINewRequest }"] request[label="{ NewRequest| -request\l| +__init__()\l }"] Irequest->request[dir=back, style=dashed, arrowtail=onormal] Iresponse[label="{ \<\<interface\>\>\nINewResponse }"] response[label="{ NewResponse| -request\l -response\l| +__init__()\l }"] Iresponse->response[dir=back, style=dashed, arrowtail=onormal] Itraverse[label="{ \<\<interface\>\>\nIBeforeTraversal }"] traverse[label="{ BeforeTraversal| -request\l| +__init__()\l }"] Itraverse->traverse[dir=back, style=dashed, arrowtail=onormal] Icontext[label="{ \<\<interface\>\>\nIContextFound }"] context[label="{ ContextFound| -request\l| +__init__()\l }"] Icontext->context[dir=back, style=dashed, arrowtail=onormal] Iapp[label="{ \<\<interface\>\>\nIApplicationCreated }"] app[label="{ ApplicationCreated| -app\l -object\l| +__init__()\l }"] Iapp->app[dir=back, style=dashed, arrowtail=onormal] Irender[label="{ \<\<interface\>\>\nIBeforeRender }"] render[label="{ BeforeRender| -dict\l -render_val\l| +__init__()\l }"] Irender->render[dir=back, style=dashed, arrowtail=onormal] router[label="{ Router| -registry\l| +handle_request()\l +invoke_request()\l }"] router->context[style=dashed, arrowhead=vee, label="<<use>>"] router->request[style=dashed, arrowhead=vee, label="<<use>>"] router->response[style=dashed, arrowhead=vee, label="<<use>>"] router->traverse[style=dashed, arrowhead=vee, label="<<use>>"] router->registry[arrowhead=vee] Configurator->app[style=dashed, arrowhead=vee, label="<<use>>"] Configurator->registry[arrowhead=vee] renderH[label="{ RendererHelper| | +__init__()\l +settings()\l +renderer()\l +get_renderer()\l +render_view()\l +render()\l +render_to_response()\l -make_response()\l +clone()\l }"] renderH->render[style=dashed, arrowhead=vee, label="<<use>>"] renderH->registry[arrowhead=vee] registry[label="{registry||+notify()}"] } ``` ## [EventType] EventType are types that implemented the corresponding InterfaceEventType. ```mermaid graph TD A(EventType)-->B(zope.interface.declaration::implementer) A-->C(InterfaceEventType<br>pyramid.interfaces) E(zope.interface.Interface)---|include|C C-->D(zope.interface.Attribute) style A fill:#f9f style C fill:#f9f ``` ```python @implementer([InterfaceEventType]) class [EventType](object): ``` Make the class, [EventType], implements the interface, [InterfaceEventType]. * [implementer](#implementer) * [InterfaceEventType](#InterfaceEventType) ### implementer zope/interface/declaration.py ```python def __call__(self, ob): if isinstance(ob, *): classImplements(ob, interfaces) else: Implements.named(*, interfaces) ``` * [classImplements](#) * [Implements.named](#) ### InterfaceEventType pyramid/interfaces.py ```python class [InterfaceEventType](Interface): [variable] = Attribute([SomeString]) ``` This class inherents from the basic class, Interface, from zope.interface.Interface. * [Interface](#Interface) * [Attribute](#Attribute) ### Attribute zope/interface/interface.py ```python class Attribute: interface = None classImplements(Attribute, IAttribute) ``` ### Interface zope/interface/interface.py ```python Interface = InterfaceClass("Interface", __module__ = 'zope.interface') ``` ## Subscriber Called as a decorator, the subscriber used the package, Venusian, to defer the decorator behavior. ```mermaid graph TD A(subscriber)---|method|B(__init__) A---|method|C(__call__) A---|method|D(register) C-->D ``` ### subscriber.\__call\__ and subscriber.register Upon called, the register for a certain event is attached to venusian wait until `pyramid.config.Configurator().scan()` is called. ```python def register(): ... config.add_subscriber(...) def __call__(): self.venusian.attach( wrapped, self.register, category=self.category, depth=self.depth + 1, ) ``` ## Example * To use subscriber * To customize events ### To use subscriber form: https://glitch.com/~pyramid-events-subscribers ```python from wsgiref.simple_server import make_server from pyramid.config import Configurator from pyramid.events import NewRequest from pyramid.events import NewResponse from pyramid.events import subscriber from pyramid.response import Response from pyramid.view import view_config @view_config( route_name='home', ) def home(request): return Response('Welcome!') @subscriber(NewRequest, NewResponse) def mysubscriber(event): print(event) if __name__ == '__main__': with Configurator() as config: config.add_route('home', '/') config.scan() app = config.make_wsgi_app() server = make_server('0.0.0.0', 3000, app) server.serve_forever() ``` ### To customize events from: https://docs.pylonsproject.org/projects/pyramid/en/latest/api/events.html ```python class DocCreated(object): def __init__(self, doc, request): self.doc = doc self.request = request from pyramid.events import subscriber @subscriber(DocCreated) def index_doc(event): # index the document using our application's index_doc function doSomething(event.doc, event.request) def new_doc_view(request): doc = MyDoc() event = DocCreated(doc, request) request.registry.notify(event) return {'document': doc} ``` ## References * [pyramid event document 1](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/events.html) * [pyramid event document 2](https://docs.pylonsproject.org/projects/pyramid/en/latest/api/events.html) * [venusian document](https://buildmedia.readthedocs.org/media/pdf/venusian/latest/venusian.pdf) * [zope.interface example](https://stackoverflow.com/questions/2521189/purpose-of-zope-interfaces) * [pyramid subscriber example](https://glitch.com/~pyramid-events-subscribers)