1# -*- coding: utf-8 -*-
2# Copyright (c) 2018 gevent contributors. See LICENSE for details.
3"""
4Interfaces gevent uses that don't belong any one place.
5
6This is not a public module, these interfaces are not
7currently exposed to the public, they mostly exist for
8documentation and testing purposes.
9
10.. versionadded:: 1.3b2
11
12"""
13from __future__ import absolute_import
14from __future__ import division
15from __future__ import print_function
16
17import sys
18
19from zope.interface import Interface
20from zope.interface import Attribute
21
22_text_type = type(u'')
23
24try:
25    from zope import schema
26except ImportError: # pragma: no cover
27    class _Field(Attribute):
28        __allowed_kw__ = ('readonly', 'min',)
29        def __init__(self, description, required=False, **kwargs):
30            description = u"%s (required? %s)" % (description, required)
31            assert isinstance(description, _text_type)
32            for k in self.__allowed_kw__:
33                kwargs.pop(k, None)
34            if kwargs:
35                raise TypeError("Unexpected keyword arguments: %r" % (kwargs,))
36            Attribute.__init__(self, description)
37
38    class schema(object):
39        Bool = _Field
40        Float = _Field
41
42
43# pylint:disable=no-method-argument, unused-argument, no-self-argument
44# pylint:disable=inherit-non-class
45
46__all__ = [
47    'ILoop',
48    'IWatcher',
49    'ICallback',
50]
51
52class ILoop(Interface):
53    """
54    The common interface expected for all event loops.
55
56    .. caution::
57       This is an internal, low-level interface. It may change
58       between minor versions of gevent.
59
60    .. rubric:: Watchers
61
62    The methods that create event loop watchers are `io`, `timer`,
63    `signal`, `idle`, `prepare`, `check`, `fork`, `async_`, `child`,
64    `stat`. These all return various types of :class:`IWatcher`.
65
66    All of those methods have one or two common arguments. *ref* is a
67    boolean saying whether the event loop is allowed to exit even if
68    this watcher is still started. *priority* is event loop specific.
69    """
70
71    default = schema.Bool(
72        description=u"Boolean indicating whether this is the default loop",
73        required=True,
74        readonly=True,
75    )
76
77    approx_timer_resolution = schema.Float(
78        description=u"Floating point number of seconds giving (approximately) the minimum "
79        "resolution of a timer (and hence the minimun value the sleep can sleep for). "
80        "On libuv, this is fixed by the library, but on libev it is just a guess "
81        "and the actual value is system dependent.",
82        required=True,
83        min=0.0,
84        readonly=True,
85    )
86
87    def run(nowait=False, once=False):
88        """
89        Run the event loop.
90
91        This is usually called automatically by the hub greenlet, but
92        in special cases (when the hub is *not* running) you can use
93        this to control how the event loop runs (for example, to integrate
94        it with another event loop).
95        """
96
97    def now():
98        """
99        now() -> float
100
101        Return the loop's notion of the current time.
102
103        This may not necessarily be related to :func:`time.time` (it
104        may have a different starting point), but it must be expressed
105        in fractional seconds (the same *units* used by :func:`time.time`).
106        """
107
108    def update_now():
109        """
110        Update the loop's notion of the current time.
111
112        .. versionadded:: 1.3
113           In the past, this available as ``update``. This is still available as
114           an alias but will be removed in the future.
115        """
116
117    def destroy():
118        """
119        Clean up resources used by this loop.
120
121        If you create loops
122        (especially loops that are not the default) you *should* call
123        this method when you are done with the loop.
124
125        .. caution::
126
127            As an implementation note, the libev C loop implementation has a
128            finalizer (``__del__``) that destroys the object, but the libuv
129            and libev CFFI implementations do not. The C implementation may change.
130
131        """
132
133    def io(fd, events, ref=True, priority=None):
134        """
135        Create and return a new IO watcher for the given *fd*.
136
137        *events* is a bitmask specifying which events to watch
138        for. 1 means read, and 2 means write.
139        """
140
141    def closing_fd(fd):
142        """
143        Inform the loop that the file descriptor *fd* is about to be closed.
144
145        The loop may choose to schedule events to be delivered to any active
146        IO watchers for the fd. libev does this so that the active watchers
147        can be closed.
148
149        :return: A boolean value that's true if active IO watchers were
150           queued to run. Closing the FD should be deferred until the next
151           run of the eventloop with a callback.
152        """
153
154    def timer(after, repeat=0.0, ref=True, priority=None):
155        """
156        Create and return a timer watcher that will fire after *after* seconds.
157
158        If *repeat* is given, the timer will continue to fire every *repeat* seconds.
159        """
160
161    def signal(signum, ref=True, priority=None):
162        """
163        Create and return a signal watcher for the signal *signum*,
164        one of the constants defined in :mod:`signal`.
165
166        This is platform and event loop specific.
167        """
168
169    def idle(ref=True, priority=None):
170        """
171        Create and return a watcher that fires when the event loop is idle.
172        """
173
174    def prepare(ref=True, priority=None):
175        """
176        Create and return a watcher that fires before the event loop
177        polls for IO.
178
179        .. caution:: This method is not supported by libuv.
180        """
181
182    def check(ref=True, priority=None):
183        """
184        Create and return a watcher that fires after the event loop
185        polls for IO.
186        """
187
188    def fork(ref=True, priority=None):
189        """
190        Create a watcher that fires when the process forks.
191
192        Availability: Unix.
193        """
194
195    def async_(ref=True, priority=None):
196        """
197        Create a watcher that fires when triggered, possibly
198        from another thread.
199
200        .. versionchanged:: 1.3
201           This was previously just named ``async``; for compatibility
202           with Python 3.7 where ``async`` is a keyword it was renamed.
203           On older versions of Python the old name is still around, but
204           it will be removed in the future.
205        """
206
207    if sys.platform != "win32":
208
209        def child(pid, trace=0, ref=True):
210            """
211            Create a watcher that fires for events on the child with process ID *pid*.
212
213            This is platform specific and not available on Windows.
214
215            Availability: Unix.
216            """
217
218    def stat(path, interval=0.0, ref=True, priority=None):
219        """
220        Create a watcher that monitors the filesystem item at *path*.
221
222        If the operating system doesn't support event notifications
223        from the filesystem, poll for changes every *interval* seconds.
224        """
225
226    def run_callback(func, *args):
227        """
228        Run the *func* passing it *args* at the next opportune moment.
229
230        The next opportune moment may be the next iteration of the event loop,
231        the current iteration, or some other time in the future.
232
233        Returns a :class:`ICallback` object. See that documentation for
234        important caveats.
235
236        .. seealso:: :meth:`asyncio.loop.call_soon`
237           The :mod:`asyncio` equivalent.
238        """
239
240    def run_callback_threadsafe(func, *args):
241        """
242        Like :meth:`run_callback`, but for use from *outside* the
243        thread that is running this loop.
244
245        This not only schedules the *func* to run, it also causes the
246        loop to notice that the *func* has been scheduled (e.g., it causes
247        the loop to wake up).
248
249        .. versionadded:: 21.1.0
250
251        .. seealso:: :meth:`asyncio.loop.call_soon_threadsafe`
252           The :mod:`asyncio` equivalent.
253        """
254
255class IWatcher(Interface):
256    """
257    An event loop watcher.
258
259    These objects call their *callback* function when the event
260    loop detects the event has happened.
261
262    .. important:: You *must* call :meth:`close` when you are
263       done with this object to avoid leaking native resources.
264    """
265
266    def start(callback, *args, **kwargs):
267        """
268        Have the event loop begin watching for this event.
269
270        When the event is detected, *callback* will be called with
271        *args*.
272
273        .. caution::
274
275            Not all watchers accept ``**kwargs``,
276            and some watchers define special meanings for certain keyword args.
277        """
278
279    def stop():
280        """
281        Have the event loop stop watching this event.
282
283        In the future you may call :meth:`start` to begin watching
284        again.
285        """
286
287    def close():
288        """
289        Dispose of any native resources associated with the watcher.
290
291        If we were active, stop.
292
293        Attempting to operate on this object after calling close is
294        undefined. You should dispose of any references you have to it
295        after calling this method.
296        """
297
298class ICallback(Interface):
299    """
300    Represents a function that will be run some time in the future.
301
302    Callback functions run in the hub, and as such they cannot use
303    gevent's blocking API; any exception they raise cannot be caught.
304    """
305
306    pending = schema.Bool(description=u"Has this callback run yet?",
307                          readonly=True)
308
309    def stop():
310        """
311        If this object is still `pending`, cause it to
312        no longer be `pending`; the function will not be run.
313        """
314
315    def close():
316        """
317        An alias of `stop`.
318        """
319