Boucle d'évènements
*******************

**Code source :** Lib/asyncio/events.py, Lib/asyncio/base_events.py

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

-[ Préface ]-

La boucle d'événements est au cœur de chaque application *asyncio*.
Les boucles d'événements exécutent des tâches et des rappels
asynchrones, effectuent des opérations d'entrée-sorite réseau et
exécutent des sous-processus.

Les développeurs d'applications doivent généralement utiliser les
fonctions *asyncio* de haut niveau, telles que "asyncio.run()", et ne
doivent que rarement référencer l'objet boucle ou appeler ses
méthodes. Cette section est principalement destinée aux auteurs de
code, de bibliothèques et de cadriciels de bas niveau, qui ont besoin
d'un contrôle plus précis sur le comportement de la boucle
d'événements.

-[ Obtention d'une boucle d'évènements ]-

Les fonctions de bas niveau suivantes peuvent être utilisées pour
obtenir, définir ou créer une boucle d'événements :

asyncio.get_running_loop()

   Renvoie la boucle d'événements en cours d'exécution dans le fil
   actuel du système d'exploitation.

   Lève une "RuntimeError" s'il n'y a pas de boucle d'événements en
   cours d'exécution.

   Cette fonction ne peut être appelée qu'à partir d'une coroutine ou
   d'une fonction de rappel.

   Ajouté dans la version 3.7.

asyncio.get_event_loop()

   Arrête l'exécution de la boucle d'évènements.

   Lorsqu'elle est appelée depuis une coroutine ou une fonction de
   rappel (par exemple planifiée avec *call_soon* ou une API
   similaire), cette fonction renvoie toujours la boucle d'événement
   en cours.

   S'il n'y a pas de boucle d'événement en cours d'exécution, la
   fonction renvoie le résultat de l'appel
   "get_event_loop_policy().get_event_loop()".

   Étant donné que cette fonction a un comportement plutôt complexe
   (en particulier lorsque des politiques de boucle d'événements
   personnalisées sont utilisées), l'utilisation de la fonction
   "get_running_loop()" est préférable à "get_event_loop()" dans les
   coroutines et les fonctions de rappel.

   Comme indiqué ci-dessus, envisagez d'utiliser la fonction de haut
   niveau "asyncio.run()", au lieu d'utiliser ces fonctions de bas
   niveau pour créer et fermer manuellement une boucle d'événements.

   Obsolète depuis la version 3.12: Deprecation warning is emitted if
   there is no current event loop. In some future Python release this
   will become an error.

asyncio.set_event_loop(loop)

   Définit *loop* comme boucle d'événements actuelle pour le fil
   d'exécution actuel du système d'exploitation.

asyncio.new_event_loop()

   Crée et renvoie un nouvel objet de boucle d'événements.

Notez que le comportement des fonctions "get_event_loop()",
"set_event_loop()" et "new_event_loop()" peut être modifié en
définissant une politique de boucle d'événement personnalisée.

-[ Sommaire ]-

Cette page de documentation contient les sections suivantes :

* la section Event Loop Methods est la documentation de référence des
  API de boucle d'événements ;

* la section Callback Handles documente les instances "Handle" et
  "TimerHandle" qui sont renvoyées par les méthodes de planification
  telles que "loop.call_soon()" et "loop.call_later()" ;

* la section Server Objects documente les types renvoyés par les
  méthodes de boucle d'événements comme "loop.create_server()" ;

* la section Event Loop Implementations documente les classes
  "SelectorEventLoop" et "ProactorEventLoop" ;

* la section Exemples montre comment travailler avec certaines API de
  boucle d'événements.


Méthodes de la boucle d'évènements
==================================

Les boucles d'événements ont des API **de bas niveau** pour les
éléments suivants :

* Démarrer et arrêter une boucle d'évènements

* Planification des fonctions de rappel

* Planification des rappels différés

* Création de *Futures* et des tâches

* Création de connexions

* Création de serveurs

* Transfert de fichiers

* Passage du flux en TLS

* Surveillance de descripteur de fichier

* Travail direct avec des objets *socket*

* DNS

* Travail avec des tubes (*pipes*)

* Signaux Unix

* Exécution de code dans des pools de threads ou de processus

* API de gestion d'erreur

* Activation du mode débogage

* Exécution de sous-processus


Démarrer et arrêter une boucle d'évènements
-------------------------------------------

loop.run_until_complete(future)

   Lance la boucle jusqu'à ce que *future* (une instance de "Future")
   soit terminée.

   Si l'argument est un objet coroutine, il est implicitement
   programmé pour s'exécuter en tant que "asyncio.Task".

   Renvoie le résultat du *Future* ou lève son exception.

loop.run_forever()

   Exécute la boucle d'événement jusqu'à ce que "stop()" soit appelée.

   If "stop()" is called before "run_forever()" is called, the loop
   will poll the I/O selector once with a timeout of zero, run all
   callbacks scheduled in response to I/O events (and those that were
   already scheduled), and then exit.

   Si "stop()" est appelée pendant que "run_forever()" est en cours
   d'exécution, la boucle exécute le lot actuel de rappels puis se
   termine. Notez que les nouveaux rappels programmés par fonctions de
   rappel ne s'exécuteront pas dans ce cas ; à la place, ils
   s'exécuteront la prochaine fois que "run_forever()" ou
   "run_until_complete()" sera appelée.

loop.stop()

   Arrête l'exécution de la boucle d'évènements.

loop.is_running()

   Renvoie "True" si la boucle d'évènements est démarrée.

loop.is_closed()

   Renvoie "True" si la boucle d'évènements est arrêtée.

loop.close()

   Arrête la boucle d'évènements.

   La boucle ne doit pas être en cours d'exécution lorsque cette
   fonction est appelée. Tous les rappels en attente seront ignorés.

   Cette méthode efface toutes les files d'attente et arrête
   l'exécuteur, mais n'attend pas que l'exécuteur se termine.

   Cette méthode est idempotente et irréversible. Aucune autre méthode
   ne doit être appelée après la fermeture de la boucle d'événements.

async loop.shutdown_asyncgens()

   Schedule all currently open *asynchronous generator* objects to
   close with an "aclose()" call.  After calling this method, the
   event loop will issue a warning if a new asynchronous generator is
   iterated. This should be used to reliably finalize all scheduled
   asynchronous generators.

   Notez qu'il n'est pas nécessaire d'appeler cette fonction lorsque
   "asyncio.run()" est utilisée.

   Exemple :

      try:
          loop.run_forever()
      finally:
          loop.run_until_complete(loop.shutdown_asyncgens())
          loop.close()

   Ajouté dans la version 3.6.

async loop.shutdown_default_executor(timeout=None)

   Planifie la fermeture de l'exécuteur par défaut et attend que tous
   les fils se rejoignent dans le "ThreadPoolExecutor". Une fois cette
   méthode appelée, l'utilisation de l'exécuteur par défaut avec
   "loop.run_in_executor()" lève une "RuntimeError".

   The *timeout* parameter specifies the amount of time (in "float"
   seconds) the executor will be given to finish joining. With the
   default, "None", the executor is allowed an unlimited amount of
   time.

   If the *timeout* is reached, a "RuntimeWarning" is emitted and the
   default executor is terminated without waiting for its threads to
   finish joining.

   Note:

     n'appelez pas cette méthode lorsque vous utilisez
     "asyncio.run()", car cette dernière gère automatiquement l'arrêt
     de l'exécuteur par défaut.

   Ajouté dans la version 3.9.

   Modifié dans la version 3.12: Added the *timeout* parameter.


Planification des fonctions de rappel
-------------------------------------

loop.call_soon(callback, *args, context=None)

   Définit la *fonction de rappel* *callback* à appeler avec les
   arguments *args* à la prochaine itération de la boucle
   d'événements.

   Renvoie une instance de "asyncio.Handle", qui pourra être utilisée
   ultérieurement pour annuler le rappel.

   Les fonctions de rappels sont appelées dans l'ordre dans lequel
   elles sont enregistrées. Chaque fonction de rappel sera appelée
   exactement une fois.

   L'argument facultatif nommé uniquement *context* spécifie un
   "contextvars.Context" personnalisé pour le *callback* à exécuter.
   Les rappels utilisent le contexte actuel lorsqu'aucun *context*
   n'est fourni.

   Contrairement à "call_soon_threadsafe()", cette méthode n'est pas
   compatible avec les programmes à fils d'exécution multiples.

