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.Gardez une référence
     au résultat de cette fonction pour éviter de voir une tâche
     disparaitre au milieu de son exécution.

   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* est un objet qui peut être attendu (*awaitable*). Les
   coroutines peuvent attendre les objets *Future* jusqu'à ce qu'ils
   renvoient un résultat, ils lèvent une exception ou qu'ils soient
   annulés. Un *Future* peut être attendu plusieurs fois et le
   résultat est le même.

   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()" accepts an optional "msg" argument, but
    "concurrent.futures.Future.cancel()" does not.
