peps: Retract most of public Handle API. Fix server-side ssl. Clean up open issues.
http://hg.python.org/peps/rev/5fa96fe9e291 changeset: 4866:5fa96fe9e291 user: Guido van Rossum <guido@python.org> date: Mon Apr 29 11:49:58 2013 -0700 summary: Retract most of public Handle API. Fix server-side ssl. Clean up open issues. files: pep-3156.txt | 178 ++++++++++++++++---------------------- 1 files changed, 74 insertions(+), 104 deletions(-) diff --git a/pep-3156.txt b/pep-3156.txt --- a/pep-3156.txt +++ b/pep-3156.txt @@ -225,14 +225,6 @@ accuracy and precision of the clock are up to the implementation; the default implementation uses ``time.monotonic()``. -A note about callbacks and Handles: any function in the API described -below that takes a callback and a variable number of arguments for it -can also be given a Handle object instead of the callback. Then no -arguments should be given, and the Handle should represent an -immediate callback (as returned from ``call_soon()``), not a delayed -callback (as returned from ``call_later()``). If the Handle has -been cancelled, the call is a no-op. - Event Loop Classes ------------------ @@ -366,16 +358,15 @@ - ``call_later(delay, callback, *args)``. Arrange for ``callback(*args)`` to be called approximately ``delay`` seconds in - the future, once, unless cancelled. Returns - a ``Handle`` object representing the callback, whose - ``cancel()`` method can be used to cancel the callback. - If ``delay`` is <= 0, this acts like ``call_soon()`` instead. - Otherwise, callbacks scheduled for exactly the same time will be - called in an undefined order. + the future, once, unless cancelled. Returns a Handle representing + the callback, whose ``cancel()`` method can be used to cancel the + callback. If ``delay`` is <= 0, this acts like ``call_soon()`` + instead. Otherwise, callbacks scheduled for exactly the same time + will be called in an undefined order. - ``call_repeatedly(interval, callback, **args)``. Like ``call_later()`` but calls the callback repeatedly, every (approximately) - ``interval`` seconds, until the ``Handle`` returned is cancelled or + ``interval`` seconds, until the Handle returned is cancelled or the callback raises an exception. The first call is in approximately ``interval`` seconds. If for whatever reason the callback happens later than scheduled, subsequent callbacks will be @@ -390,8 +381,10 @@ loop. This is the *only* method that is safe to call from another thread. (To schedule a callback for a later time in a threadsafe manner, you can use ``loop.call_soon_threadsafe(loop.call_later, - when, callback, *args)``.) This is not safe to call from a signal - handler (since it may use locks). + when, callback, *args)``.) Note: this is not safe to call from a + signal handler (since it may use locks). In fact, no API is + signal-safe; if you want to handle signals, use + ``add_signal_handler()`` described below. - ``wrap_future(future)``. This takes a PEP 3148 Future (i.e., an instance of ``concurrent.futures.Future``) and returns a Future @@ -435,6 +428,13 @@ implement their own DNS lookup. The optional arguments *must* be specified as keyword arguments. + Note: implementations are required to implement a subset of the full + socket.getaddrinfo() interface; e.g. they may not support symbolic + port names, or they may ignore or incompletely implement the type, + proto and flags arguments. However, if ``type`` and ``proto`` are + ignored, the argument values should be reflected unchanged in the + return tuples' ``socket_type`` and ``socket_protocol`` elements. + - ``getnameinfo(sockaddr, flags=0)``. Similar to ``socket.getnameinfo()`` but returns a Future. The Future's result on success will be a tuple ``(host, port)``. Same implementation @@ -512,9 +512,10 @@ Optional keyword arguments: - - ``ssl``: Pass ``True`` to create an SSL transport (by default a - plain TCP transport is created). Or pass an ``ssl.SSLContext`` - object to override the default SSL context object to be used. + - ``ssl``: Pass an ``ssl.SSLContext`` object to override the default + SSL context object to be used. (Unlike ``create_connection()``, + passing ``True`` does not make sense -- the ``SSLContext`` object + is required to specify the certificate and key.) - ``backlog``: Backlog value to be passed to the ``listen()`` call. Defaults to ``100``. @@ -538,7 +539,10 @@ - ``stop_serving(sock)``. The argument should be a socket from the list returned by ``start_serving()``. The serving loop associated with that socket will be stopped. Connections that have already - been accepted will not be affected. + been accepted will not be affected. (TBD: What if + ``start_serving()`` doesn't use sockets? Then it should probably + return a list of opaque objects that can be passed to + ``stop_serving()``.) - ``create_datagram_endpoint(protocol_factory, local_addr, remote_addr, **kwds)``. Creates an endpoint for sending and @@ -645,14 +649,12 @@ - ``add_reader(fd, callback, *args)``. Arrange for ``callback(*args)`` to be called whenever file descriptor ``fd`` is - deemed ready for reading. Returns a ``Handle`` object which can be - used to cancel the callback. Note that, unlike ``call_later()``, - the callback may be called many times. Calling ``add_reader()`` - again for the same file descriptor implies a call to - ``remove_reader()`` for the same file descriptor. Note that, - although cancelling the ``Handle`` returned is nearly equivalent to - calling ``remove_reader()``, it is strongly preferred to call - ``remove_reader()``. + deemed ready for reading. Returns a Handle object which can be used + to cancel the callback. (However, it is strongly preferred to use + ``remove_reader()`` instead.) Calling ``add_reader()`` again for + the same file descriptor implies a call to ``remove_reader()`` for + the same file descriptor. (TBD: Since cancelling the Handle is not + recommended, perhaps we should return None instead?) - ``add_writer(fd, callback, *args)``. Like ``add_reader()``, but registers the callback for writing instead of for reading. @@ -661,7 +663,7 @@ descriptor ``fd``, if one is set. If no callback is currently set for the file descriptor, this is a no-op and returns ``False``. Otherwise, it removes the callback arrangement, cancels the - corresponding ``Handle``, and returns ``True``. + corresponding Handle, and returns ``True``. - ``remove_writer(fd)``. This is to ``add_writer()`` as ``remove_reader()`` is to ``add_reader()``. @@ -669,6 +671,10 @@ Pipes and Subprocesses '''''''''''''''''''''' +TBD: Should these really take stream objects? The stream objects are +not useful for reading or writing because they would cause blocking +I/O. This section of the API is clearly not yet ready for review. + - ``connect_read_pipe(protocol_factory, pipe)``: Create a unidrectional stream connection from a file-like object wrapping the read end of a UNIX pipe. The protocol/transport interface is the @@ -692,7 +698,7 @@ - ``add_signal_handler(sig, callback, *args). Whenever signal ``sig`` is received, arrange for ``callback(*args)`` to be called. Returns - a ``Handle`` which can be used to cancel the signal callback. + a Handle which can be used to cancel the signal callback. (Cancelling the handle causes ``remove_signal_handler()`` to be called the next time the signal arrives. Explicitly calling ``remove_signal_handler()`` is preferred.) @@ -761,48 +767,17 @@ and ``SystemExit``; it is usually unwise to treat these the same as most other exceptions.) -The Handle Class ----------------- +Handles +------- -The various methods for registering callbacks (e.g. ``call_later()``) -all return an object representing the registration that can be used to -cancel the callback. For want of a better name this object is called -a ``Handle``, although the user never needs to instantiate -instances of this class. There is one public method: +The various methods for registering callbacks (e.g. ``call_soon()`` +and ``add_reader()``) all return an object representing the +registration that can be used to cancel the callback. This object is +called a Handle (although its class name is not necessarily +``Handle``). Handles are opaque and have only one public method: -- ``cancel()``. Cancel the callback. This just sets the - ``cancelled`` attribute. The event loop must check this. +- ``cancel()``. Cancel the callback. -- ``run()``. Call the callback with the specified arguments. If this - raises an exception, it is logged and the function returns normally. - This always returns None. Note that this ignores the ``cancelled`` - attribute (i.e., a cancelled ``Handle`` can still be called). - -Read-only public attributes: - -- ``callback``. The callback function to be called. - -- ``args``. The argument tuple with which to call the callback function. - -- ``cancelled``. True if ``cancel()`` has been called. - -Note that some callbacks (e.g. those registered with ``call_later()``) -are meant to be called only once. Others (e.g. those registered with -``call_repeatedly()`` or ``add_reader()``) are meant to be called -multiple times. - -The Timer Subclass -'''''''''''''''''' - -``Timer`` is a subclass of ``Handle`` returned by ``call_later()`` and -``call_repeatedly()``. - -It has one additional read-only public attribute: - -- ``when``, the real time when the callback is next scheduled to be - called. - -``Timer`` objects are ordered by their ``when`` field. Futures ------- @@ -989,7 +964,9 @@ *which* end is closed.) - ``can_write_eof()``. Return ``True`` if the protocol supports - ``write_eof()``, ``False`` if it does not. (This method is needed + ``write_eof()``, ``False`` if it does not. (This method typically + returns a fixed value that depends only on the specific Transport + class, not on the state of the Transport object. It is needed because some protocols need to change their behavior when ``write_eof()`` is unavailable. For example, in HTTP, to send data whose size is not known ahead of time, the end of the data is @@ -1079,6 +1056,8 @@ Protocols --------- +XXX This is about where I left off. + TBD Describe different kinds of protocols (bidrectional stream, unidirectional stream, datagram). @@ -1332,41 +1311,38 @@ Open Issues =========== +- A ``time()`` method that returns the time according to the function + used by the scheduler (e.g. ``time.monotonic()`` in Tulip's case)? + What's the use case? + +- A fuller public API for Handle? What's the use case? + +- Should we require all event loops to implement ``sock_recv()`` and + friends? Is the use case strong enough? (Maybe some transports + usable with both ``SelectorEventLoop`` and ``ProactorEventLoop`` use + them? That'd be a good enough use case for me.) + +- Should we require callers of ``create_connection()`` to create and + pass an ``SSLContext`` explicitly, instead of allowing ssl=True? + (For ``start_serving()`` we already require an ``SSLContext``.) + - A debugging API? E.g. something that logs a lot of stuff, or logs unusual conditions (like queues filling up faster than they drain) or even callbacks taking too much time... - Do we need introspection APIs? E.g. asking for the read callback given a file descriptor. Or when the next scheduled call is. Or - the list of file descriptors registered with callbacks. + the list of file descriptors registered with callbacks. Right now + these would all require using Tulip internals. -- Transports may need a method that tries to return the address of the - socket (and another for the peer address). Although these depend on - the socket type and there may not always be a socket; then it should - return None. (Alternatively, there could be a method to return the - socket itself -- but it is conceivable that a transport implements - IP connections without using sockets, and what should it do then?) +- Locks and queues? The Tulip implementation contains implementations + of most types of locks and queues modeled after the stdlib + ``threading`` and ``queue`` modules. Should we incorporate these in + the PEP? -- Need to handle os.fork(). (This may be up to the selector classes - in Tulip's case.) - -- Perhaps start_serving() needs a way to pass in an existing socket - (e.g. gunicorn would need this). Ditto for create_connection(). - -- We might introduce explicit locks, though these will be a bit of a - pain to use, as we can't use the ``with lock: block`` syntax - (because to wait for a lock we'd have to use ``yield from``, which - the ``with`` statement can't do). - -- Support for datagram protocols, "connected" or otherwise. Probably - need more socket I/O methods, e.g. ``sock_sendto()`` and - ``sock_recvfrom()``. Or users can write their own (it's not rocket - science). Is it reasonable to map ``write()``, ``writelines()``, - ``data_received()`` to single datagrams? Or should we have a - different ``datagram_received()`` method on datagram protocols? - (Glyph recommends the latter.) And then what instead of ``write()``? - Finally, do we need support for unconnected datagram protocols? - (That would mean wrappers for ``sendto()`` and ``recvfrom()``.) +- Probably need more socket I/O methods, e.g. ``sock_sendto()`` and + ``sock_recvfrom()``, and perhaps others like ``pipe_read()``. Or + users can write their own (it's not rocket science). - We may need APIs to control various timeouts. E.g. we may want to limit the time spent in DNS resolution, connecting, ssl handshake, @@ -1377,12 +1353,6 @@ operations need default timeouts, and we may want to change the default for a specific operation globally (i.e., per event loop). -- An EventEmitter in the style of NodeJS? Or make this a separate - PEP? It's easy enough to do in user space, though it may benefit - from standardization. (See - https://github.com/mnot/thor/blob/master/thor/events.py and - https://github.com/mnot/thor/blob/master/doc/events.md for examples.) - References ========== -- Repository URL: http://hg.python.org/peps
participants (1)
-
guido.van.rossum