loop.call_soon_threadsafe(callback, *args, context=None)

   Une variante compatible avec les programmes à fils d'exécution
   multiples de "call_soon()". Lors de la planification de rappels à
   partir d'un autre fil d'exécution, cette fonction *doit* être
   utilisée, puisque "call_soon()" n'est pas thread-safe.

   This function is safe to be called from a reentrant context or
   signal handler, however, it is not safe or fruitful to use the
   returned handle in such contexts.

   Lève "RuntimeError" si elle est appelée sur une boucle qui a été
   fermée. Cela peut se produire sur un fil secondaire lorsque
   l'application principale se ferme.

   Voir la section exécution concurrente et multi-fils d'exécution de
   la documentation.

   Modifié dans la version 3.7: le paramètre nommé uniquement
   *context* a été ajouté. Voir **PEP 567** pour plus de détails.

Note:

  la plupart des fonctions d'ordonnancement "asyncio" n'autorisent pas
  le passage d'arguments nommés. Pour le faire, utilisez
  "functools.partial()"

     # will schedule "print("Hello", flush=True)"
     loop.call_soon(
         functools.partial(print, "Hello", flush=True))

  L'utilisation d'objets partiels est généralement plus pratique que
  l'utilisation de lambdas, car *asyncio* peut mieux rendre les objets
  partiels dans les messages de débogage et d'erreur.


Planification des rappels différés
----------------------------------

La boucle d'événements fournit des mécanismes pour programmer les
fonctions de rappel à appeler à un moment donné dans le futur. La
boucle d'événements utilise des horloges monotones pour suivre le
temps.

loop.call_later(delay, callback, *args, context=None)

   Planifie le rappel *callback* à appeler après *delay* secondes
   (peut être un entier ou un flottant).

   Une instance de "asyncio.TimerHandle" est renvoyée et peut être
   utilisée pour annuler le rappel.

   *callback* sera appelé exactement une fois. Si deux rappels sont
   programmés exactement à la même heure, l'ordre dans lequel ils sont
   appelés n'est pas défini.

   L'argument positionnel facultatif *args* sera transmis au rappel
   lorsqu'il sera appelé. Si vous voulez que le rappel soit appelé
   avec des arguments nommés, utilisez "functools.partial()".

   Un argument facultatif *context* nommé uniquement permet de
   spécifier un "contextvars.Context" personnalisé pour le *callback*
   à exécuter. Le contexte actuel est utilisé lorsqu'aucun *context*
   n'est fourni.

   Note:

     For performance, callbacks scheduled with "loop.call_later()" may
     run up to one clock-resolution early (see
     "time.get_clock_info('monotonic').resolution").

   Modifié dans la version 3.7: le paramètre nommé uniquement
   *context* a été ajouté. Voir **PEP 567** pour plus de détails.

   Modifié dans la version 3.8: dans Python 3.7 et versions
   antérieures avec l'implémentation de la boucle d'événements par
   défaut, le *delay* ne pouvait pas dépasser un jour. Cela a été
   corrigé dans Python 3.8.

loop.call_at(when, callback, *args, context=None)

   Planifie l'appel de *callback* à l'horodatage absolu donné *when*
   (un *int* ou un *float*), en utilisant la même référence de temps
   que "loop.time()".

   Le comportement de cette méthode est le même que "call_later()".

   Une instance de "asyncio.TimerHandle" est renvoyée et peut être
   utilisée pour annuler le rappel.

   Note:

     For performance, callbacks scheduled with "loop.call_at()" may
     run up to one clock-resolution early (see
     "time.get_clock_info('monotonic').resolution").

   Modifié dans la version 3.7: le paramètre nommé uniquement
   *context* a été ajouté. Voir **PEP 567** pour plus de détails.

   Modifié dans la version 3.8: dans Python 3.7 et versions
   antérieures avec l'implémentation de la boucle d'événements par
   défaut, la différence entre *when* et l'heure actuelle ne pouvait
   pas dépasser un jour. Cela a été corrigé dans Python 3.8.

loop.time()

   Renvoie l'heure actuelle, sous la forme d'une valeur "float", selon
   l'horloge monotone interne de la boucle d'événements.

Note:

  Modifié dans la version 3.8: dans Python 3.7 et les versions
  antérieures, les délais d'expiration (relatif *delay* ou absolu
  *when*) ne doivent pas dépasser un jour. Cela a été corrigé dans
  Python 3.8.

Voir aussi: la fonction "asyncio.sleep()".


Création de *Futures* et des tâches
-----------------------------------

loop.create_future()

   Crée un objet "asyncio.Future" attaché à la boucle d'événements.

   C'est la méthode préférée pour créer des *Futures* avec *asyncio*.
   Cela permet aux boucles d'événements tierces de fournir des
   implémentations alternatives de l'objet *Future* (avec de
   meilleures performances ou instrumentation).

   Ajouté dans la version 3.5.2.

loop.create_task(coro, *, name=None, context=None, **kwargs)

   Planifie l'exécution de coroutine *coro*. Renvoie un objet "Task".

   Les boucles d'événements tierces peuvent utiliser leur propre sous-
   classe de "Task" pour l'interopérabilité. Dans ce cas, le type de
   résultat est une sous-classe de "Task".

   The full function signature is largely the same as that of the
   "Task" constructor (or factory) - all of the keyword arguments to
   this function are passed through to that interface, except *name*,
   or *context* if it is "None".

   Si l'argument *name* est fourni et non "None", il est défini comme
   le nom de la tâche en utilisant "Task.set_name()".

   Argument facultatif *context* nommé uniquement qui permet de
   spécifier un "contextvars.Context" personnalisé pour la *coro* à
   exécuter. La copie de contexte actuel est créée lorsqu'aucun
   *context* n'est fourni.

   Modifié dans la version 3.8: ajout du paramètre "name".

   Modifié dans la version 3.11: ajout du paramètre "context".

   Modifié dans la version 3.13.3: Added "kwargs" which passes on
   arbitrary extra parameters, including  "name" and "context".

   Modifié dans la version 3.13.4: Rolled back the change that passes
   on *name* and *context* (if it is None), while still passing on
   other arbitrary keyword arguments (to avoid breaking backwards
   compatibility with 3.13.3).

loop.set_task_factory(factory)

   Définit une fabrique de tâches qui sera utilisée par
   "loop.create_task()".

   If *factory* is "None" the default task factory will be set.
   Otherwise, *factory* must be a *callable* with the signature
   matching "(loop, coro, **kwargs)", where *loop* is a reference to
   the active event loop, and *coro* is a coroutine object.  The
   callable must pass on all *kwargs*, and return a
   "asyncio.Task"-compatible object.

   Modifié dans la version 3.13.3: Required that all *kwargs* are
   passed on to "asyncio.Task".

   Modifié dans la version 3.13.4: *name* is no longer passed to task
   factories. *context* is no longer passed to task factories if it is
   "None".

loop.get_task_factory()

   Renvoie une fabrique de tâches ou "None" si celle par défaut est
   utilisée.


Création de connexions
----------------------

