1# -*- test-case-name: nevow -*-
2# Copyright (c) 2004-2009 Divmod.
3# See LICENSE for details.
4
5"""
6Nevow interface definitions.
7"""
8
9from zope.interface import Interface, Attribute
10
11class IQ(Interface):
12    """Interface for querying. Adapters implement this for objects which may
13    appear in the stan DOM to allow introspecting the DOM and finding nodes
14    with certain qualities.
15    """
16    def patternGenerator(pattern, default=None):
17        """Returns a pseudo-Tag which will generate clones of matching
18        pattern tags forever, looping around to the beginning when running
19        out of unique matches.
20
21        If no matches are found, and default is None, raise an exception,
22        otherwise, generate clones of default forever.
23
24        You can use the normal stan syntax on the return value.
25
26        Useful to find repeating pattern elements. Example rendering
27        function:
28
29        >>> def simpleSequence(context, data):
30        ...   pattern = IQ(context).patternGenerator('item')
31        ...   return [pattern(data=element) for element in data]
32        """
33
34    def allPatterns(pattern):
35        """Return a list of all matching pattern tags, cloned.
36
37        Useful if you just want to insert them in the output in one
38        place.
39
40        E.g. the sequence renderer's header and footer are found with this.
41        """
42
43    def onePattern(pattern):
44        """Return a single matching pattern, cloned.
45        If there is more than one matching pattern or no matching patterns,
46        raise an exception.
47
48        Useful in the case where you want to locate one and only one
49        sub-tag and do something with it.
50        """
51
52    def keyed(key):
53        """Locate the node with the key 'key', clone it, call fillSlots(key, clone)
54        and return the clone.
55
56        This method lets you effectively locate and mutate a node in the DOM.
57        It is useful for setting the data special on a specific node, and also for
58        calling fillSlots on a specific node, as well as other node-mutation operations
59        such as setting a handler or assigning a class or id to a node.
60        """
61
62
63class IResource(Interface):
64    def locateChild(ctx, segments):
65        """
66        Locate another object which can be adapted to IResource.
67
68        @param ctx: The context object for the request being responded to.
69        @param segments: A tuple of strings giving the remaining query segments
70            to resolve into an IResource.
71
72        @return: A two-tuple of an L{IResource} provider and a tuple giving the
73            query segments which remain to be processed.  A L{Deferred} which
74            is called back with such a two-tuple may also be returned.
75        """
76
77    def renderHTTP(ctx):
78        """Render a request
79        """
80
81
82class IRenderer(Interface):
83    """Things implementing this interface are serialized by calling their
84    'rend' method.
85    """
86    def rend(ctx, data):
87        """Turn this instance into stan suitable for displaying it in a web page.
88        """
89
90
91class IRenderable(Interface):
92    def renderer(name):
93        """
94        Return the render function associated with the given name.
95
96        @type name: C{str}
97        @param name: The value of a render directive encountered in the
98            document returned by a call to L{IRenderable.render}.
99
100        @return: A two-argument callable which will be invoked with the request
101            being responded to and the tag object on which the render directive
102            was encountered.
103        """
104
105
106    def render(request):
107        """
108        Get the document for this L{IRenderable}.
109
110        @type request: L{IRequest} provider or L{NoneType}
111        @param request: The request in response to which this method is being
112            invoked.
113
114        @return: An object which can be flattened.
115        """
116
117
118
119class IRendererFactory(Interface):
120    """A renderer factory is capable of taking a renderer directive (a string)
121    and returning a callable which when called, will render a portion of DOM.
122    """
123    def renderer(context, name):
124        """Given a context object and a name, return a callable which responds
125        to the signature (context, data) or (data) and returns an object which
126        is flattenable.
127        """
128
129
130class IMacroFactory(Interface):
131    """A macro factory is capable of taking a macro directive (a string)
132    and returning a callable which when called, will replace the portion
133    of the DOM upon which the macro was placed with some different
134    DOM.
135    """
136    def macro(context, name):
137        """Given a context object and a name, return a callable which responds
138        to the signature (context, *parameters) and returns an object which
139        is flattenable.
140        """
141
142
143class IData(Interface):
144    """Any python object to be used as model data to be passed
145    to view functions. Used for marking the context stack only.
146
147    ANY python object is said to implement IData.
148    """
149
150
151class IGettable(Interface):
152    def get(context):
153        """Return the data
154
155        Return any object
156        """
157
158
159class ISettable(Interface):
160    def set(context, data):
161        """Set the data
162
163        This might be removed.
164        """
165
166
167class IContainer(Interface):
168    def child(context, name):
169        """Return a conceptual child; an attribute, or a key,
170        or the result of a function call.
171
172        Returns any object; the result may be adapted to IGettable
173        if possible.
174
175        Return None if the adaptee does not have a child with the
176        given name.
177
178        TODO: Maybe returning None is bad, and .child should just
179        raise whatever exception is natural
180        """
181
182class IComponentized(Interface):
183    """I am a mixin to allow you to be adapted in various ways persistently.
184
185    I define a list of persistent adapters.  This is to allow adapter classes
186    to store system-specific state, and initialized on demand.  The
187    getComponent method implements this.  You must also register adapters for
188    this class for the interfaces that you wish to pass to getComponent.
189
190    Many other classes and utilities listed here are present in Zope3; this one
191    is specific to Twisted.
192    """
193
194    def setComponent(interfaceClass, component):
195        """
196        Add a component to me for the indicated interface.
197        """
198
199    def addComponent(component, ignoreClass=0, registry=None):
200        """
201        Add a component to me, for all appropriate interfaces.
202
203        In order to determine which interfaces are appropriate, the component's
204        provided interfaces will be scanned.
205
206        If the argument 'ignoreClass' is True, then all interfaces are
207        considered appropriate.
208
209        Otherwise, an 'appropriate' interface is one for which its class has
210        been registered as an adapter for my class according to the rules of
211        getComponent.
212
213        @return: the list of appropriate interfaces
214        """
215
216    def getComponent(interface, registry=None, default=None):
217        """Create or retrieve an adapter for the given interface.
218
219        If such an adapter has already been created, retrieve it from the cache
220        that this instance keeps of all its adapters.  Adapters created through
221        this mechanism may safely store system-specific state.
222
223        If you want to register an adapter that will be created through
224        getComponent, but you don't require (or don't want) your adapter to be
225        cached and kept alive for the lifetime of this Componentized object,
226        set the attribute 'temporaryAdapter' to True on your adapter class.
227
228        If you want to automatically register an adapter for all appropriate
229        interfaces (with addComponent), set the attribute 'multiComponent' to
230        True on your adapter class.
231        """
232
233    def unsetComponent(interfaceClass):
234        """Remove my component specified by the given interface class."""
235
236    def removeComponent(component):
237        """
238        Remove the given component from me entirely, for all interfaces for which
239        it has been registered.
240
241        @return: a list of the interfaces that were removed.
242        """
243
244
245
246class ISession(IComponentized):
247    """
248    A web session
249
250    You can locate a Session object to represent a unique web session using
251    ISession(ctx). This default session implementation uses cookies to
252    store a session identifier in the user's browser.
253
254    TODO: Need better docs; what's a session and why and how do you use it
255    """
256
257    uid = Attribute("The unique identifier for this session.")
258
259    def setLifetime(lifetime):
260        """
261        Set the approximate lifetime of this session, in seconds.
262
263        This is highly imprecise, but it allows you to set some general
264        parameters about when this session will expire.  A callback will be
265        scheduled each 'lifetime' seconds, and if I have not been 'touch()'ed
266        in half a lifetime, I will be immediately expired.
267
268        If you need to change the lifetime of all the sessions change sessionsLifeTime
269        attribute in class guard.SessionWrapper
270        """
271
272
273    def notifyOnExpire(callback):
274        """
275        Call this callback when the session expires or logs out.
276        """
277
278
279    def expire():
280        """
281        Expire/logout of the session.
282        """
283
284
285    def touch():
286        """
287        Refresh the session
288        """
289
290
291
292class IGuardSession(ISession):
293    """ A web session base interface
294    Needed for guard to do its dirty job
295
296    guard: SessionWrapper object
297    """
298    def portalLogout(port):
299        """Logout from portal port
300        """
301
302class IRequest(IComponentized):
303    """A HTTP request.
304
305    Subclasses should override the process() method to determine how
306    the request will be processed.
307
308    @ivar method: The HTTP method that was used.
309    @ivar uri: The full URI that was requested (includes arguments).
310    @ivar path: The path only (arguments not included).
311    @ivar args: All of the arguments, including URL and POST arguments.
312    @type args: A mapping of strings (the argument names) to lists of values.
313                i.e., ?foo=bar&foo=baz&quux=spam results in
314                {'foo': ['bar', 'baz'], 'quux': ['spam']}.
315    @ivar requestHeaders: Header fields received in the request.
316    @ivar received_headers: DEPRECATED: All received headers.
317    """
318    method = Attribute("The HTTP method that was used.")
319    uri = Attribute("The full URI that was requested (includes arguments).")
320    path = Attribute("The path only (arguments not included).")
321    prepath = Attribute("Path segments that have already been handled.")
322    postpath = Attribute("Path segments still to be handled.")
323    args = Attribute("All of the arguments, including URL and POST arguments.")
324    requestHeaders = Attribute(
325        "A L{http_headers.Headers} instance giving all received HTTP request "
326        "header fields.")
327    deferred = Attribute("Fired once request processing is finished.")
328    client = Attribute("The client that sent this request.")
329    content = Attribute("File-like object containing the request body.")
330
331    # DEPRECATED:
332    received_headers = Attribute("DEPRECATED: All received headers.")
333
334    # Methods for received request
335    def getHeader(key):
336        """Get a header that was sent from the network.
337
338        Return C{None} if the header is not present.
339        """
340
341
342    def getCookie(key):
343        """Get a cookie that was sent from the network.
344        """
345
346
347    def getAllHeaders():
348        """Return dictionary of all headers the request received."""
349
350    def getRequestHostname():
351        """Get the hostname that the user passed in to the request.
352
353        This will either use the Host: header (if it is available) or the
354        host we are listening on if the header is unavailable.
355        """
356
357    def getHost():
358        """Get my originally requesting transport's host.
359
360        Don't rely on the 'transport' attribute, since Request objects may be
361        copied remotely.  For information on this method's return value, see
362        twisted.internet.tcp.Port.
363        """
364
365    def getClientIP():
366        pass
367
368    def getClient():
369        pass
370
371    def getUser():
372        pass
373
374    def getPassword():
375        pass
376
377    def isSecure():
378        pass
379
380    def getSession(sessionInterface = None):
381        pass
382
383    def URLPath():
384        pass
385
386    def prePathURL():
387        pass
388
389    def rememberRootURL():
390        """
391        Remember the currently-processed part of the URL for later
392        recalling.
393        """
394
395    def getRootURL():
396        """
397        Get a previously-remembered URL.
398        """
399
400    # Methods for outgoing request
401    def finish():
402        """We are finished writing data."""
403
404    def write(data):
405        """
406        Write some data as a result of an HTTP request.  The first
407        time this is called, it writes out response data.
408        """
409
410    def addCookie(k, v, expires=None, domain=None, path=None, max_age=None, comment=None, secure=None):
411        """Set an outgoing HTTP cookie.
412
413        In general, you should consider using sessions instead of cookies, see
414        twisted.web.server.Request.getSession and the
415        twisted.web.server.Session class for details.
416        """
417
418    def setResponseCode(code, message=None):
419        """Set the HTTP response code.
420        """
421
422    def setHeader(k, v):
423        """Set an outgoing HTTP header.
424        """
425
426    def redirect(url):
427        """Utility function that does a redirect.
428
429        The request should have finish() called after this.
430        """
431
432    def setLastModified(when):
433        """Set the X{Last-Modified} time for the response to this request.
434
435        If I am called more than once, I ignore attempts to set
436        Last-Modified earlier, only replacing the Last-Modified time
437        if it is to a later value.
438
439        If I am a conditional request, I may modify my response code
440        to L{NOT_MODIFIED} if appropriate for the time given.
441
442        @param when: The last time the resource being returned was
443            modified, in seconds since the epoch.
444        @type when: number
445        @return: If I am a X{If-Modified-Since} conditional request and
446            the time given is not newer than the condition, I return
447            L{http.CACHED<CACHED>} to indicate that you should write no
448            body.  Otherwise, I return a false value.
449        """
450
451    def setETag(etag):
452        """Set an X{entity tag} for the outgoing response.
453
454        That's \"entity tag\" as in the HTTP/1.1 X{ETag} header, \"used
455        for comparing two or more entities from the same requested
456        resource.\"
457
458        If I am a conditional request, I may modify my response code
459        to L{NOT_MODIFIED<twisted.protocols.http.NOT_MODIFIED>} or
460        L{PRECONDITION_FAILED<twisted.protocols.http.PRECONDITION_FAILED>},
461        if appropriate for the tag given.
462
463        @param etag: The entity tag for the resource being returned.
464        @type etag: string
465        @return: If I am a X{If-None-Match} conditional request and
466            the tag matches one in the request, I return
467            L{CACHED<twisted.protocols.http.CACHED>} to indicate that
468            you should write no body.  Otherwise, I return a false
469            value.
470        """
471
472    def setHost(host, port, ssl=0):
473        """Change the host and port the request thinks it's using.
474
475        This method is useful for working with reverse HTTP proxies (e.g.
476        both Squid and Apache's mod_proxy can do this), when the address
477        the HTTP client is using is different than the one we're listening on.
478
479        For example, Apache may be listening on https://www.example.com, and then
480        forwarding requests to http://localhost:8080, but we don't want HTML produced
481        by Twisted to say 'http://localhost:8080', they should say 'https://www.example.com',
482        so we do:
483
484        >>> request.setHost('www.example.com', 443, ssl=1)
485
486        This method is experimental.
487        """
488
489
490    def notifyFinish(success):
491        """
492        Return a deferred that fires when the request is finished.
493
494        The deferred will fire with C{None} if the request finished
495        successfully, or with the error that caused it to be unsuccessful.
496        """
497
498
499
500class ISerializable(Interface):
501    """DEPRECATED. Use nevow.flat.registerFlattener instead of registering
502    an ISerializable adapter.
503    """
504    def serialize(context):
505        """Serialize the adaptee, with the given context
506        stack if necessary.
507        """
508
509class IStatusMessage(Interface):
510    """A marker interface, which should be set on the user's web session
511    to an object which can be cast to a string, which will be shown to the
512    user to indicate the status of the most recent operation.
513    """
514
515
516class IHand(Interface):
517    """A marker interface which indicates what object the user is currently
518    holding in their hand. This is conceptually the "result" of the last operation;
519    this interface can be used to mark a status string which indicates whether
520    the most recent operation completed successfully, or can be used to hold
521    an object which resulted from the most recent operation.
522    """
523
524
525class ICanHandleException(Interface):
526    def renderHTTP_exception(context, failure):
527        """Render an exception to the given request object.
528        """
529
530    def renderInlineException(context, reason):
531        """Return stan representing the exception, to be printed in the page,
532        not replacing the page."""
533
534
535class ICanHandleNotFound(Interface):
536    def renderHTTP_notFound(context):
537        """Render a not found message to the given request.
538        """
539
540
541class IEventMaster(Interface):
542    pass
543
544
545class IDocFactory(Interface):
546    """Interface for objects that load and parse templates for Nevow's
547    renderers.
548
549    The load method's context arg is optional. Loaders should be written to cope
550    with no context arg and either create a new context (if necessary) or raise
551    a ValueError if the context of the caller is important.
552
553    If a context is passed to load() it should *not* be passed on to the
554    flattener/precompiler; a new context should be created if necessary. This
555    measure is to ensure that nothing remembered in the caller's context, i.e.
556    personal information in the session, leaks into the template until it is
557    actually rendered.
558    """
559
560    def load(ctx=None, preprocessors=(), precompile=None):
561        """
562        Load a template and return a stan document tree.
563
564        @param preprocessors: An iterable of one-argument callables which will
565            be given the stan document tree to transform before it is compiled.
566        """
567
568
569class IRemainingSegments(Interface):
570    """During the URL traversal process, requesting this from the context
571    will result in a tuple of the segments remaining to be processed.
572
573    Equivalent to request.postpath in twisted.web
574    """
575
576
577class ICurrentSegments(Interface):
578    """Requesting this from the context will result in a tuple of path segments
579    which have been consumed to reach the current Page instance during
580    the URL traversal process.
581
582    Equivalent to request.prepath in twisted.web
583    """
584
585
586class IViewParameters(Interface):
587    """An interface used by url.viewhere. When this interface is remembered
588    above a url.viewhere embedded in a page, and the url to the current page
589    is rendered, this object will be consulted for additional manipulations
590    to perform on the url object before returning it.
591    """
592    def __iter__():
593        """Return an iterator which yields a series of (command, args, kw) triples,
594        where 'command' is a string, indicating which url method to call, 'args' is a
595        list indicating the arguments to be passed to this method, and 'kw' is a dict
596        of keyword arguments to pass to this method.
597        """
598
599class II18NConfig(Interface):
600    """
601    Interface for I18N configuration.
602
603    @ivar domain: the gettext domain
604
605    @type domain: str
606
607    @ivar localeDir: path to the messages files or None to use the
608    system default
609
610    @type localeDir: str or None
611    """
612    domain = Attribute("The gettext domain")
613    localeDir = Attribute("Path to the messages files or None to use the system default")
614
615
616class ILanguages(Interface):
617    """
618    Marker interface for the sequence of strings that defines the
619    languages requested by the user.
620    """
621
622
623class ILogger(Interface):
624    """
625    An access.log writing interface.
626
627    Remember this interface in the context stack to use alternative
628    logging for the resources below that point in the tree.
629    """
630    def log(ctx):
631        """Write a log entry for this request."""
632
633
634
635class IFilesystemPackage(Interface):
636    """
637    Represents information about the filesystem layout of a set of modules.
638    """
639    mapping = Attribute("""
640    A C{dict} mapping C{unicode} to C{str}.  The keys in this dictionary are
641    CSS or Javascript module names which can be imported by
642    L{nevow.athena.LivePage}.  The values give locations in the filesystem
643    where the implementation of each module can be found.
644    """)
645
646
647
648class IJavascriptPackage(IFilesystemPackage):
649    """
650    Represents information about the filesystem layout of a set of JavaScript
651    modules.
652    """
653
654
655
656class ICSSPackage(IFilesystemPackage):
657    """
658    Represents information about the filesystem layout of a set of CSS
659    modules.
660    """
661
662
663
664class IAthenaTransportable(Interface):
665    """
666    An object which can be sent by Athena from the Python server to the
667    JavaScript client.
668    """
669    jsClass = Attribute(
670        """
671        A C{unicode} string giving the fully-qualified name of a JavaScript
672        function which will be invoked to unserialize the serialized form of
673        this object.
674
675        The current serialization implementation is limited to supporting
676        values for this attribute which refer to JavaScript functions which
677        are defined in modules which have already been imported by the
678        client receiving the serialized data.  An attempt to lift this
679        limitation will likely be made at some future point.
680        """)
681
682
683    def getInitialArguments():
684        """
685        Define the arguments which will be passed to L{jsClass}.
686
687        @rtype: L{tuple}
688        @return: A tuple of simple types which will be passed as positional
689            arguments to L{jsClass}.
690        """
691