14.1. "csv" — Lecture et écriture de fichiers CSV
*************************************************

**Code source :** Lib/csv.py

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

Le format CSV (*Comma Separated Values*, valeurs séparées par des
virgules) est le format le plus commun dans l'importation et
l'exportation de feuilles de calculs et de bases de données.  Le
format fut utilisé pendant des années avant qu'aient lieu des
tentatives de standardisation avec la **RFC 4180**.  L'absence de
format bien défini signifie que des différences subtiles existent dans
la production et la consommation de données par différentes
applications.  Ces différences peuvent gêner lors du traitement de
fichiers CSV depuis des sources multiples. Cependant, bien que les
séparateurs et délimiteurs varient, le format global est suffisamment
similaire pour qu'un module unique puisse manipuler efficacement ces
données, masquant au programmeur les détails de lecture/écriture des
données.

Le module "csv" implémente des classes pour lire et écrire des données
tabulaires au format CSV.  Il vous permet de dire « écris ces données
dans le format préféré par Excel » ou « lis les données de ce fichier
généré par Excel », sans connaître les détails précis du format CSV
utilisé par Excel.  Vous pouvez aussi décrire les formats CSV utilisés
par d'autres application ou définir vos propres spécialisations.

Les objets "reader" et "writer" du module "csv" lisent et écrivent des
séquences.  Vous pouvez aussi lire/écrire les données dans un
dictionnaire en utilisant les classes "DictReader" et "DictWriter".

Voir aussi:

  **PEP 305** ­— Interface des fichiers CSV
     La proposition d'amélioration de Python (PEP) qui a proposé cet
     ajout au langage.


14.1.1. Contenu du module
=========================

Le module "csv" définit les fonctions suivantes :

csv.reader(csvfile, dialect='excel', **fmtparams)

   Renvoie un objet lecteur, qui itérera sur les lignes de l'objet
   *csvfile* donné. *csvfile* peut être n'importe quel objet
   supportant le protocole *itérateur* et renvoyant une chaîne de
   caractères chaque fois que sa méthode "__next__()" est appelée —
   les *fichiers objets* et les listes sont tous deux valables.   Si
   *csvfile* est un fichier, il doit être ouvert avec "newline=''".
   [1]  Un paramètre *dialect* optionnel peut être fourni pour définir
   un ensemble de paramètres spécifiques à un dialecte CSV
   particulier.  Il peut s'agir d'une instance de sous-classe de
   "Dialect" ou de l'une des chaînes renvoyées par la fonction
   "list_dialects()".  Les autres arguments nommés optionnels
   (*fmtparams*) peuvent être spécifiés pour redéfinir des paramètres
   de formatage particuliers dans le dialecte courant.  Pour des
   détails complets sur les dialectes et paramètres de formatage, voir
   la section Dialectes et paramètres de formatage.

   Chaque ligne lue depuis le fichier CSV est renvoyée comme une liste
   de chaînes de caractères.  Aucune conversion automatique de type
   des données n'est effectuée à moins que l'option de formatage
   "QUOTE_NONNUMERIC" soit spécifiée (dans ce cas, les champs sans
   guillemets sont transformés en nombres flottants).

   Un court exemple d'utilisation :

      >>> import csv
      >>> with open('eggs.csv', newline='') as csvfile:
      ...     spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
      ...     for row in spamreader:
      ...         print(', '.join(row))
      Spam, Spam, Spam, Spam, Spam, Baked Beans
      Spam, Lovely Spam, Wonderful Spam