async loop.create_connection(protocol_factory, host=None, port=None, *, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, happy_eyeballs_delay=None, interleave=None, all_errors=False)

   Ouvre un flux de transport connecté à l'adresse spécifiée par
   *host* et *port*.

   The socket family can be either "AF_INET" or "AF_INET6" depending
   on *host* (or the *family* argument, if provided).

   The socket type will be "SOCK_STREAM".

   *protocol_factory* doit être un appelable renvoyant un protocole
   gérant le protocole asyncio.

   Cette méthode tente d'établir la connexion en arrière-plan. En cas
   de succès, elle renvoie une paire "(transport, protocol)".

   Le synopsis chronologique de l'opération sous-jacente est le
   suivant :

   1. La connexion est établie et un transport asyncio est créé pour
      cela.

   2. *protocol_factory* est appelée sans arguments et doit renvoyer
      une instance de protocol asyncio.

   3. L'instance de protocole est couplée au transport en appelant sa
      méthode "connection_made()".

   4. Un *n*-uplet "(transport, protocol)" est renvoyé en cas de
      succès.

   Le transport créé est un flux bidirectionnel dépendant de
   l'implémentation.

   Autres arguments :

   * *ssl* : s'il est donné et non faux, un transport SSL/TLS est créé
     (par défaut un transport TCP simple est créé). Si *ssl* est un
     objet "ssl.SSLContext", ce contexte est utilisé pour créer le
     transport ; si *ssl* est "True", un contexte par défaut renvoyé
     par "ssl.create_default_context()" est utilisé.

     Voir aussi: Considérations sur la sécurité SSL/TLS

   * *server_hostname* définit ou remplace le nom d'hôte auquel le
     certificat du serveur cible sera comparé. Ne doit être passé que
     si *ssl* n'est pas "None". Par défaut, la valeur de l'argument
     *host* est utilisée. Si *host* est vide, il n'y a pas de valeur
     par défaut et vous devez transmettre une valeur pour
     *server_hostname*. Si *server_hostname* est une chaîne vide, la
     correspondance du nom d'hôte est désactivée (ce qui constitue un
     risque de sécurité sérieux, permettant des attaques potentielles
     de type « homme du milieu »).

   * *family*, *proto*, *flags* sont facultatifs et sont la famille
     d'adresse, le protocole et les drapeaux à transmettre à
     *getaddrinfo()* pour la résolution de *host*. S'ils sont fournis,
     ils doivent tous être des entiers provenant des constantes du
     module "socket".

   * *happy_eyeballs_delay*, s'il est fourni, active Happy Eyeballs
     pour cette connexion. Il doit s'agir d'un nombre à virgule
     flottante représentant le temps d'attente en secondes pour qu'une
     tentative de connexion se termine, avant de démarrer la prochaine
     tentative en parallèle. Il s'agit du « délai de tentative de
     connexion » tel que défini dans la **RFC 8305**. Une valeur par
     défaut raisonnable recommandée par la RFC est "0.25" (250
     millisecondes).

   * *interleave* contrôle la réorganisation des adresses lorsqu'un
     nom d'hôte se résout en plusieurs adresses IP. S'il vaut "0" ou
     n'est pas spécifié, aucune réorganisation n'est effectuée et les
     adresses sont essayées dans l'ordre renvoyé par "getaddrinfo()".
     Si un entier positif est spécifié, les adresses sont entrelacées
     par famille d'adresses et l'entier donné est interprété comme
     "First Address Family Count" tel que défini dans la **RFC 8305**.
     La valeur par défaut est "0" si *happy_eyeballs_delay* n'est pas
     spécifié, et "1" si c'est le cas.

   * *sock*, s'il est fourni, doit être un objet "socket.socket"
     existant et déjà connecté à utiliser par le transport. Si *sock*
     est donné, aucun des *host*, *port*, *family*, *proto*, *flags*,
     *happy_eyeballs_delay*, *interleave* et *local_addr* ne doit être
     spécifié.

     Note:

       l'argument *sock* transfère la propriété du connecteur au
       transport créé. Pour fermer le connecteur, appelez la méthode
       "close()" du transport.

   * *local_addr*, s'il est fourni, est un *n*-uplet "(local_host,
     local_port)" utilisé pour lier le connecteur localement.
     *local_host* et *local_port* sont recherchés en utilisant
     "getaddrinfo()", de la même manière que *host* et *port*.

   * *ssl_handshake_timeout* est (pour une connexion TLS) le temps en
     secondes à attendre que la poignée de main TLS se termine avant
     d'abandonner la connexion. "60.0" secondes si "None" (par
     défaut).

   * *ssl_shutdown_timeout* est le temps en secondes à attendre que
     l'arrêt SSL se termine avant d'abandonner la connexion. "30.0"
     secondes si "None" (par défaut).

   * *all_errors* determines what exceptions are raised when a
     connection cannot be created. By default, only a single
     "Exception" is raised: the first exception if there is only one
     or all errors have same message, or a single "OSError" with the
     error messages combined. When "all_errors" is "True", an
     "ExceptionGroup" will be raised containing all exceptions (even
     if there is only one).

   Modifié dans la version 3.5: ajout de la prise en charge de SSL/TLS
   dans "ProactorEventLoop".

   Modifié dans la version 3.6: The socket option socket.TCP_NODELAY
   is set by default for all TCP connections.

   Modifié dans la version 3.7: ajout du paramètre *ssl handshake
   timeout*

   Modifié dans la version 3.8: ajout des paramètres
   *happy_eyeballs_delay* et *interleave*.Algorithme Happy Eyeballs :
   « succès avec les hôtes à double pile ». Lorsque le chemin et le
   protocole IPv4 d'un serveur fonctionnent, mais que le chemin et le
   protocole IPv6 du serveur ne fonctionnent pas, une application
   cliente à double pile subit un retard de connexion important par
   rapport à un client IPv4 uniquement. Ceci n'est pas souhaitable car
   cela entraîne une moins bonne expérience utilisateur pour le client
   à double pile. Ce document spécifie les exigences pour les
   algorithmes qui réduisent ce délai visible par l'utilisateur et
   fournit un algorithme correspondant.For more information:
   https://datatracker.ietf.org/doc/html/rfc6555

   Modifié dans la version 3.11: ajout du paramètre *ssl shutdown
   timeout*

   Modifié dans la version 3.12: *all_errors* was added.

   Voir aussi:

     la fonction "open_connection()" est une API alternative de haut
     niveau. Elle renvoie une paire de ("StreamReader",
     "StreamWriter") qui peut être utilisée directement dans le code
     *async/wait*.

async loop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, *, family=0, proto=0, flags=0, reuse_port=None, allow_broadcast=None, sock=None)

   Création d'une connexion par datagramme

   The socket family can be either "AF_INET", "AF_INET6", or
   "AF_UNIX", depending on *host* (or the *family* argument, if
   provided).

   The socket type will be "SOCK_DGRAM".

   *protocol_factory* doit être un appelable gérant le protocole
   asyncio.

   Un *n*-uplet "(transport, protocol)" est renvoyé en cas de succès.

   Autres arguments :

   * *local_addr*, s'il est fourni, est un *n*-uplet "(local_host,
     local_port)" utilisé pour lier le connecteur localement. Le
     *local_host* et le *local_port* sont recherchés en utilisant
     "getaddrinfo()".

     Note:

       On Windows, when using the proactor event loop with
       "local_addr=None", an "OSError" with "errno.WSAEINVAL" will be
       raised when running it.

   * *remote_addr*, s'il est fourni, est un *n*-uplet "(remote_host,
     remote_port)" utilisé pour se connecter à une adresse distante.
     Le *remote_host* et le *remote_port* sont recherchés en utilisant
     "getaddrinfo()".

   * *family*, *proto*, *flags* sont facultatifs et représentent la
     famille d'adresse, le protocole et les drapeaux à transmettre à
     "getaddrinfo()" pour la résolution *host*. S'ils sont fournis,
     ils doivent tous être des entiers provenant des constantes du
     module "socket".

   * *reuse_port* tells the kernel to allow this endpoint to be bound
     to the same port as other existing endpoints are bound to, so
     long as they all set this flag when being created. This option is
     not supported on Windows and some Unixes. If the
     socket.SO_REUSEPORT constant is not defined then this capability
     is unsupported.

   * *allow_broadcast* indique au noyau d'autoriser ce point de
     terminaison à envoyer des messages à l'adresse de *broadcast*.

   * *sock* peut éventuellement être spécifié afin d'utiliser un objet
     "socket.socket" préexistant, déjà connecté, à utiliser par le
     transport. Si spécifié, *local_addr* et *remote_addr* doivent
     être omis (doit être "None").

     Note:

       l'argument *sock* transfère la propriété du connecteur au
       transport créé. Pour fermer le connecteur, appelez la méthode
       "close()" du transport.

   Voir les exemples Client écho en UDP et Serveur écho en UDP.

   Modifié dans la version 3.4.4: les paramètres *family*, *proto*,
   *flags*, *reuse_address*, *reuse_port*, *allow_broadcast* et *sock*
   ont été ajoutés.

   Modifié dans la version 3.8: prise en charge sur Windows.

   Modifié dans la version 3.8.1: The *reuse_address* parameter is no
   longer supported, as using socket.SO_REUSEADDR poses a significant
   security concern for UDP. Explicitly passing "reuse_address=True"
   will raise an exception.Lorsque plusieurs processus avec des UID
   différents attribuent des connecteurs à une adresse de connecteur
   UDP identique avec "SO_REUSEADDR", les paquets entrants peuvent
   être distribués de manière aléatoire entre les connecteurs.For
   supported platforms, *reuse_port* can be used as a replacement for
   similar functionality. With *reuse_port*, socket.SO_REUSEPORT is
   used instead, which specifically prevents processes with differing
   UIDs from assigning sockets to the same socket address.

   Modifié dans la version 3.11: The *reuse_address* parameter,
   disabled since Python 3.8.1, 3.7.6 and 3.6.10, has been entirely
   removed.

