extension.py |
|
---|---|
WebCore extension management. This extension registry handles loading and access to extensions as well as the collection of standard WebCore
Extension API callbacks. Reference the At a basic level an extension is a class. That's it; attributes and methods are used to inform the manager of extension metadata and register callbacks for certain events. The most basic extension is one that does nothing:
To register your extension, add a reference to it to your project's
Your extension may define several additional properties:
Tags used as |
|
Imports |
from __future__ import unicode_literals
from marrow.package.host import ExtensionManager
from .compat import items
from .context import Context
|
Module Globals |
|
A standard Python logger object. |
log = __import__('logging').getLogger(__name__)
|
Extension Manager |
|
Principal WebCore extension manager. |
class WebExtensions(ExtensionManager):
|
Each of these is an optional extension callback attribute. |
SIGNALS = ( # Extension hooks.
'start', # Executed during Application construction.
'stop', # Executed when (and if) the serve() server returns.
'graceful', # Executed when (and if) the process is instructed to reload configuration.
'prepare', # Executed during initial request processing.
'dispatch', # Executed once for each dispatch event.
'before', # Executed after all extension `prepare` methods have been called, prior to dispatch.
'after', # Executed after dispatch has returned and the response populated.
'mutate', # Inspect and potentially mutate arguments to the handler prior to execution.
'transform', # Transform the result returned by the handler and apply it to the response.
'middleware', # Executed to allow WSGI middleware wrapping.
)
__isabstractmethod__ = False # Work around a Python 3.4+ issue when attaching to the context.
|
__init__(ctx: ApplicationContext)Extension registry constructor. The extension registry is not meant to be instantiated by third-party software. Instead, access the registry
as an attribute of the current Application or Request context: Currently, this uses some application-internal shenanigans to construct the initial extension set. |
def __init__(self, ctx):
self.feature = set() # Track the active `provides` tags.
self.all = self.order(ctx.app.config['extensions']) # Needs/uses/provides-dependency ordered active extensions.
signals = {signal: [] for signal in self.SIGNALS} # Prepare the known callback sets.
for ext in self.all:
self.feature.update(getattr(ext, 'provides', [])) # Enable those flags.
for mn in self.SIGNALS: # Attach any callbacks that might exist.
m = getattr(ext, mn, None)
if m: signals[mn].append(m)
if hasattr(ext, '__call__'): # This one is aliased; the extension itself is treated as WSGI middleware.
signals['middleware'].append(ext)
|
Certain operations act as a stack, i.e. "before" are executed in dependency order, but "after" are executed in reverse dependency order. This is also the case with "mutate" (incoming) and "transform" (outgoing). |
signals['after'].reverse()
signals['transform'].reverse()
signals['middleware'].reverse()
|
Transform the signal lists into tuples to compact them. |
self.signal = Context(**{k: tuple(v) for k, v in items(signals)})
|
This will save a chain() call on each request by pre-prepending the two lists. Attempts to add extensions during runtime are complicated by this optimization. |
self.signal['pre'] = tuple(signals['prepare'] + signals['before'])
|
Continue up the chain with the |
super(WebExtensions, self).__init__('web.extension')
|