csv.writer(csvfile, dialect='excel', **fmtparams)

   Renvoie un objet transcripteur responsable de convertir les données
   de l'utilisateur en chaînes délimitées sur l'objet fichier-
   compatible donné.  *csvfile* peut être n'importe quel objet avec
   une méthode "write()".  Si *csvfile* est un fichier, il doit être
   ouvert avec "newline=''". [1]  Un paramètre *dialect* optionnel
   peut être fourni pour définir un ensemble de paramètres spécifiques
   à un dialecte CSV particulier.  Il peut s'agir d'une instance de
   sous-classe de "Dialect" ou de l'une des chaînes renvoyées par la
   fonction "list_dialects()".  Les autres arguments nommés optionnels
   (*fmtparams*) peuvent être spécifiés pour redéfinir des paramètres
   de formatage particuliers dans le dialecte courant.  Pour des
   détails complets sur les dialectes et paramètres de formatage, voir
   la section Dialectes et paramètres de formatage. Pour faciliter au
   mieux l'interfaçage avec d'autres modules implémentant l'interface
   *DB*, la valeur "None" est écrite comme une chaîne vide.  Bien que
   ce ne soit pas une transformation réversible, cela simplifie
   l'exportation de données SQL *NULL* vers des fichiers CSV sans
   pré-traiter les données renvoyées par un appel à "cursor.fetch*".
   Toutes les autres données qui ne sont pas des chaînes de caractères
   sont transformées en chaînes par un appel à "str()" avant d'être
   écrites.

   Un court exemple d'utilisation :

      import csv
      with open('eggs.csv', 'w', newline='') as csvfile:
          spamwriter = csv.writer(csvfile, delimiter=' ',
                                  quotechar='|', quoting=csv.QUOTE_MINIMAL)
          spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])
          spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])

csv.register_dialect(name[, dialect[, **fmtparams]])

   Associe *dialect* avec *name*.  *name* doit être une chaîne de
   caractères. Le dialecte peut être spécifié en passant une instance
   d'une sous-classe de "Dialect", des arguments nommés *fmtparams*,
   ou les deux, avec les arguments nommés redéfinissant les paramètres
   du dialecte. Pour des détails complets sur les dialectes et
   paramètres de formatage, voir la section Dialectes et paramètres de
   formatage.

csv.unregister_dialect(name)

   Supprime le dialecte associé à *name* depuis le registre des
   dialectes.  Une "Error" est levée si *name* n'est pas un nom de
   dialecte enregistré.

csv.get_dialect(name)

   Renvoie le dialecte associé à *name*.  Une "Error" est levée si
   *name* n'est pas un nom de dialecte enregistré.  Cette fonction
   renvoie un objet "Dialect" immuable.

csv.list_dialects()

   Renvoie les noms de tous les dialectes enregistrés.

csv.field_size_limit([new_limit])

   Renvoie la taille de champ maximale courante autorisée par
   l'analyseur. Si *new_limit* est donnée, elle devient la nouvelle
   limite.

Le module "csv" définit les classes suivantes :

class csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)

   Crée un objet qui opère comme un lecteur ordinaire mais assemble
   les informations de chaque ligne dans un "OrderedDict" dont les
   clés sont données par le paramètre optionnel *fieldnames*.

   Le paramètre *fieldnames* est une *sequence*.  Si *fieldnames* est
   omis, les valeurs de la première ligne du fichier *f* seront
   utilisées comme noms de champs.  Sans se soucier de comment sont
   déterminés les noms de champs, le dictionnaire ordonné préserve
   leur ordre original.

   Si une ligne a plus de champs que *fieldnames*, les données
   excédentaires sont mises dans une liste stockée dans le champ
   spécifié par *restkey* ("None" par défaut).  Si une ligne non-vide
   a moins de champs que *fieldnames*, les valeurs manquantes sont
   mises à "None".

   Tous les autres arguments optionnels ou nommés sont passés à
   l'instance "reader" sous-jacente.

   Modifié dans la version 3.6: Les lignes renvoyées sont maintenant
   de type "OrderedDict".

   Un court exemple d'utilisation :

      >>> import csv
      >>> with open('names.csv', newline='') as csvfile:
      ...     reader = csv.DictReader(csvfile)
      ...     for row in reader:
      ...         print(row['first_name'], row['last_name'])
      ...
      Eric Idle
      John Cleese

      >>> print(row)
      OrderedDict([('first_name', 'John'), ('last_name', 'Cleese')])