async loop.create_unix_connection(protocol_factory, path=None, *, ssl=None, sock=None, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None)

   Crée une connexion Unix

   The socket family will be "AF_UNIX"; socket type will be
   "SOCK_STREAM".

   Un *n*-uplet "(transport, protocol)" est renvoyé en cas de succès.

   *path* est le nom d'un connecteur de domaine Unix et est
   obligatoire, sauf si un paramètre *sock* est spécifié. Les
   connecteurs Unix abstraits, les chemins "str", "bytes" et "Path"
   sont pris en charge.

   Voir la documentation de la méthode "loop.create_connection()" pour
   plus d'informations sur les arguments de cette méthode.

   Availability: Unix.

   Modifié dans la version 3.7: ajout du paramètre
   *ssl_handshake_timeout*. Le paramètre *chemin* peut désormais être
   un *objet simili-chemin*.

   Modifié dans la version 3.11: ajout du paramètre *ssl shutdown
   timeout*


Création de serveurs
--------------------

async loop.create_server(protocol_factory, host=None, port=None, *, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, keep_alive=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, start_serving=True)

   Create a TCP server (socket type "SOCK_STREAM") listening on *port*
   of the *host* address.

   Renvoie un objet "Server".

   Arguments :

   * *protocol_factory* doit être un appelable gérant le protocole
     asyncio.

   * Le paramètre *host* peut être défini sur plusieurs types qui
     déterminent où le serveur écoute :

     * Si *host* est une chaîne, le serveur TCP est lié à une seule
       interface réseau spécifiée par *host*.

     * Si *host* est une séquence de chaînes, le serveur TCP est lié à
       toutes les interfaces réseau spécifiées par la séquence.

     * Si *host* est une chaîne vide ou "None", toutes les interfaces
       sont prises en compte et une liste de plusieurs connecteurs est
       renvoyée (probablement une pour IPv4 et une autre pour IPv6).

   * Le paramètre *port* peut être défini pour spécifier sur quel port
     le serveur doit écouter. Si "0" ou "None" (la valeur par défaut),
     un port inutilisé aléatoire est sélectionné (notez que si *host*
     se résout en plusieurs interfaces réseau, un port aléatoire
     différent est sélectionné pour chaque interface).

   * *family* can be set to either "socket.AF_INET" or "AF_INET6" to
     force the socket to use IPv4 or IPv6. If not set, the *family*
     will be determined from host name (defaults to "AF_UNSPEC").

   * *flags* est un masque de bits pour "getaddrinfo()".

   * *sock* peut éventuellement être spécifié afin d'utiliser un objet
     connecteur préexistant. S'il est spécifié, *host* et *port* ne
     doivent pas être spécifiés.

     Note:

       l'argument *sock* transfère la propriété du connecteur au
       serveur créé. Pour fermer le connecteur, appelez la méthode
       "close()" du serveur.

   * *backlog* est le nombre maximum de connexions en file d'attente
     passées à "listen()" (par défaut à 100).

   * *ssl* peut être défini sur une instance "SSLContext" pour activer
     TLS sur les connexions acceptées.

   * *reuse_address* indique au noyau de réutiliser un connecteur
     local dans l'état "TIME_WAIT", sans attendre l'expiration de son
     délai d'attente naturel. S'il n'est pas spécifié, il est
     automatiquement défini sur "True" sous Unix.

   * *reuse_port* indique au noyau d'autoriser ce point de terminaison
     à être lié au même port que les autres points de terminaison
     existants, tant qu'ils définissent tous cet indicateur lors de
     leur création. Cette option n'est pas prise en charge sous
     Windows.

   * *keep_alive* set to "True" keeps connections active by enabling
     the periodic transmission of messages.

   Modifié dans la version 3.13: Added the *keep_alive* parameter.

   * *ssl_handshake_timeout* est (pour un serveur TLS) le temps en
     secondes à attendre que la poignée de main TLS se termine avant
     d'abandonner la connexion. "60.0" secondes si "None" (par
     défaut).

   * *ssl_shutdown_timeout* est le temps en secondes à attendre que
     l'arrêt SSL se termine avant d'abandonner la connexion. "30.0"
     secondes si "None" (par défaut).

   * *start_serving* défini à "True" (valeur par défaut) fait que le
     serveur créé commence immédiatement à accepter les connexions.
     Lorsqu'il est défini sur "False", l'utilisateur doit attendre sur
     "Server.start_serving()" ou "Server.serve_forever()" pour que le
     serveur commence à accepter les connexions.

   Modifié dans la version 3.5: ajout de la prise en charge de SSL/TLS
   dans "ProactorEventLoop".

   Modifié dans la version 3.5.1: le paramètre *host* peut être une
   séquence de chaînes.

   Modifié dans la version 3.6: Added *ssl_handshake_timeout* and
   *start_serving* parameters. The socket option socket.TCP_NODELAY is
   set by default for all TCP connections.

   Modifié dans la version 3.11: ajout du paramètre *ssl shutdown
   timeout*

   Voir aussi:

     la fonction "start_server()" est une API alternative de niveau
     supérieur qui renvoie une paire de "StreamReader" et
     "StreamWriter" qui peut être utilisée dans un code *async/wait*.

async loop.create_unix_server(protocol_factory, path=None, *, sock=None, backlog=100, ssl=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, start_serving=True, cleanup_socket=True)

   Similar to "loop.create_server()" but works with the "AF_UNIX"
   socket family.

   *path* est le nom d'un connecteur de domaine Unix et est
   obligatoire, sauf si un argument *sock* est fourni. Les connecteurs
   Unix abstraits, les chemins "str", "bytes" et "Path" sont pris en
   charge.

   If *cleanup_socket* is true then the Unix socket will automatically
   be removed from the filesystem when the server is closed, unless
   the socket has been replaced after the server has been created.

   Voir la documentation de la méthode "loop.create_server()" pour
   plus d'informations sur les arguments de cette méthode.

   Availability: Unix.

   Modifié dans la version 3.7: ajout des paramètres
   *ssl_handshake_timeout* et *start_serving*. Le paramètre *path*
   peut maintenant être un objet "Path".

   Modifié dans la version 3.11: ajout du paramètre *ssl shutdown
   timeout*

   Modifié dans la version 3.13: Added the *cleanup_socket* parameter.

async loop.connect_accepted_socket(protocol_factory, sock, *, ssl=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None)

   Enveloppe une connexion déjà acceptée dans une paire
   transport/protocole.

   Cette méthode peut être utilisée par les serveurs qui acceptent les
   connexions en dehors d'*asyncio* mais qui utilisent *asyncio* pour
   les gérer.

   Paramètres :

   * *protocol_factory* doit être un appelable gérant le protocole
     asyncio.

   * *sock* est un objet connecteur préexistant renvoyé par
     "socket.accept".

     Note:

       l'argument *sock* transfère la propriété du connecteur au
       transport créé. Pour fermer le connecteur, appelez la méthode
       "close()" du transport.

   * *ssl* peut être défini sur une "SSLContext" pour activer SSL sur
     les connexions acceptées.

   * *ssl_handshake_timeout* est (pour une connexion SSL) le temps en
     secondes à attendre que la poignée de main SSL se termine avant
     d'abandonner la connexion. "60.0" secondes si "None" (par
     défaut).

   * *ssl_shutdown_timeout* est le temps en secondes à attendre que
     l'arrêt SSL se termine avant d'abandonner la connexion. "30.0"
     secondes si "None" (par défaut).

   Renvoie une paire "(transport, protocole)".

   Ajouté dans la version 3.5.3.

   Modifié dans la version 3.7: ajout du paramètre *ssl handshake
   timeout*

   Modifié dans la version 3.11: ajout du paramètre *ssl shutdown
   timeout*


Transfert de fichiers
---------------------

async loop.sendfile(transport, file, offset=0, count=None, *, fallback=True)

   Envoie *file* via *transport*. Renvoie le nombre total d'octets
   envoyés.

   La méthode utilise "os.sendfile()" (hautes performances) si elle
   est disponible.

   *file* doit être un objet fichier normal ouvert en mode binaire.

   *offset* indique où commencer la lecture du fichier. Si spécifié,
   *count* est le nombre total d'octets à transmettre, par opposition
   à l'envoi du fichier jusqu'à ce que EOF soit atteint. La position
   du fichier est toujours mise à jour, même lorsque cette méthode
   génère une erreur. "file.tell()" peut être utilisée pour obtenir le
   nombre d'octets réellement envoyés.

   *fallback* défini sur "True" permet à *asyncio* de lire et
   d'envoyer manuellement le fichier lorsque la plateforme ne prend
   pas en charge l'appel système *sendfile* (par exemple, Windows ou
   connecteur SSL sous Unix).

   Lève "SendfileNotAvailableError" si le système ne prend pas en
   charge l'appel système *sendfile* et que *fallback* est "False".

   Ajouté dans la version 3.7.


