Futures
*******

**Code source :** Lib/asyncio/futures.py, Lib/asyncio/base_futures.py

======================================================================

Les objets *Future* sont utilisés comme passerelles entre du **code
bas niveau basé sur des fonctions de rappel** et du code haut niveau
utilisant *async* et *await*.


Fonctions pour *Future*
=======================

asyncio.isfuture(obj)

   Renvoie "True" si *obj* est soit :

   * une instance de "asyncio.Future" ;

   * une instance de "asyncio.Task" ;

   * un objet se comportant comme *Future* et possédant un attribut
     "_asyncio_future_blocking".

   Nouveau dans la version 3.5.

asyncio.ensure_future(obj, *, loop=None)

   Renvoie :

   * l'objet *obj* tel quel si c'est un objet "Future", "Task" ou se
     comportant comme un *Future*. "isfuture()" est utilisée pour le
     test ;

   * un objet "Task" encapsulant *obj* si ce dernier est une coroutine
     ("iscoroutine()" est utilisée pour le test). Dans ce cas,
     l’exécution de la coroutine sera planifiée par "ensure_future()"
     ;

   * un objet "Task" qui attendra (*await*) *obj* si ce dernier peut
     être attendu (*awaitable*). "iscoroutine()" est utilisée pour le
     test.

   Si *obj* ne correspond à aucun des critères ci-dessus, une
   exception "TypeError" est levée.

   Important:

     Voir aussi la fonction "create_task()" qui est la manière
     privilégiée pour créer des nouvelles tâches.Save a reference to
     the result of this function, to avoid a task disappearing mid-
     execution.

   Modifié dans la version 3.5.1: La fonction accepte n'importe quel
   objet *awaitable*.

   Obsolète depuis la version 3.10: Un "DeprecationWarning" est levé
   si *obj* n'est pas un objet se comportant comme un *Future*, si
   *loop* n'est pas spécifié et s'il n'y a pas de boucle d'évènements
   en cours d'exécution.

asyncio.wrap_future(future, *, loop=None)

   Encapsule un objet "concurrent.futures.Future" dans un objet
   "asyncio.Future".

   Obsolète depuis la version 3.10: Un "DeprecationWarning" est levé
   si *future* n'est pas un objet se comportant comme un *Future*, si
   *loop* n'est pas spécifié et s'il n'y a pas de boucle d'évènements
   en cours d'exécution.


Objet *Future*
==============