class csv.DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)

   Crée un objet qui opère comme un transcripteur ordinaire mais qui
   produit les lignes de sortie depuis des dictionnaires.  Le
   paramètre *fieldnames* est une "séquence" de clés  qui indique
   l'ordre dans lequel les valeurs du dictionnaire passé à la méthode
   "writerow()" doivent être écrites vers le fichier *f*.  Le
   paramètre optionnel *restval* spécifie la valeur à écrire si une
   clé de *fieldnames* manque dans le dictionnaire.  Si le
   dictionnaire passé à "writerow()" possède une clé non présente dans
   *fieldnames*, le paramètre optionnel *extrasaction* indique quelle
   action réaliser. S'il vaut "'raise'", sa valeur par défaut, une
   "ValueError" est levée. S'il faut "'ignore'", les valeurs
   excédentaires du dictionnaire sont ignorées. Les autres arguments
   optionnels ou nommés sont passés à l'instance "writer" sous-
   jacente.

   Notez que contrairement à la classe "DictReader", le paramètre
   *fieldnames* de "DictWriter" n'est pas optionnel.  Puisque les
   objets "dict" de Python ne sont pas ordonnés, il n'y a pas
   d'information suffisante pour déduire l'ordre dans lequel la ligne
   devrait être transcrite vers le fichier *f*.

   Un court exemple d'utilisation :

      import csv

      with open('names.csv', 'w', newline='') as csvfile:
          fieldnames = ['first_name', 'last_name']
          writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

          writer.writeheader()
          writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})
          writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'})
          writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})

class csv.Dialect

   La classe "Dialect" est une classe de conteneurs utilisée
   principalement pour ses attributs, qui servent à définir des
   paramètres pour des instances spécifiques de "reader" ou "writer".

class csv.excel

   La classe "excel" définit les propriétés usuelles d'un fichier CSV
   généré par Excel.  Elle est enregistrée avec le nom de dialecte
   "'excel'".

class csv.excel_tab

   La classe "excel_tab" définit les propriétés usuelles d'un fichier
   CSV généré par Excel avec des tabulations comme séparateurs.  Elle
   est enregistrée avec le nom de dialecte "'excel-tab'".

class csv.unix_dialect

   La classe "unix_dialect" définit les propriétés usuelles d'un
   fichier CSV généré sur un système Unix, c'est-à-dire utilisant
   "'\n'" comme marqueur de fin de ligne et délimitant tous les champs
   par des guillemets.  Elle est enregistrée avec le nom de dialecte
   "'unix'".

   Nouveau dans la version 3.2.

class csv.Sniffer

   La classe "Sniffer" est utilisée pour déduire le format d'un
   fichier CSV.

   La classe "Sniffer" fournit deux méthodes :

   sniff(sample, delimiters=None)

      Analyse l'extrait donné (*sample*) et renvoie une sous-classe
      "Dialect" reflétant les paramètres trouvés.  Si le paramètre
      optionnel *delimiters* est donné, il est interprété comme une
      chaîne contenant tous les caractères valides de séparation
      possibles.

   has_header(sample)

      Analyse l'extrait de texte (présumé être au format CSV) et
      renvoie "True" si la première ligne semble être une série d'en-
      têtes de colonnes.

Un exemple d'utilisation de "Sniffer" :

   with open('example.csv', newline='') as csvfile:
       dialect = csv.Sniffer().sniff(csvfile.read(1024))
       csvfile.seek(0)
       reader = csv.reader(csvfile, dialect)
       # ... process CSV file contents here ...

Le module "csv" définit les constantes suivantes :

csv.QUOTE_ALL

   Indique aux objets "writer" de délimiter tous les champs par des
   guillemets.

csv.QUOTE_MINIMAL

   Indique aux objets "writer" de ne délimiter ainsi que les champs
   contenant un caractère spécial comme *delimiter*, *quotechar* ou
   n'importe quel caractère de *lineterminator*.

csv.QUOTE_NONNUMERIC

   Indique aux objets "writer" de délimiter ainsi tous les champs non-
   numériques.

   Indique au lecteur de convertir tous les champs non délimités par
   des guillemets vers des *float*.

csv.QUOTE_NONE

   Indique aux objets "writer" de ne jamais délimiter les champs par
   des guillemets.  Quand le *delimiter* courant apparaît dans les
   données, il est précédé sur la sortie par un caractère
   *escapechar*.  Si *escapechar* n'est pas précisé, le transcripteur
   lèvera une "Error" si un caractère nécessitant un échappement est
   rencontré.

   Indique au "reader" de ne pas opérer de traitement spécial sur les
   guillemets.

