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

Nouveau dans la version 2.3.

The so-called CSV (Comma Separated Values) format is the most common
import and export format for spreadsheets and databases.  There is no
« CSV standard », so the format is operationally defined by the many
applications which read and write it.  The lack of a standard means
that subtle differences often exist in the data produced and consumed
by different applications.  These differences can make it annoying to
process CSV files from multiple sources.  Still, while the delimiters
and quoting characters vary, the overall format is similar enough that
it is possible to write a single module which can efficiently
manipulate such data, hiding the details of reading and writing the
data from the programmer.

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".

Note: This version of the "csv" module doesn’t support Unicode
  input. Also, there are currently some issues regarding ASCII NUL
  characters.  Accordingly, all input should be UTF-8 or printable
  ASCII to be safe; see the examples in section Exemples.

Voir aussi:

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


13.1.1. Contenu du module
=========================

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

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

   Return a reader object which will iterate over lines in the given
   *csvfile*. *csvfile* can be any object which supports the
   *iterator* protocol and returns a string each time its "next()"
   method is called — file objects and list objects are both suitable.
   If *csvfile* is a file object, it must be opened with the “b” flag
   on platforms where that makes a difference.  An optional *dialect*
   parameter can be given which is used to define a set of parameters
   specific to a particular CSV dialect.  It may be an instance of a
   subclass of the "Dialect" class or one of the strings returned by
   the "list_dialects()" function.  The other optional *fmtparams*
   keyword arguments can be given to override individual formatting
   parameters in the current dialect.  For full details about the
   dialect and formatting parameters, see section Dialectes et
   paramètres de formatage.

   Each row read from the csv file is returned as a list of strings.
   No automatic data type conversion is performed.

   Un court exemple d’utilisation :

      >>> import csv
      >>> with open('eggs.csv', 'rb') 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

   Modifié dans la version 2.5: The parser is now stricter with
   respect to multi-line quoted fields. Previously, if a line ended
   within a quoted field without a terminating newline character, a
   newline would be inserted into the returned field. This behavior
   caused problems when reading files which contained carriage return
   characters within fields. The behavior was changed to return the
   field without inserting newlines. As a consequence, if newlines
   embedded within fields are important, the input should be split
   into lines in a manner which preserves the newline characters.

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

   Return a writer object responsible for converting the user’s data
   into delimited strings on the given file-like object.  *csvfile*
   can be any object with a "write()" method.  If *csvfile* is a file
   object, it must be opened with the “b” flag on platforms where that
   makes a difference.  An optional *dialect* parameter can be given
   which is used to define a set of parameters specific to a
   particular CSV dialect.  It may be an instance of a subclass of the
   "Dialect" class or one of the strings returned by the
   "list_dialects()" function.  The other optional *fmtparams* keyword
   arguments can be given to override individual formatting parameters
   in the current dialect.  For full details about the dialect and
   formatting parameters, see section Dialectes et paramètres de
   formatage. To make it as easy as possible to interface with modules
   which implement the DB API, the value "None" is written as the
   empty string.  While this isn’t a reversible transformation, it
   makes it easier to dump SQL NULL data values to CSV files without
   preprocessing the data returned from a "cursor.fetch*" call. Floats
   are stringified with "repr()" before being written. All other non-
   string data are stringified with "str()" before being written.

   Un court exemple d’utilisation :

      import csv
      with open('eggs.csv', 'wb') 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)

   Associate *dialect* with *name*.  *name* must be a string or
   Unicode object. The dialect can be specified either by passing a
   sub-class of "Dialect", or by *fmtparams* keyword arguments, or
   both, with keyword arguments overriding parameters of the dialect.
   For full details about the dialect and formatting parameters, see
   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)

   Return the dialect associated with *name*.  An "Error" is raised if
   *name* is not a registered dialect name.

   Modifié dans la version 2.5: This function now returns an immutable
   "Dialect".  Previously an instance of the requested dialect was
   returned.  Users could modify the underlying class, changing the
   behavior of active readers and writers.

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.

   Nouveau dans la version 2.5.

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

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

   Create an object which operates like a regular reader but maps the
   information read into a dict whose keys are given by the optional
   *fieldnames* parameter.  The *fieldnames* parameter is a sequence
   whose elements are associated with the fields of the input data in
   order. These elements become the keys of the resulting dictionary.
   If the *fieldnames* parameter is omitted, the values in the first
   row of the file *f* will be used as the fieldnames.  If the row
   read has more fields than the fieldnames sequence, the remaining
   data is added as a sequence keyed by the value of *restkey*.  If
   the row read has fewer fields than the fieldnames sequence, the
   remaining keys take the value of the optional *restval* parameter.
   Any other optional or keyword arguments are passed to the
   underlying "reader" instance.

   Un court exemple d’utilisation :

      >>> import csv
      >>> with open('names.csv') as csvfile:
      ...     reader = csv.DictReader(csvfile)
      ...     for row in reader:
      ...         print(row['first_name'], row['last_name'])
      ...
      Baked Beans
      Lovely Spam
      Wonderful Spam

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

   Create an object which operates like a regular writer but maps
   dictionaries onto output rows.  The *fieldnames* parameter is a
   sequence of keys that identify the order in which values in the
   dictionary passed to the "writerow()" method are written to the
   file *f*.  The optional *restval* parameter specifies the value to
   be written if the dictionary is missing a key in *fieldnames*.  If
   the dictionary passed to the "writerow()" method contains a key not
   found in *fieldnames*, the optional *extrasaction* parameter
   indicates what action to take.  If it is set to "'raise'" a
   "ValueError" is raised. If it is set to "'ignore'", extra values in
   the dictionary are ignored. Any other optional or keyword arguments
   are passed to the underlying "writer" instance.

   Note that unlike the "DictReader" class, the *fieldnames* parameter
   of the "DictWriter" is not optional.  Since Python’s "dict" objects
   are not ordered, there is not enough information available to
   deduce the order in which the row should be written to the file
   *f*.

   Un court exemple d’utilisation :

      import csv

      with open('names.csv', 'w') 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.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', 'rb') 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.


