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'