Le module "csv" définit les exceptions suivantes :

exception csv.Error

   Levée par les fonctions du module quand une erreur détectée.


14.1.2. Dialectes et paramètres de formatage
============================================

Pour faciliter la spécification du format des entrées et sorties, les
paramètres de formatage spécifiques sont regroupés en dialectes.  Un
dialecte est une sous-classe de "Dialect" avec un ensemble de méthodes
spécifiques et une méthode "validate()".  Quand un objet "reader" ou
"writer" est créé, vous pouvez spécifier une chaîne ou une sous-classe
de "Dialect" comme paramètre *dialect*.  En plus du paramètre
*dialect*, ou à sa place, vous pouvez aussi préciser des paramètres de
formatage individuels, qui ont les mêmes noms que les attributs de
"Dialect" définis ci-dessous.

Les dialectes supportent les attributs suivants :

Dialect.delimiter

   Une chaîne d'un seul caractère utilisée pour séparer les champs.
   Elle vaut "','" par défaut.

Dialect.doublequote

   Contrôle comment les caractères *quotechar* dans le champ doivent
   être retranscrits.  Quand ce paramètre vaut "True", le caractère
   est doublé. Quand il vaut "False", le caractère *escapechar* est
   utilisé comme préfixe à *quotechar*.  Il vaut "True" par défaut.

   En écriture, si *doublequote* vaut "False" et qu'aucun *escapechar*
   n'est précisé, une "Error" est levée si un *quotechar* est trouvé
   dans le champ.

Dialect.escapechar

   Une chaîne d'un seul caractère utilisée par le transcripteur pour
   échapper *delimiter* si *quoting* vaut "QUOTE_NONE", et pour
   échapper *quotechar* si *doublequote* vaut "False". À la lecture,
   *escapechar* retire toute signification spéciale au caractère qui
   le suit. Elle vaut par défaut "None", ce qui désactive
   l'échappement.

Dialect.lineterminator

   La chaîne utilisée pour terminer les lignes produites par un
   "writer". Elle vaut par défaut "'\r\n'".

   Note:

     La classe "reader" est codée en dur pour reconnaître "'\r'" et
     "'\n'" comme marqueurs de fin de ligne, et ignorer
     *lineterminator*. Ce comportement pourrait changer dans le futur.

Dialect.quotechar

   Une chaîne d'un seul caractère utilisée pour délimiter les champs
   contenant des caractères spéciaux, comme *delimiter* ou
   *quotechar*, ou contenant un caractère de fin de ligne.  Elle vaut
   "'"'" par défaut.

Dialect.quoting

   Contrôle quand les guillemets doivent être générés par le
   transcripteur et reconnus par le lecteur.  Il peut prendre comme
   valeur l'une des constantes "QUOTE_*" (voir la section Contenu du
   module) et vaut par défaut "QUOTE_MINIMAL".

Dialect.skipinitialspace

   Quand il vaut "True", les espaces suivant directement *delimiter*
   sont ignorés. Il vaut "False" par défaut.

Dialect.strict

   Quand il vaut "True", une exception "Error" est levée lors de
   mauvaises entrées CSV. Il vaut "False" par défaut.


14.1.3. Objets lecteurs
=======================

Les objets lecteurs (instances de "DictReader" ou objets renvoyés par
la fonction "reader()") ont les méthodes publiques suivantes :