Passage du flux en TLS
----------------------

async loop.start_tls(transport, protocol, sslcontext, *, server_side=False, server_hostname=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None)

   Convertit une connexion existante en connexion TLS.

   Crée une instance de codeur-décodeur TLS et l'insère entre le
   *transport* et le *protocol*. Le codeur-décodeur implémente à la
   fois le protocole vers le *transport* et le transport vers le
   *protocol*.

   Renvoie l'instance à deux interfaces créée. Après *await*, le
   *protocol* doit cesser d'utiliser le *transport* d'origine et
   communiquer avec l'objet renvoyé uniquement parce que le codeur met
   en cache les données côté *protocol* et échange sporadiquement des
   paquets de session TLS supplémentaires avec *transport*.

   In some situations (e.g. when the passed transport is already
   closing) this may return "None".

   Paramètres :

   * *transport* et *protocol* que des méthodes comme
     "create_server()" et "create_connection()" renvoient.

   * *sslcontext* : une instance configurée de "SSLContext".

   * *server_side* passe à "True" lorsqu'une connexion côté serveur
     est mise à jour (comme celle créée par "create_server()").

   * *server_hostname* : définit ou remplace le nom d'hôte auquel le
     certificat du serveur cible est comparé.

   * *ssl_handshake_timeout* est (pour une connexion TLS) le temps en
     secondes à attendre que la poignée de main TLS se termine avant
     d'abandonner la connexion. "60.0" secondes si "None" (par
     défaut).

   * *ssl_shutdown_timeout* est le temps en secondes à attendre que
     l'arrêt SSL se termine avant d'abandonner la connexion. "30.0"
     secondes si "None" (par défaut).

   Ajouté dans la version 3.7.

   Modifié dans la version 3.11: ajout du paramètre *ssl shutdown
   timeout*


Surveillance de descripteur de fichier
--------------------------------------

loop.add_reader(fd, callback, *args)

   Commence à surveiller la disponibilité en lecture du descripteur de
   fichier *fd* et appelle *callback* avec les arguments spécifiés une
   fois que *fd* est disponible en lecture.

   Any preexisting callback registered for *fd* is cancelled and
   replaced by *callback*.

loop.remove_reader(fd)

   Arrête de surveiller le descripteur de fichier *fd* pour la
   disponibilité en lecture. Renvoie "True" si *fd* était précédemment
   surveillé pour les lectures.

loop.add_writer(fd, callback, *args)

   Commence à surveiller le descripteur de fichier *fd* pour la
   disponibilité en écriture et appelle *callback* avec les arguments
   spécifiés une fois que *fd* est disponible en écriture.

   Any preexisting callback registered for *fd* is cancelled and
   replaced by *callback*.

   Utilisez "functools.partial()" pour passer des arguments nommés à
   *callback*.

loop.remove_writer(fd)

   Arrête de surveiller le descripteur de fichier *fd* pour la
   disponibilité en écriture. Renvoie "True" si *fd* était
   précédemment surveillé pour les écritures.

Voir aussi la section Prise en charge de la plate-forme pour certaines
limitations de ces méthodes.


Travail direct avec des objets *socket*
---------------------------------------

En général, les implémentations de protocole qui utilisent des API
basées sur le transport telles que "loop.create_connection()" et
"loop.create_server()" sont plus rapides que les implémentations qui
fonctionnent directement avec les *sockets*. Cependant, il existe des
cas d'utilisation où les performances ne sont pas critiques, et
travailler directement avec les objets "socket" est plus pratique.

async loop.sock_recv(sock, nbytes)

   Reçoit jusqu'à *nbytes* de *sock*. Version asynchrone de
   "socket.recv()".

   Renvoie les données reçues sous la forme d'un objet bytes.

   Le connecteur *sock* ne doit pas être bloquant.

   Modifié dans la version 3.7: même si cette méthode a toujours été
   documentée en tant que méthode coroutine, les versions antérieures
   à Python 3.7 renvoyaient un "Future". Depuis Python 3.7, il s'agit
   d'une méthode "async def".

async loop.sock_recv_into(sock, buf)

   Reçoit les données de *sock* dans le tampon *buf*. Basée sur le
   modèle de la méthode bloquante "socket.recv_into()".

   Renvoie le nombre d'octets écrits dans le tampon.

   Le connecteur *sock* ne doit pas être bloquant.

   Ajouté dans la version 3.7.

async loop.sock_recvfrom(sock, bufsize)

   Reçoit un datagramme jusqu'à *bufsize* de *sock*. Version
   asynchrone de "socket.recvfrom()".

   Renvoie un *n*-uplet (données reçues, adresse distante).

   Le connecteur *sock* ne doit pas être bloquant.

   Ajouté dans la version 3.11.

async loop.sock_recvfrom_into(sock, buf, nbytes=0)

   Reçoit un datagramme jusqu'à *nbytes* de *sock* vers *buf*. Version
   asynchrone de "socket.recvfrom_into()".

   Renvoie un *n*-uplet (nombre d'octets reçus, adresse distante).

   Le connecteur *sock* ne doit pas être bloquant.

   Ajouté dans la version 3.11.

async loop.sock_sendall(sock, data)

   Envoie les données *data* au connecteur *sock*. Version asynchrone
   de "socket.sendall()".

   Cette méthode continue d'envoyer des données au connecteur jusqu'à
   ce que toutes les *data* aient été envoyées ou qu'une erreur se
   produise. "None" est renvoyé en cas de succès. En cas d'erreur, une
   exception est levée. De plus, il n'existe aucun moyen de déterminer
   la quantité de données, le cas échéant, qui a été traitée avec
   succès par l'extrémité réceptrice de la connexion.

   Le connecteur *sock* ne doit pas être bloquant.

   Modifié dans la version 3.7: même si la méthode a toujours été
   documentée en tant que méthode coroutine, avant Python 3.7, elle
   renvoyait un "Future". Depuis Python 3.7, il s'agit d'une méthode
   "async def".

async loop.sock_sendto(sock, data, address)

   Envoie un datagramme de *sock* à *address*. Version asynchrone de
   "socket.sendto()".

   Renvoie le nombre d'octets envoyés.

   Le connecteur *sock* ne doit pas être bloquant.

   Ajouté dans la version 3.11.

async loop.sock_connect(sock, address)

   Connecte *sock* à un connecteur distant situé à *address*.

   Version asynchrone de "socket.connect()".

   Le connecteur *sock* ne doit pas être bloquant.

   Modifié dans la version 3.5.2: "address" n'a plus besoin d'être
   résolu. "sock_connect" essaie de vérifier si *address* est déjà
   résolue en appelant "socket.inet_pton()". Sinon,
   "loop.getaddrinfo()" est utilisé pour résoudre *address*.

   Voir aussi:

     "loop.create_connection()" et "asyncio.open_connection()".

async loop.sock_accept(sock)

   Accepte une connexion. Basée sur le modèle de la méthode bloquante
   "socket.accept()".

   Le connecteur doit être lié à une adresse et écouter les
   connexions. La valeur de retour est une paire "(conn, adresse)" où
   *conn* est un *nouvel* objet socket utilisable pour envoyer et
   recevoir des données sur la connexion, et *adresse* est l'adresse
   liée au connecteur de l'autre côté de la connexion.

   Le connecteur *sock* ne doit pas être bloquant.

   Modifié dans la version 3.7: même si la méthode a toujours été
   documentée en tant que méthode coroutine, avant Python 3.7, elle
   renvoyait un "Future". Depuis Python 3.7, il s'agit d'une méthode
   "async def".

   Voir aussi: "loop.create_server()" et "start_server()".

async loop.sock_sendfile(sock, file, offset=0, count=None, *, fallback=True)

   Envoie le fichier en utilisant "os.sendfile" (haute performance) si
   possible. Renvoie le nombre total d'octets envoyés.

   Version asynchrone de "socket.sendfile()".

   *sock* doit être un "socket.SOCK_STREAM" "socket" non bloquant.

   *file* doit être un objet fichier normal ouvert en mode binaire.

   *offset* indique où commencer la lecture du fichier. Si spécifié,
   *count* est le nombre total d'octets à transmettre, par opposition
   à l'envoi du fichier jusqu'à ce que EOF soit atteint. La position
   du fichier est toujours mise à jour, même lorsque cette méthode
   génère une erreur. "file.tell()" peut être utilisée pour obtenir le
   nombre d'octets réellement envoyés.

   *fallback*, lorsqu'il est défini à "True", permet à *asyncio* de
   lire et d'envoyer manuellement le fichier lorsque la plateforme ne
   prend pas en charge l'appel système *sendfile* (par exemple,
   Windows ou connecteur SSL sous Unix).

   Lève une "SendfileNotAvailableError" si le système ne prend pas en
   charge l'appel système *sendfile* et que *fallback* est "False".

   Le connecteur *sock* ne doit pas être bloquant.

   Ajouté dans la version 3.7.


