RAHHH
This commit is contained in:
200
backend/lib/python3.12/site-packages/twisted/web/_element.py
Normal file
200
backend/lib/python3.12/site-packages/twisted/web/_element.py
Normal file
@@ -0,0 +1,200 @@
|
||||
# -*- test-case-name: twisted.web.test.test_template -*-
|
||||
# Copyright (c) Twisted Matrix Laboratories.
|
||||
# See LICENSE for details.
|
||||
|
||||
import itertools
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
List,
|
||||
Optional,
|
||||
TypeVar,
|
||||
Union,
|
||||
overload,
|
||||
)
|
||||
|
||||
from zope.interface import implementer
|
||||
|
||||
from twisted.web.error import (
|
||||
MissingRenderMethod,
|
||||
MissingTemplateLoader,
|
||||
UnexposedMethodError,
|
||||
)
|
||||
from twisted.web.iweb import IRenderable, IRequest, ITemplateLoader
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from twisted.web.template import Flattenable, Tag
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
_Tc = TypeVar("_Tc", bound=Callable[..., object])
|
||||
|
||||
|
||||
class Expose:
|
||||
"""
|
||||
Helper for exposing methods for various uses using a simple decorator-style
|
||||
callable.
|
||||
|
||||
Instances of this class can be called with one or more functions as
|
||||
positional arguments. The names of these functions will be added to a list
|
||||
on the class object of which they are methods.
|
||||
"""
|
||||
|
||||
def __call__(self, f: _Tc, /, *funcObjs: Callable[..., object]) -> _Tc:
|
||||
"""
|
||||
Add one or more functions to the set of exposed functions.
|
||||
|
||||
This is a way to declare something about a class definition, similar to
|
||||
L{zope.interface.implementer}. Use it like this::
|
||||
|
||||
magic = Expose('perform extra magic')
|
||||
class Foo(Bar):
|
||||
def twiddle(self, x, y):
|
||||
...
|
||||
def frob(self, a, b):
|
||||
...
|
||||
magic(twiddle, frob)
|
||||
|
||||
Later you can query the object::
|
||||
|
||||
aFoo = Foo()
|
||||
magic.get(aFoo, 'twiddle')(x=1, y=2)
|
||||
|
||||
The call to C{get} will fail if the name it is given has not been
|
||||
exposed using C{magic}.
|
||||
|
||||
@param funcObjs: One or more function objects which will be exposed to
|
||||
the client.
|
||||
|
||||
@return: The first of C{funcObjs}.
|
||||
"""
|
||||
for fObj in itertools.chain([f], funcObjs):
|
||||
exposedThrough: List[Expose] = getattr(fObj, "exposedThrough", [])
|
||||
exposedThrough.append(self)
|
||||
setattr(fObj, "exposedThrough", exposedThrough)
|
||||
return f
|
||||
|
||||
_nodefault = object()
|
||||
|
||||
@overload
|
||||
def get(self, instance: object, methodName: str) -> Callable[..., Any]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def get(
|
||||
self, instance: object, methodName: str, default: T
|
||||
) -> Union[Callable[..., Any], T]:
|
||||
...
|
||||
|
||||
def get(
|
||||
self, instance: object, methodName: str, default: object = _nodefault
|
||||
) -> object:
|
||||
"""
|
||||
Retrieve an exposed method with the given name from the given instance.
|
||||
|
||||
@raise UnexposedMethodError: Raised if C{default} is not specified and
|
||||
there is no exposed method with the given name.
|
||||
|
||||
@return: A callable object for the named method assigned to the given
|
||||
instance.
|
||||
"""
|
||||
method = getattr(instance, methodName, None)
|
||||
exposedThrough = getattr(method, "exposedThrough", [])
|
||||
if self not in exposedThrough:
|
||||
if default is self._nodefault:
|
||||
raise UnexposedMethodError(self, methodName)
|
||||
return default
|
||||
return method
|
||||
|
||||
|
||||
def exposer(thunk: Callable[..., object]) -> Expose:
|
||||
expose = Expose()
|
||||
expose.__doc__ = thunk.__doc__
|
||||
return expose
|
||||
|
||||
|
||||
@exposer
|
||||
def renderer() -> None:
|
||||
"""
|
||||
Decorate with L{renderer} to use methods as template render directives.
|
||||
|
||||
For example::
|
||||
|
||||
class Foo(Element):
|
||||
@renderer
|
||||
def twiddle(self, request, tag):
|
||||
return tag('Hello, world.')
|
||||
|
||||
<div xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">
|
||||
<span t:render="twiddle" />
|
||||
</div>
|
||||
|
||||
Will result in this final output::
|
||||
|
||||
<div>
|
||||
<span>Hello, world.</span>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
@implementer(IRenderable)
|
||||
class Element:
|
||||
"""
|
||||
Base for classes which can render part of a page.
|
||||
|
||||
An Element is a renderer that can be embedded in a stan document and can
|
||||
hook its template (from the loader) up to render methods.
|
||||
|
||||
An Element might be used to encapsulate the rendering of a complex piece of
|
||||
data which is to be displayed in multiple different contexts. The Element
|
||||
allows the rendering logic to be easily re-used in different ways.
|
||||
|
||||
Element returns render methods which are registered using
|
||||
L{twisted.web._element.renderer}. For example::
|
||||
|
||||
class Menu(Element):
|
||||
@renderer
|
||||
def items(self, request, tag):
|
||||
....
|
||||
|
||||
Render methods are invoked with two arguments: first, the
|
||||
L{twisted.web.http.Request} being served and second, the tag object which
|
||||
"invoked" the render method.
|
||||
|
||||
@ivar loader: The factory which will be used to load documents to
|
||||
return from C{render}.
|
||||
"""
|
||||
|
||||
loader: Optional[ITemplateLoader] = None
|
||||
|
||||
def __init__(self, loader: Optional[ITemplateLoader] = None):
|
||||
if loader is not None:
|
||||
self.loader = loader
|
||||
|
||||
def lookupRenderMethod(
|
||||
self, name: str
|
||||
) -> Callable[[Optional[IRequest], "Tag"], "Flattenable"]:
|
||||
"""
|
||||
Look up and return the named render method.
|
||||
"""
|
||||
method = renderer.get(self, name, None)
|
||||
if method is None:
|
||||
raise MissingRenderMethod(self, name)
|
||||
return method
|
||||
|
||||
def render(self, request: Optional[IRequest]) -> "Flattenable":
|
||||
"""
|
||||
Implement L{IRenderable} to allow one L{Element} to be embedded in
|
||||
another's template or rendering output.
|
||||
|
||||
(This will simply load the template from the C{loader}; when used in a
|
||||
template, the flattening engine will keep track of this object
|
||||
separately as the object to lookup renderers on and call
|
||||
L{Element.renderer} to look them up. The resulting object from this
|
||||
method is not directly associated with this L{Element}.)
|
||||
"""
|
||||
loader = self.loader
|
||||
if loader is None:
|
||||
raise MissingTemplateLoader(self)
|
||||
return loader.load()
|
||||
Reference in New Issue
Block a user