csvreader.__next__()

   Renvoie la ligne suivante de l'objet itérable du lecteur en tant
   que liste (si l'objet est renvoyé depuis "reader()") ou
   dictionnaire (si l'objet est un "DictReader"), analysé suivant le
   dialecte courant.  Généralement, vous devez appeler la méthode à
   l'aide de "next(reader)".

Les objets lecteurs ont les attributs publics suivants :

csvreader.dialect

   Une description en lecture seule du dialecte utilisé par
   l'analyseur.

csvreader.line_num

   Le nombre de lignes lues depuis l'itérateur source. Ce n'est pas
   équivalent au nombre d'enregistrements renvoyés, puisque certains
   enregistrements peuvent s'étendre sur plusieurs lignes.

Les objets *DictReader* ont les attributs publics suivants :

csvreader.fieldnames

   S'il n'est pas passé comme paramètre à la création de l'objet, cet
   attribut est initialisé lors du premier accès ou quand le premier
   enregistrement est lu depuis le fichier.


14.1.4. Objets transcripteurs
=============================

Les objets "Writer" (instances de "DictWriter" ou objets renvoyés par
la fonction "writer()") ont les méthodes publiques suivantes.  Une
*row* doit être un itérable de chaînes de caractères ou de nombres
pour les objets "Writer", et un dictionnaire associant des noms de
champs à des chaînes ou des nombres (en les faisant d'abord passer par
"str()") pour les objets "DictWriter".  Notez que les nombres
complexes sont retranscrits entourés de parenthèses. Cela peut causer
quelques problèmes pour d'autres programmes qui liraient ces fichiers
CSV (en supposant qu'ils supportent les nombres complexes).

csvwriter.writerow(row)

   Écrit le paramètre *row* vers le fichier associé au transcripteur,
   formaté selon le dialecte courant.

   Modifié dans la version 3.5: Ajout du support d'itérables
   arbitraires.

csvwriter.writerows(rows)

   Écrit tous les éléments de *rows* (itérable d'objets *row* comme
   décrits précédemment) vers le fichier associé au transcripteur,
   formatés selon le dialecte courant.

Les objets transcripteurs ont les attributs publics suivants :

csvwriter.dialect

   Une description en lecture seule du dialecte utilisé par le
   transcripteur.

Les objets *DictWriter* ont les attributs publics suivants :

DictWriter.writeheader()

   Écrit une ligne contenant les noms de champs (comme spécifiés au
   constructeur).

   Nouveau dans la version 3.2.


14.1.5. Exemples
================

Le plus simple exemple de lecture d'un fichier CSV :

   import csv
   with open('some.csv', newline='') as f:
       reader = csv.reader(f)
       for row in reader:
           print(row)

Lire un fichier avec un format alternatif :

   import csv
   with open('passwd', newline='') as f:
       reader = csv.reader(f, delimiter=':', quoting=csv.QUOTE_NONE)
       for row in reader:
           print(row)

Le plus simple exemple d'écriture correspondant est :

   import csv
   with open('some.csv', 'w', newline='') as f:
       writer = csv.writer(f)
       writer.writerows(someiterable)

Puisque "open()" est utilisée pour ouvrir un fichier CSV en lecture,
le fichier sera par défaut décodé vers Unicode en utilisant l'encodage
par défaut (voir "locale.getpreferredencoding()").  Pour décoder un
fichier utilisant un encodage différent, utilisez l'argument
"encoding" de *open* :

   import csv
   with open('some.csv', newline='', encoding='utf-8') as f:
       reader = csv.reader(f)
       for row in reader:
           print(row)

La même chose s'applique lors de l'écriture dans un autre encodage que
celui par défaut du système : spécifiez l'encodage en argument lors de
l'ouverture du fichier de sortie.

Enregistrer un nouveau dialecte :

   import csv
   csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
   with open('passwd', newline='') as f:
       reader = csv.reader(f, 'unixpwd')

Un exemple d'utilisation un peu plus avancé du lecteur --- attrapant
et notifiant les erreurs :

   import csv, sys
   filename = 'some.csv'
   with open(filename, newline='') as f:
       reader = csv.reader(f)
       try:
           for row in reader:
               print(row)
       except csv.Error as e:
           sys.exit('file {}, line {}: {}'.format(filename, reader.line_num, e))

Et bien que le module ne permette pas d'analyser directement des
chaînes, cela peut être fait facilement :

   import csv
   for row in csv.reader(['one,two,three']):
       print(row)

-[ Notes ]-

[1] Si "newline=''" n'est pas spécifié, les caractères de fin de ligne
    embarqués dans des champs délimités par des guillemets ne seront
    pas interprétés correctement, et sur les plateformes qui utilisent
    "\r\n" comme marqueur de fin de ligne, un "\r" sera ajouté.  Vous
    devriez toujours spécifier sans crainte "newline=''", puisque le
    module *csv* gère lui-même les fins de lignes (*universelles*).