DNS
---

async loop.getaddrinfo(host, port, *, family=0, type=0, proto=0, flags=0)

   Version asynchrone de "socket.getaddrinfo()".

async loop.getnameinfo(sockaddr, flags=0)

   Version asynchrone de "socket.getnameinfo()".

Note:

  Both *getaddrinfo* and *getnameinfo* internally utilize their
  synchronous versions through the loop's default thread pool
  executor. When this executor is saturated, these methods may
  experience delays, which higher-level networking libraries may
  report as increased timeouts. To mitigate this, consider using a
  custom executor for other user tasks, or setting a default executor
  with a larger number of workers.

Modifié dans la version 3.7: les méthodes *getaddrinfo* et
*getnameinfo* ont toujours été documentées pour renvoyer une
coroutine, mais avant Python 3.7, elles renvoyaient en fait des objets
"asyncio.Future". À partir de Python 3.7, les deux méthodes sont des
coroutines.


Travail avec des tubes (*pipes*)
--------------------------------

async loop.connect_read_pipe(protocol_factory, pipe)

   Branche l'extrémité en lecture du tube *pipe* à la boucle
   d'évènements.

   *protocol_factory* doit être un appelable renvoyant un protocole
   gérant le protocole asyncio.

   *pipe* est un *simili-fichier*.

   Renvoie la paire "(transport, protocol)", où *transport* prend en
   charge l'interface "ReadTransport" et *protocol* est un objet
   instancié par *protocol_factory*.

   Avec la boucle d'événements "SelectorEventLoop", le *pipe* est mis
   en mode non bloquant.

async loop.connect_write_pipe(protocol_factory, pipe)

   Branche l'extrémité en écriture de *pipe* à la boucle d'évènements.

   *protocol_factory* doit être un appelable renvoyant un protocole
   gérant le protocole asyncio.

   *pipe* est un *simili-fichier*.

   Renvoie la paire "(transport, protocol)", où *transport* prend en
   charge l'interface "WriteTransport" et *protocol* est un objet
   instancié par *protocol_factory*.

   Avec la boucle d'événements "SelectorEventLoop", le *pipe* est mis
   en mode non bloquant.

Note:

  "SelectorEventLoop" ne prend pas en charge les méthodes ci-dessus
  sous Windows. Utilisez "ProactorEventLoop" à la place pour Windows.

Voir aussi:

  les méthodes "loop.subprocess_exec()" et "loop.subprocess_shell()".


Signaux Unix
------------

loop.add_signal_handler(signum, callback, *args)

   Définit *callback* comme gestionnaire du signal *signum*.

   La fonction de rappel sera appelée par *loop*, avec d'autres
   rappels en file d'attente et des coroutines exécutables de cette
   boucle d'événements. Contrairement aux gestionnaires de signaux
   enregistrés à l'aide de "signal.signal()", un rappel enregistré
   avec cette fonction est autorisé à interagir avec la boucle
   d'événements.

   Lève une "ValueError" si le numéro de signal est invalide ou non
   attrapable. Lève une "RuntimeError" s'il y a un problème lors de la
   configuration du gestionnaire.

   Utilisez "functools.partial()" pour passer des arguments nommés à
   *callback*.

   Comme "signal.signal()", cette fonction doit être invoquée dans le
   fil d'exécution principal.

loop.remove_signal_handler(sig)

   Supprime le gestionnaire du signal *sig*.

   Renvoie "True" si le gestionnaire de signal a été supprimé, ou
   "False" si aucun gestionnaire n'a été défini pour le signal donné.

   Availability: Unix.

Voir aussi: le module "signal".


Exécution de code dans des pools de threads ou de processus
-----------------------------------------------------------

awaitable loop.run_in_executor(executor, func, *args)

   Fait en sorte que *func* soit appelée dans l'exécuteur spécifié.

   The *executor* argument should be an "concurrent.futures.Executor"
   instance. The default executor is used if *executor* is "None". The
   default executor can be set by "loop.set_default_executor()",
   otherwise, a "concurrent.futures.ThreadPoolExecutor" will be lazy-
   initialized and used by "run_in_executor()" if needed.

   Exemple :

      import asyncio
      import concurrent.futures

      def blocking_io():
          # File operations (such as logging) can block the
          # event loop: run them in a thread pool.
          with open('/dev/urandom', 'rb') as f:
              return f.read(100)

      def cpu_bound():
          # CPU-bound operations will block the event loop:
          # in general it is preferable to run them in a
          # process pool.
          return sum(i * i for i in range(10 ** 7))

      async def main():
          loop = asyncio.get_running_loop()

          ## Options:

          # 1. Run in the default loop's executor:
          result = await loop.run_in_executor(
              None, blocking_io)
          print('default thread pool', result)

          # 2. Run in a custom thread pool:
          with concurrent.futures.ThreadPoolExecutor() as pool:
              result = await loop.run_in_executor(
                  pool, blocking_io)
              print('custom thread pool', result)

          # 3. Run in a custom process pool:
          with concurrent.futures.ProcessPoolExecutor() as pool:
              result = await loop.run_in_executor(
                  pool, cpu_bound)
              print('custom process pool', result)

      if __name__ == '__main__':
          asyncio.run(main())

   Notez que la garde du point d'entrée ("if __name__ == '__main__'")
   est requis pour l'option 3 en raison des particularités de
   "multiprocessing", qui est utilisé par "ProcessPoolExecutor". Voir
   Importation sécurisée du module principal.

   Cette méthode renvoie un objet "asyncio.Future".

   Utilisez "functools.partial()" pour passer des arguments nommés à
   *func*.

   Modifié dans la version 3.5.3: "loop.run_in_executor()" ne
   configure plus le "max_workers" de l'exécuteur de pool de threads
   qu'il crée, laissant à la place à l'exécuteur de pool de threads
   ("ThreadPoolExecutor") le soin de définir le défaut.

loop.set_default_executor(executor)

   Définit *executor* comme exécuteur par défaut utilisé par
   "run_in_executor()". *executor* doit être une instance de
   "ThreadPoolExecutor".

   Modifié dans la version 3.11: *executor* doit être une instance de
   "ThreadPoolExecutor".


API de gestion d'erreur
-----------------------

Permet de personnaliser la façon dont les exceptions sont gérées dans
la boucle d'événements.

loop.set_exception_handler(handler)

   Définit *handler* comme nouveau gestionnaire d'exceptions de boucle
   d'événements.

   Si *handler* est "None", le gestionnaire d'exceptions par défaut
   est activé. Sinon, *handler* doit être un appelable avec la
   signature correspondant à "(loop, context)", où "loop" est une
   référence à la boucle d'événements active et "context" est un
   "dict" contenant les détails de l'exception (voir la documentation
   "call_exception_handler()" pour plus de détails sur le contexte).

   If the handler is called on behalf of a "Task" or "Handle", it is
   run in the "contextvars.Context" of that task or callback handle.

   Modifié dans la version 3.12: The handler may be called in the
   "Context" of the task or handle where the exception originated.

loop.get_exception_handler()

   Renvoie le gestionnaire d'exceptions actuel ou "None" si aucun
   gestionnaire d'exceptions personnalisé n'a été défini.

   Ajouté dans la version 3.5.2.

loop.default_exception_handler(context)

   Gestionnaire d'exception par défaut.

   Appelée lorsqu'une exception se produit et qu'aucun gestionnaire
   d'exception n'est défini. Elle peut être appelée par un
   gestionnaire d'exceptions personnalisé qui souhaite s'en remettre
   au comportement du gestionnaire par défaut.

   Le paramètre *context* a la même signification que dans
   "call_exception_handler()".