class asyncio.Future(*, loop=None)

   Un *Future* représente le résultat final d'une opération
   asynchrone. Il n'est pas conçu pour pouvoir être utilisé par
   plusieurs fils d'exécution.

   Future is an *awaitable* object.  Coroutines can await on Future
   objects until they either have a result or an exception set, or
   until they are cancelled. A Future can be awaited multiple times
   and the result is same.

   Les *Futures* sont habituellement utilisés pour permettre à du code
   bas niveau basé sur des fonctions de rappel (par exemple : les
   protocoles utilisant *asyncio* transports) d'interagir avec du code
   haut niveau utilisant *async* et *await*.

   Une bonne règle empirique est de ne jamais exposer des objets
   *Future* dans des *API* destinées à l'utilisateur. La façon
   privilégiée de créer des objets *Future* est d'appeler la méthode
   "loop.create_future()". Cela permet aux implémentations
   alternatives de la boucle d'évènements d'utiliser leur propre
   implémentation de l'objet *Future*.

   Modifié dans la version 3.7: Ajout du support du module
   "contextvars".

   Obsolète depuis la version 3.10: Un "DeprecationWarning" est levé
   si *loop* n'est pas spécifié et s'il n'y a pas de boucle
   d'évènements en cours d'exécution.

   result()

      Renvoie le résultat du *Future*.

      Si le *Future* est « terminé » et a un résultat défini par la
      méthode "set_result()", ce résultat est renvoyé.

      Si le *Future* est « terminé » et a une exception définie par la
      méthode "set_exception()", cette méthode lève l'exception.

      Si le *Future* a été *annulé*, cette méthode lève une exception
      "CancelledError".

      Si le résultat de la tâche n'est pas encore disponible, cette
      méthode lève une exception "InvalidStateError".

   set_result(result)

      Marque le *Future* comme « terminé » et définit son résultat.

      Lève une erreur "InvalidStateError" si le *Future* est déjà «
      terminé ».

   set_exception(exception)

      Marque le *Future* comme « terminé » et définit une exception.

      Lève une erreur "InvalidStateError" si le *Future* est déjà «
      terminé ».

   done()

      Renvoie "True" si le *Future* est « terminé ».

      Un *Future* est « terminé » s'il a été « annulé » ou si un
      résultat ou une exception a été définie par les méthodes
      "set_result()" ou "set_exception()".

   cancelled()

      Renvoie "True" si le *Future* a été « annulé ».

      Cette méthode est habituellement utilisée pour vérifier qu'un
      *Future* n'est pas « annulé » avant de définir un résultat ou
      une exception pour celui-ci :

         if not fut.cancelled():
             fut.set_result(42)

   add_done_callback(callback, *, context=None)

      Ajoute une fonction de rappel à exécuter lorsque le *Future* est
      « terminé ».

      L'argument *callback* est appelé avec l'objet *Future* comme
      seul argument.

      Si le *Future* est déjà « terminé » lorsque la méthode est
      appelée, l'exécution de la fonction de rappel est planifiée avec
      "loop.call_soon()".

      L'argument nommé optionnel *context* permet de spécifier une
      classe "contextvars.Context" personnalisée dans laquelle la
      fonction de rappel s’exécutera. Le contexte actuel est utilisé
      si *context* n'est pas fourni.

      "functools.partial()" peut être utilisée pour passer des
      paramètres à la fonction de rappel :

         # Call 'print("Future:", fut)' when "fut" is done.
         fut.add_done_callback(
             functools.partial(print, "Future:"))

      Modifié dans la version 3.7: Ajout de l'argument nommé
      *context*. Voir **PEP 567** pour plus de détails.

   remove_done_callback(callback)

      Retire *callback* de la liste de fonctions de rappel.

      Renvoie le nombre de fonctions de rappel retiré. La méthode
      renvoie généralement 1, à moins que la fonction ait été ajoutée
      plus d'une fois.

   cancel(msg=None)

      Annule le *Future* et planifie l'exécution des fonctions de
      rappel.

      Si le *Future* est déjà « terminé » ou « annulé », renvoie
      "False". Autrement, change l'état du *Future* à « annulé »,
      planifie l'exécution des fonctions de rappel et renvoie "True".

      Modifié dans la version 3.9: Ajout du paramètre *msg*.

   exception()

      Renvoie l'exception définie pour ce *Future*.

      L'exception, ou "None" si aucune exception n'a été définie, est
      renvoyé seulement si le *Future* est « terminé ».

      Si le *Future* a été *annulé*, cette méthode lève une exception
      "CancelledError".

      Si le *Future* n'est pas encore « terminé », cette méthode lève
      une exception "InvalidStateError".

   get_loop()

      Renvoie la boucle d'évènements à laquelle le *Future* est
      attaché.

      Nouveau dans la version 3.7.

Cet exemple crée un objet *Future*, puis crée et planifie l’exécution
d'une tâche asynchrone qui définira le résultat du *Future* et attend
jusqu'à ce que le *Future* ait un résultat :

   async def set_after(fut, delay, value):
       # Sleep for *delay* seconds.
       await asyncio.sleep(delay)

       # Set *value* as a result of *fut* Future.
       fut.set_result(value)

   async def main():
       # Get the current event loop.
       loop = asyncio.get_running_loop()

       # Create a new Future object.
       fut = loop.create_future()

       # Run "set_after()" coroutine in a parallel Task.
       # We are using the low-level "loop.create_task()" API here because
       # we already have a reference to the event loop at hand.
       # Otherwise we could have just used "asyncio.create_task()".
       loop.create_task(
           set_after(fut, 1, '... world'))

       print('hello ...')

       # Wait until *fut* has a result (1 second) and print it.
       print(await fut)

   asyncio.run(main())

Important:

  L'objet *Future* est conçu pour imiter la classe
  "concurrent.futures.Future". Les principales différences sont :

  * contrairement au *Future asyncio*, les instances de
    "concurrent.futures.Future" ne peuvent pas être attendues ;

  * "asyncio.Future.result()" et "asyncio.Future.exception()"
    n'acceptent pas d'argument *timeout* ;

  * "asyncio.Future.result()" et "asyncio.Future.exception()" lèvent
    une exception "InvalidStateError" lorsque le *Future* n'est pas «
    terminé » ;

  * les fonctions de rappel enregistrées à l'aide de
    "asyncio.Future.add_done_callback()" ne sont pas exécutées
    immédiatement mais planifiées avec "loop.call_soon()" ;

  * les *Future asyncio* ne sont pas compatibles avec les fonctions
    "concurrent.futures.wait()" et "concurrent.futures.as_completed()"
    ;

  * "asyncio.Future.cancel()" accepte un argument optionnel "msg" mais
    pas "concurrent.futures.cancel()".