13.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.


13.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()

   Return the next row of the reader’s iterable object as a list,
   parsed according to the current dialect.

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.

   Nouveau dans la version 2.5.

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.

   Modifié dans la version 2.6.


13.1.4. Objets transcripteurs
=============================

"Writer" objects ("DictWriter" instances and objects returned by the
"writer()" function) have the following public methods.  A *row* must
be a sequence of strings or numbers for "Writer" objects and a
dictionary mapping fieldnames to strings or numbers (by passing them
through "str()" first) for "DictWriter" objects.  Note that complex
numbers are written out surrounded by parens. This may cause some
problems for other programs which read CSV files (assuming they
support complex numbers at all).

csvwriter.writerow(row)

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

csvwriter.writerows(rows)

   Write all elements in *rows* (an iterable of *row* objects as
   described above) to the writer’s file object, formatted according
   to the current dialect.

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 2.7.


13.1.5. Exemples
================

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

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

Lire un fichier avec un format alternatif :

   import csv
   with open('passwd', 'rb') 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', 'wb') as f:
       writer = csv.writer(f)
       writer.writerows(someiterable)

Enregistrer un nouveau dialecte :

   import csv
   csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
   with open('passwd', 'rb') 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, 'rb') as f:
       reader = csv.reader(f)
       try:
           for row in reader:
               print row
       except csv.Error as e:
           sys.exit('file %s, line %d: %s' % (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

The "csv" module doesn’t directly support reading and writing Unicode,
but it is 8-bit-clean save for some problems with ASCII NUL
characters.  So you can write functions or classes that handle the
encoding and decoding for you as long as you avoid encodings like
UTF-16 that use NULs.  UTF-8 is recommended.

"unicode_csv_reader()" below is a *generator* that wraps "csv.reader"
to handle Unicode CSV data (a list of Unicode strings).
"utf_8_encoder()" is a *generator* that encodes the Unicode strings as
UTF-8, one string (or row) at a time.  The encoded strings are parsed
by the CSV reader, and "unicode_csv_reader()" decodes the
UTF-8-encoded cells back into Unicode:

   import csv

   def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
       # csv.py doesn't do Unicode; encode temporarily as UTF-8:
       csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
                               dialect=dialect, **kwargs)
       for row in csv_reader:
           # decode UTF-8 back to Unicode, cell by cell:
           yield [unicode(cell, 'utf-8') for cell in row]

   def utf_8_encoder(unicode_csv_data):
       for line in unicode_csv_data:
           yield line.encode('utf-8')

For all other encodings the following "UnicodeReader" and
"UnicodeWriter" classes can be used. They take an additional
*encoding* parameter in their constructor and make sure that the data
passes the real reader or writer encoded as UTF-8:

   import csv, codecs, cStringIO

   class UTF8Recoder:
       """
       Iterator that reads an encoded stream and reencodes the input to UTF-8
       """
       def __init__(self, f, encoding):
           self.reader = codecs.getreader(encoding)(f)

       def __iter__(self):
           return self

       def next(self):
           return self.reader.next().encode("utf-8")

   class UnicodeReader:
       """
       A CSV reader which will iterate over lines in the CSV file "f",
       which is encoded in the given encoding.
       """

       def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
           f = UTF8Recoder(f, encoding)
           self.reader = csv.reader(f, dialect=dialect, **kwds)

       def next(self):
           row = self.reader.next()
           return [unicode(s, "utf-8") for s in row]

       def __iter__(self):
           return self

   class UnicodeWriter:
       """
       A CSV writer which will write rows to CSV file "f",
       which is encoded in the given encoding.
       """

       def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
           # Redirect output to a queue
           self.queue = cStringIO.StringIO()
           self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
           self.stream = f
           self.encoder = codecs.getincrementalencoder(encoding)()

       def writerow(self, row):
           self.writer.writerow([s.encode("utf-8") for s in row])
           # Fetch UTF-8 output from the queue ...
           data = self.queue.getvalue()
           data = data.decode("utf-8")
           # ... and reencode it into the target encoding
           data = self.encoder.encode(data)
           # write to the target stream
           self.stream.write(data)
           # empty queue
           self.queue.truncate(0)

       def writerows(self, rows):
           for row in rows:
               self.writerow(row)