loop.call_exception_handler(context)

   Appelle le gestionnaire d'exception de la boucle d'évènements
   actuelle.

   *context* est un objet "dict" contenant les clés suivantes (de
   nouvelles clés pourront être introduites dans les futures versions
   de Python) :

   * 'message' : message d'erreur ;

   * 'exception' (facultatif) : objet exception ;

   * 'future' (facultatif) : instance de "asyncio.Future" ;

   * 'task' (facultatif) : instance de "asyncio.Task" ;

   * *'handle'* (facultatif) : instance de "asyncio.Handle" ;

   * *'protocol'* (facultatif) : instance de protocole asyncio ;

   * 'transport' (facultatif) : instance de transport asyncio ;

   * 'socket' (facultatif) : instance de "socket.socket" ;

   * 'source_traceback' (optional): Traceback of the source;

   * 'handle_traceback' (optional): Traceback of the handle;

   * *'asyncgen'* (facultatif) : générateur asynchrone qui a causé
        l'exception

   Note:

     This method should not be overloaded in subclassed event loops.
     For custom exception handling, use the "set_exception_handler()"
     method.


Activation du mode débogage
---------------------------

loop.get_debug()

   Obtient le mode de débogage ("bool") de la boucle d'événements.

   La valeur par défaut est "True" si la variable d'environnement
   "PYTHONASYNCIODEBUG" est définie sur une chaîne non vide, "False"
   sinon.

loop.set_debug(enabled: bool)

   Active le mode débogage pour la boucle d'évènements.

   Modifié dans la version 3.7: le nouveau mode de développement
   Python peut désormais également être utilisé pour activer le mode
   de débogage.

loop.slow_callback_duration

   This attribute can be used to set the minimum execution duration in
   seconds that is considered "slow". When debug mode is enabled,
   "slow" callbacks are logged.

   Default value is 100 milliseconds.

Voir aussi: le mode debogage d'asyncio.


Exécution de sous-processus
---------------------------

Les méthodes décrites dans ces sous-sections sont de bas niveau. Dans
le code *async/await* normal, pensez à utiliser les fonctions de
commodité de haut niveau "asyncio.create_subprocess_shell()" et
"asyncio.create_subprocess_exec()" à la place.

Note:

  sous Windows, la boucle d'événements par défaut "ProactorEventLoop"
  prend en charge les sous-processus, contrairement à
  "SelectorEventLoop". Voir Prise en charge des sous-processus sous
  Windows pour plus de détails.

async loop.subprocess_exec(protocol_factory, *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)

   Crée un sous-processus à partir d'un ou plusieurs arguments de
   chaîne spécifiés par *args*.

   *args* doit être une liste de chaînes représentée par :

   * "str" ;

   * ou "bytes", encodés selon l'encodage du système de fichiers.

   La première chaîne spécifie l'exécutable du programme et les
   chaînes restantes spécifient les arguments. Ensemble, les arguments
   de chaîne forment le "argv" du programme.

   C'est similaire à la classe standard de la bibliothèque
   "subprocess.Popen" appelée avec "shell=False" et la liste des
   chaînes passées en premier argument ; cependant, où "Popen" prend
   un seul argument qui est une liste de chaînes, *subprocess_exec*
   prend plusieurs arguments de chaînes.

   Le *protocol_factory* doit être un appelable renvoyant une sous-
   classe de la classe "asyncio.SubprocessProtocol".

   Autres paramètres :

   * *stdin* peut être l'un de ces éléments :

     * a file-like object

     * an existing file descriptor (a positive integer), for example
       those created with "os.pipe()"

     * la constante "subprocess.PIPE" (par défaut) qui va créer un
       nouveau tube et le connecter,

     * la valeur "None" qui fera que le sous-processus héritera du
       descripteur de fichier de ce processus,

     * la constante "subprocess.DEVNULL" qui indique que le fichier
       spécial "os.devnull" sera utilisé.

   * *stdout* peut être l'un de ces éléments :

     * a file-like object

     * la constante "subprocess.PIPE" (par défaut) qui va créer un
       nouveau tube et le connecter,

     * la valeur "None" qui fera que le sous-processus héritera du
       descripteur de fichier de ce processus,

     * la constante "subprocess.DEVNULL" qui indique que le fichier
       spécial "os.devnull" sera utilisé.

   * *stderr* peut être l'un de ces éléments :

     * a file-like object

     * la constante "subprocess.PIPE" (par défaut) qui va créer un
       nouveau tube et le connecter,

     * la valeur "None" qui fera que le sous-processus héritera du
       descripteur de fichier de ce processus,

     * la constante "subprocess.DEVNULL" qui indique que le fichier
       spécial "os.devnull" sera utilisé.

     * la constante "subprocess.STDOUT" qui connectera le flux
       d'erreur standard au flux de sortie standard du processus.

   * Tous les autres arguments nommés sont passés à "subprocess.Popen"
     sans interprétation, à l'exception de *bufsize*,
     *universal_newlines*, *shell*, *text*, *encoding* et *errors*,
     qui ne doivent pas être spécifiés du tout.

     L'API de sous-processus "asyncio" ne prend pas en charge le
     décodage des flux sous forme de texte. "bytes.decode()" peut être
     utilisée pour convertir les octets renvoyés par le flux en texte.

   If a file-like object passed as *stdin*, *stdout* or *stderr*
   represents a pipe, then the other side of this pipe should be
   registered with "connect_write_pipe()" or "connect_read_pipe()" for
   use with the event loop.

   Voir le constructeur de la classe "subprocess.Popen" pour la
   documentation sur les autres arguments.

   Renvoie une paire "(transport, protocol)", où *transport* est
   conforme à la classe de base "asyncio.SubprocessTransport" et
   *protocol* est un objet instancié par *protocol_factory*.

async loop.subprocess_shell(protocol_factory, cmd, *, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)

   Crée un sous-processus à partir de *cmd*, qui peut être une chaîne
   "str" ou une chaîne "bytes" encodée avec l'encodage du système de
   fichiers, en utilisant la syntaxe "shell" de la plate-forme.

   C'est similaire à la classe standard de la bibliothèque
   "subprocess.Popen" appelée avec "shell=True".

   Le *protocol_factory* doit être un appelable renvoyant une sous-
   classe de la classe "SubprocessProtocol".

   Voir "subprocess_exec()" pour plus de détails sur les arguments
   restants.

   Renvoie une paire "(transport, protocol)", où *transport* est
   conforme à la classe de base "SubprocessTransport" et *protocol*
   est un objet instancié par *protocol_factory*.

Note:

  il est de la responsabilité de l'application de s'assurer que tous
  les espaces blancs et les caractères spéciaux sont correctement
  échappés pour éviter les vulnérabilités d'injection de shell. La
  fonction "shlex.quote()" peut être utilisée pour échapper
  correctement les espaces blancs et les caractères spéciaux dans les
  chaînes qui seront utilisées pour construire des commandes shell.


Fonctions de rappel sur des descripteurs
========================================

class asyncio.Handle

   Objet encapsulant une fonction de rappel renvoyé par
   "loop.call_soon()", "loop.call_soon_threadsafe()".

   get_context()

      Return the "contextvars.Context" object associated with the
      handle.

      Ajouté dans la version 3.12.

   cancel()

      Annule le rappel. Si le rappel a déjà été annulé ou exécuté,
      cette méthode n'a aucun effet.

   cancelled()

      Renvoie "True" si la fonction de rappel a été annulée.

      Ajouté dans la version 3.7.

class asyncio.TimerHandle

   Objet encapsulant la fonction de rappel renvoyé par
   "loop.call_later()" et "loop.call_at()".

   Cette classe est une sous-classe de "Handle".

   when()

      Renvoie une heure de rappel planifiée sous forme de "float"
      secondes.

      L'heure est un horodatage absolu, utilisant la même référence de
      temps que "loop.time()".

      Ajouté dans la version 3.7.


Objets Serveur
==============

Les objets serveur sont créés par les fonctions
"loop.create_server()", "loop.create_unix_server()", "start_server()"
et "start_unix_server()".

Do not instantiate the "Server" class directly.

