Exercise: Away From Raw Dictionaries#

Requirement#

Up to the past two iterations (Exercise: Refactoring - Extract Both CSV Formats Into Module and Exercise: Convert User Record To JSON And Back), we have represented the Persons as raw dictionaries of the following form:

{
    'id': 2,    # int
    'firstname': 'Jörg',
    'lastname': 'Faschingbauer',
    'birth': '19.6.1966',
}

Now that we know what classes are, and which benefits they bring (Classes And Dictionaries), lets

  • design a class Person

  • re-implement all of the CSV stuff, by creating a parallel set of function that return Person objects instead of those dictionaries

Note

The lovely collections.namedtuple can be used to solve that problem.

Test Code#

The following tests cover the required class Person changes.

import userdb_csv


def test_noheader_person(tmpdir):
    with open(tmpdir/'noheader.csv', 'w', encoding='cp1252') as f:
        f.writelines([
            '1;"Jörg;DI";Faschingbauer;19.6.1966\n',
            '2;Caro;Faschingbauer;25.4.1997\n',
            '3;Johanna;Faschingbauer;11.6.1995\n',
            '4;Philipp;Lichtenberger;6.4.1986\n',
            '5;Elizabeth II;Queen;1.1.1900\n',
        ])

    users = list(userdb_csv.read_noheader_person(tmpdir/'noheader.csv'))

    assert type(users[0]) is userdb_csv.Person
    assert users[0].id == 1
    assert users[0].firstname == 'Jörg;DI'
    assert users[0].lastname == 'Faschingbauer'
    assert users[0].birth == '19.6.1966'

    assert type(users[1]) is userdb_csv.Person
    assert users[1].id == 2
    assert users[1].firstname == 'Caro'
    assert users[1].lastname == 'Faschingbauer'
    assert users[1].birth == '25.4.1997'

    assert type(users[2]) is userdb_csv.Person
    assert users[2].id == 3
    assert users[2].firstname == 'Johanna'
    assert users[2].lastname == 'Faschingbauer'
    assert users[2].birth == '11.6.1995'

    assert type(users[3]) is userdb_csv.Person
    assert users[3].id == 4
    assert users[3].firstname == 'Philipp'
    assert users[3].lastname == 'Lichtenberger'
    assert users[3].birth == '6.4.1986'

    assert type(users[4]) is userdb_csv.Person
    assert users[4].id == 5
    assert users[4].firstname == 'Elizabeth II'
    assert users[4].lastname == 'Queen'
    assert users[4].birth == '1.1.1900'

def test_must_not_use_global_variables_as_return_object(tmpdir):
    filename1 = tmpdir/'noheader1.csv'
    with open(filename1, 'w', encoding='cp1252') as f:
        f.writelines([
            '1;"Jörg;DI";Faschingbauer;19.6.1966\n',
            '2;Caro;Faschingbauer;25.4.1997\n',
            '3;Johanna;Faschingbauer;11.6.1995\n',
            '4;Philipp;Lichtenberger;6.4.1986\n',
            '5;Elizabeth II;Queen;1.1.1900\n',
        ])

    filename2 = tmpdir/'noheader2.csv'
    with open(filename2, 'w', encoding='cp1252') as f:
        f.writelines([
            '3;Johanna;Faschingbauer;11.6.1995\n',
            '4;Philipp;Lichtenberger;6.4.1986\n',
            '5;Elizabeth II;Queen;1.1.1900\n',
        ])

    users1 = list(userdb_csv.read_noheader_person(filename1))
    users2 = list(userdb_csv.read_noheader_person(filename2))

    assert len(users1) == 5
    assert len(users2) == 3
import userdb_csv


def test_header_person(tmpdir):
    with open(tmpdir/'header.csv', 'w', encoding='cp1252') as f:
        f.writelines([
            'ID;First name;Last name;Date of Birth\n',
            '1;"Jörg;DI";Faschingbauer;19.6.1966\n',
            '2;Caro;Faschingbauer;25.4.1997\n',
            '3;Johanna;Faschingbauer;11.6.1995\n',
            '4;Philipp;Lichtenberger;6.4.1986\n',
            '5;Elizabeth II;Queen;1.1.1900\n',
        ])
            
    users = list(userdb_csv.read_header_person(tmpdir/'header.csv'))

    assert type(users[0]) is userdb_csv.Person
    assert users[0].id == 1
    assert users[0].firstname == 'Jörg;DI'
    assert users[0].lastname == 'Faschingbauer'
    assert users[0].birth == '19.6.1966'

    assert type(users[1]) is userdb_csv.Person
    assert users[1].id == 2
    assert users[1].firstname == 'Caro'
    assert users[1].lastname == 'Faschingbauer'
    assert users[1].birth == '25.4.1997'

    assert type(users[2]) is userdb_csv.Person
    assert users[2].id == 3
    assert users[2].firstname == 'Johanna'
    assert users[2].lastname == 'Faschingbauer'
    assert users[2].birth == '11.6.1995'

    assert type(users[3]) is userdb_csv.Person
    assert users[3].id == 4
    assert users[3].firstname == 'Philipp'
    assert users[3].lastname == 'Lichtenberger'
    assert users[3].birth == '6.4.1986'

    assert type(users[4]) is userdb_csv.Person
    assert users[4].id == 5
    assert users[4].firstname == 'Elizabeth II'
    assert users[4].lastname == 'Queen'
    assert users[4].birth == '1.1.1900'

def test_must_not_use_global_variables_as_return_object(tmpdir):
    filename1 = tmpdir/'noheader1.csv'
    with open(filename1, 'w', encoding='cp1252') as f:
        f.writelines([
            '1;"Jörg;DI";Faschingbauer;19.6.1966\n',
            '2;Caro;Faschingbauer;25.4.1997\n',
            '3;Johanna;Faschingbauer;11.6.1995\n',
            '4;Philipp;Lichtenberger;6.4.1986\n',
            '5;Elizabeth II;Queen;1.1.1900\n',
        ])

    filename2 = tmpdir/'noheader2.csv'
    with open(filename2, 'w', encoding='cp1252') as f:
        f.writelines([
            '3;Johanna;Faschingbauer;11.6.1995\n',
            '4;Philipp;Lichtenberger;6.4.1986\n',
            '5;Elizabeth II;Queen;1.1.1900\n',
        ])

    users1 = list(userdb_csv.read_noheader_person(filename1))
    users2 = list(userdb_csv.read_noheader_person(filename2))

    assert len(users1) == 5
    assert len(users2) == 3
from userdb_csv import Person
import userdb_json


def test_person_to_json():
    joerg = Person(
        id=1,
        firstname='Jörg',
        lastname='Faschingbauer',
        birth='19.6.1966',
    )

    joerg_sent = userdb_json.to_json_person(joerg)
    joerg_received = userdb_json.from_json_person(joerg_sent)

    assert joerg_received.id == 1
    assert joerg_received.firstname == 'Jörg'
    assert joerg_received.lastname == 'Faschingbauer'
    assert joerg_received.birth == '19.6.1966'