1. CSV Serialization

1.1. Reading data from CSV files

  • Good practice is to always set:

    • quotechar='"'
    • delimiter=','
Code Listing 1.26. Zapis do plików csv używając csv.DictReader()
import csv

"""
    "first_name", "last_name"
    "José", "Jiménez"
    "Matt", "Kowalski"
    "Иван", "Иванович"
    "Mark", "Watney"
"""


with open(r'filename.csv') as file:
    data = csv.DictReader(file, delimiter=',', quotechar='"')

    for row in data:
        print(row['first_name'], row['last_name'])

1.2. Writing to CSV files

  • Good practice is to always set:

    • quoting=csv.QUOTE_ALL
    • quotechar='"'
    • delimiter=','
    • lineterminator='\n'
Code Listing 1.27. Zapis do plików csv używając csv.DictWriter()
import csv

DATA = [
    {'first_name': 'José', 'last_name': 'Jiménez'},
    {'first_name': 'Mark', 'last_name': 'Watney'},
    {'first_name': 'Иван', 'last_name': 'Иванович'},
    {'first_name': 'Alex', 'last_name': 'Vogel'},
]


with open(r'filename.csv', mode='w') as file:
    writer = csv.DictWriter(
        f=file,
        fieldnames=['first_name', 'last_name'],
        delimiter=',',
        quotechar='"',
        quoting=csv.QUOTE_ALL,
        lineterminator='\n')

    writer.writeheader()

    for row in DATA:
        writer.writerow(row)

1.3. Parsing non-CSV files with csv.DictReader()

1.3.1. Parsing /etc/passwd

Code Listing 1.28. Parsing /etc/passwd file with csv.DictReader()
import csv


FIELDNAMES = ['username', 'password', 'uid', 'gid', 'full_name', 'home', 'shell']
"""
root:x:0:0:root:/root:/bin/bash
watney:x:1000:1000:Mark Watney:/home/watney:/bin/bash
jimenez:x:1001:1001:José Jiménez:/home/jimenez:/bin/bash
ivanovic:x:1002:1002:Иван Иванович:/home/ivanovic:/bin/bash
"""


with open(r'etc-passwd.txt') as file:
    content = csv.DictReader(file, fieldnames=FIELDNAMES, delimiter=':')

    for row in content:
        print(dict(row))

# {'username': 'root', 'password': 'x', 'uid': '0',...}
# {'username': 'bin', 'password': 'x', 'uid': '1',...}
# {'username': 'daemon', 'password': 'x', 'uid': '2',...}
# {'username': 'adm', 'password': 'x', 'uid': '3',...}
# {'username': 'shutdown', 'password': 'x', 'uid': '6',...}
# {'username': 'halt', 'password': 'x', 'uid': '7',...}
# {'username': 'nobody', 'password': 'x', 'uid': '99',...}
# {'username': 'sshd', 'password': 'x', 'uid': '74',...}
# {'username': 'peck', 'password': 'x', 'uid': '1000',...}
# {'username': 'jimenez', 'password': 'x', 'uid': '1001',...}
# {'username': 'ivanovic', 'password': 'x', 'uid': '1002',...}

1.3.2. Parsing Java properties file

Code Listing 1.29. Parsing sonar-project.properties file with csv.DictReader()
import csv

"""
    sonar.host.url=https://sonarcloud.io
    sonar.language=py
    sonar.sourceEncoding=UTF-8
    sonar.verbose=true
    sonar.projectKey=habitatOS
    sonar.projectName=habitatOS
    sonar.projectDescription=Operating System for analog extraterrestrial habitats.
"""

with open(r'sonar-project.properties') as file:
    
    config = csv.DictReader(
        file,
        fieldnames=['property', 'value'],
        delimiter='=',
        lineterminator='\n',
        quoting=csv.QUOTE_NONE)

    for line in config:
        property = line['property']
        value = line['value']
        print(f'{property} -> {value}')

1.4. Assignments

1.4.1. Reading csv

  1. Otwórz w przeglądarce podany powyżej URL

  2. Zapisz jego zawartość na dysku w miejscu gdzie masz skrypty w pliku iris.csv

  3. Korzystając z csv.DictReader wczytaj zawartość pliku

  4. Podaj jawnie encoding, delimiter oraz quotechar

  5. Nazwy poszczególnych kolumn:

    • Sepal length
    • Sepal width
    • Petal length
    • Petal width
    • Species
  6. Wypisz wiersze na ekranie

About:
  • Filename: csv_dictreader.py
  • Lines of code to write: 20 lines
  • Estimated time of completion: 10 min

1.4.2. Writing csv

  1. Za pomocą csv.DictWriter() zapisz do pliku CSV dane o zmiennej strukturze
  2. Podaj jawnie encoding, delimiter, quotechar quoting, lineterminator
  3. fieldnames nie może być wymienione wprost w skrypcie (zahardkodowane)
DATA = [
    {'first_name': 'José'},
    {'last_name': 'Jiménez'},
    {'first_name': 'Иван', 'last_name': 'Иванович'},
    {'first_name': 'Mark', 'last_name': 'Watney', 'born': 1961},
    {'first_name': 'José', 'born': 1961, 'first_step': 1969},
]
About:
  • Filename: csv_dictwriter.py
  • Lines of code to write: 8 lines
  • Estimated time of completion: 10 min
Hints:
  • To jest bardzo często występujący i użyteczny przykład
The whys and wherefores:
 
  • Umiejętność korzystania z modułu csv
  • Umiejętność iteracji po złożonych strukturach danych
  • Dynamiczne generowanie struktur danych na podstawie innych

1.4.3. Object serialization to CSV

  1. Użyj obiektu książka_adresowa z listingu Code Listing 1.30.
  2. Za pomocą csv.DictWriter() zapisz kontakty z książki adresowej w pliku
  3. Wszystkie pola muszą być zawsze w cudzysłowiach i oddzielone średnikami, kodowanie UTF-8.
  4. Jak zapisać w CSV dane relacyjne (kontakt ma wiele adresów)?
  5. Stwórz obiekty książki adresowej na podstawie danych odczytanych z pliku
Hints:
  • powtarzanie rekordów (user pozostaje ten sam) z innymi danymi adresowymi
  • dodawanie kolumn (ulica_1, miasto_1, panstwo_1, ulica_2, miasto_2, panstwo_2) i automatyczne generowanie fieldnames
  • wrzucenie danych jako string do jednego pola adres_1, adres_2, adres_3 i ustalenie separatora (np: średnik - ‘;’)
  • jedno pole adres (w ramach niego wszystkie adresy rozdzielone “;” a dane przecinkami “,”)
Code Listing 1.30. Address book
class Contact:
    def __init__(self, first_name, last_name, addresses=[]):
        self.first_name = first_name
        self.last_name = last_name
        self.addresses = addresses


class Address:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)


addressbook = [
    Contact(first_name='Matt', last_name='Kowalski', addresses=[
        Address(street='2101 E NASA Pkwy', city='Houston', state='Texas', code='77058', country='USA'),
        Address(street=None, city='Kennedy Space Center', code='32899', country='USA'),
        Address(street='4800 Oak Grove Dr', city='Pasadena', code='91109', country='USA'),
        Address(street='2825 E Ave P', city='Palmdale', state='California', code='93550', country='USA', data_urodzenia=None),
    ]),
    Contact(first_name='José', last_name='Jiménez'),
    Contact(first_name='Иван', last_name='Иванович', addresses=[]),
]
About:
  • Filename: csv_addressbook.py
  • Lines of code to write: 10 lines
  • Estimated time of completion: 20 min