class asyncio.Server

   Les objets *Server* sont des gestionnaires de contexte asynchrones.
   Lorsqu'il est utilisé dans une instruction "async with", il est
   garanti que l'objet Serveur est fermé et n'accepte pas de nouvelle
   connexion lorsque l'instruction "async with" est terminée :

      srv = await loop.create_server(...)

      async with srv:
          # some code

      # At this point, srv is closed and no longer accepts new connections.

   Modifié dans la version 3.7: l'objet serveur est un gestionnaire de
   contexte asynchrone depuis Python 3.7.

   Modifié dans la version 3.11: This class was exposed publicly as
   "asyncio.Server" in Python 3.9.11, 3.10.3 and 3.11.

   close()

      Arrête le serveur : ferme les connecteurs d'écoute et définit
      l'attribut "sockets" à "None".

      Les connecteurs qui représentent les connexions client entrantes
      existantes restent ouvertes.

      The server is closed asynchronously; use the "wait_closed()"
      coroutine to wait until the server is closed (and no more
      connections are active).

   close_clients()

      Close all existing incoming client connections.

      Calls "close()" on all associated transports.

      "close()" should be called before "close_clients()" when closing
      the server to avoid races with new clients connecting.

      Ajouté dans la version 3.13.

   abort_clients()

      Close all existing incoming client connections immediately,
      without waiting for pending operations to complete.

      Calls "abort()" on all associated transports.

      "close()" should be called before "abort_clients()" when closing
      the server to avoid races with new clients connecting.

      Ajouté dans la version 3.13.

   get_loop()

      Renvoie la boucle d'événement associée à l'objet serveur.

      Ajouté dans la version 3.7.

   async start_serving()

      Commence à accepter les connexions.

      Cette méthode est idempotente, elle peut donc être appelée
      lorsque le serveur est déjà en service.

      Le paramètre nommé *start_serving* de "loop.create_server()" et
      "asyncio.start_server()" permet de créer un objet *Server* qui
      n'accepte pas les connexions initialement. Dans ce cas,
      "Server.start_serving()" ou "Server.serve_forever()" peut être
      utilisée pour que le serveur commence à accepter les connexions.

      Ajouté dans la version 3.7.

   async serve_forever()

      Commence à accepter les connexions jusqu'à ce que la coroutine
      soit annulée. L'annulation de la tâche "serve_forever" provoque
      la fermeture du serveur.

      Cette méthode peut être appelée si le serveur accepte déjà les
      connexions. Une seule tâche "serve_forever" peut exister par
      objet *Server*.

      Exemple :

         async def client_connected(reader, writer):
             # Communicate with the client with
             # reader/writer streams.  For example:
             await reader.readline()

         async def main(host, port):
             srv = await asyncio.start_server(
                 client_connected, host, port)
             await srv.serve_forever()

         asyncio.run(main('127.0.0.1', 0))

      Ajouté dans la version 3.7.

   is_serving()

      Renvoie "True" si le serveur accepte de nouvelles connexions.

      Ajouté dans la version 3.7.

   async wait_closed()

      Wait until the "close()" method completes and all active
      connections have finished.

   sockets

      List of socket-like objects, "asyncio.trsock.TransportSocket",
      which the server is listening on.

      Modifié dans la version 3.7: avant Python 3.7, "Server.sockets"
      renvoyait directement une liste interne de sockets de serveur.
      En 3.7, une copie de cette liste est renvoyée.


Implémentations de boucle d'évènements
======================================

*asyncio* est livré avec deux implémentations de boucles d'événements
différentes : "SelectorEventLoop" et "ProactorEventLoop".

By default asyncio is configured to use "EventLoop".

class asyncio.SelectorEventLoop

   A subclass of "AbstractEventLoop" based on the "selectors" module.

   Utilise le *sélecteur* le plus efficace disponible pour la plate-
   forme donnée. Il est également possible de configurer manuellement
   l'implémentation exacte du sélecteur à utiliser :

      import asyncio
      import selectors

      class MyPolicy(asyncio.DefaultEventLoopPolicy):
         def new_event_loop(self):
            selector = selectors.SelectSelector()
            return asyncio.SelectorEventLoop(selector)

      asyncio.set_event_loop_policy(MyPolicy())

   Availability: Unix, Windows.

class asyncio.ProactorEventLoop

   A subclass of "AbstractEventLoop" for Windows that uses "I/O
   Completion Ports" (IOCP).

   Availability: Windows.

   Voir aussi: MSDN documentation on I/O Completion Ports.

class asyncio.EventLoop

      An alias to the most efficient available subclass of
      "AbstractEventLoop" for the given platform.

      It is an alias to "SelectorEventLoop" on Unix and
      "ProactorEventLoop" on Windows.

   Ajouté dans la version 3.13.

class asyncio.AbstractEventLoop

   Classe mère abstraite pour les boucles d'événements conforme à
   *asyncio*.

   La section Méthodes de la boucle d'évènements liste toutes les
   méthodes qu'une implémentation alternative de "AbstractEventLoop"
   doit définir.


Exemples
========

Notez que tous les exemples de cette section montrent **à dessein**
comment utiliser les API de boucle d'événement de bas niveau, telles
que "loop.run_forever()" et "loop.call_soon()". Les applications
*asyncio* modernes ont rarement besoin d'être écrites de cette façon ;
pensez à utiliser les fonctions de haut niveau comme "asyncio.run()".


"Hello World" avec "call_soon()"
--------------------------------

Un exemple utilisant la méthode "loop.call_soon()" pour programmer un
rappel. Le rappel affiche ""Hello World"" puis arrête la boucle
d'événements :

   import asyncio

   def hello_world(loop):
       """A callback to print 'Hello World' and stop the event loop"""
       print('Hello World')
       loop.stop()

   loop = asyncio.new_event_loop()

   # Schedule a call to hello_world()
   loop.call_soon(hello_world, loop)

   # Blocking call interrupted by loop.stop()
   try:
       loop.run_forever()
   finally:
       loop.close()

Voir aussi:

  un exemple similaire de Hello World créé avec une coroutine et la
  fonction "run()".


Affichage de la date actuelle avec "call_later()"
-------------------------------------------------

Un exemple de rappel affichant la date actuelle toutes les secondes.
Le rappel utilise la méthode "loop.call_later()" pour se re-planifier
après 5 secondes, puis arrête la boucle d'événements :

   import asyncio
   import datetime

   def display_date(end_time, loop):
       print(datetime.datetime.now())
       if (loop.time() + 1.0) < end_time:
           loop.call_later(1, display_date, end_time, loop)
       else:
           loop.stop()

   loop = asyncio.new_event_loop()

   # Schedule the first call to display_date()
   end_time = loop.time() + 5.0
   loop.call_soon(display_date, end_time, loop)

   # Blocking call interrupted by loop.stop()
   try:
       loop.run_forever()
   finally:
       loop.close()

Voir aussi:

  un exemple similaire de date actuelle créé avec une coroutine et la
  fonction "run()".


Surveillance des événements de lecture pour un descripteur de fichier
---------------------------------------------------------------------

Attend qu'un descripteur de fichier reçoive des données en utilisant
la méthode "loop.add_reader()" puis ferme la boucle d'événements :

   import asyncio
   from socket import socketpair

   # Create a pair of connected file descriptors
   rsock, wsock = socketpair()

   loop = asyncio.new_event_loop()

   def reader():
       data = rsock.recv(100)
       print("Received:", data.decode())

       # We are done: unregister the file descriptor
       loop.remove_reader(rsock)

       # Stop the event loop
       loop.stop()

   # Register the file descriptor for read event
   loop.add_reader(rsock, reader)

   # Simulate the reception of data from the network
   loop.call_soon(wsock.send, 'abc'.encode())

   try:
       # Run the event loop
       loop.run_forever()
   finally:
       # We are done. Close sockets and the event loop.
       rsock.close()
       wsock.close()
       loop.close()

Voir aussi:

  * un exemple similaire utilisant les transports, les protocoles et
    la méthode "loop.create_connection()",

  * un autre exemple utilisant la fonction et les flux de haut niveau
    "asyncio.open_connection()".


Gestion des signaux *SIGINT* et *SIGTERM*
-----------------------------------------

(Cet exemple ne fonctionne que sur Unix.)

Register handlers for signals "SIGINT" and "SIGTERM" using the
"loop.add_signal_handler()" method:

   import asyncio
   import functools
   import os
   import signal

   def ask_exit(signame, loop):
       print("got signal %s: exit" % signame)
       loop.stop()

   async def main():
       loop = asyncio.get_running_loop()

       for signame in {'SIGINT', 'SIGTERM'}:
           loop.add_signal_handler(
               getattr(signal, signame),
               functools.partial(ask_exit, signame, loop))

       await asyncio.sleep(3600)

   print("Event loop running for 1 hour, press Ctrl+C to interrupt.")
   print(f"pid {os.getpid()}: send SIGINT or SIGTERM to exit.")

   asyncio.run(main())
