Introduction
Objectives:
- Learn more about exception handling and logging
Files Modified: reader.py
Objectives:
Files Modified: reader.py
In the reader.py
file, there is a central function convert_csv()
that does most of the work. This function crashes if you run it on data with missing or bad data. For example:
$ python
>>> from reader import read_csv_as_dicts
>>> port = read_csv_as_dicts('missing.csv', types=[str, int, float])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "reader.py", line 24, in read_csv_as_dicts
return csv_as_dicts(file, types, headers=headers)
File "reader.py", line 13, in csv_as_dicts
lambda headers, row: { name: func(val) for name, func, val in zip(headers, types, row) })
File "reader.py", line 9, in convert_csv
return list(map(lambda row: converter(headers, row), rows))
File "reader.py", line 9, in <lambda>
return list(map(lambda row: converter(headers, row), rows))
File "reader.py", line 13, in <lambda>
lambda headers, row: { name: func(val) for name, func, val in zip(headers, types, row) })
File "reader.py", line 13, in <dictcomp>
lambda headers, row: { name: func(val) for name, func, val in zip(headers, types, row) })
ValueError: invalid literal for int() with base 10: ''
>>>
Instead of crashing on bad data, modify the code to issue a warning message instead. The final result should be a list of the rows that were successfully converted. For example:
>>> port = read_csv_as_dicts('missing.csv', types=[str, int, float])
Row 4: Bad row: ['C', '', '53.08']
Row 7: Bad row: ['DIS', '50', 'N/A']
Row 8: Bad row: ['GE', '', '37.23']
Row 13: Bad row: ['INTC', '', '21.84']
Row 17: Bad row: ['MCD', '', '51.11']
Row 19: Bad row: ['MO', '', '70.09']
Row 22: Bad row: ['PFE', '', '26.40']
Row 26: Bad row: ['VZ', '', '42.92']
>>> len(port)
20
>>>
Note: Making this change may be a bit tricky because of your previous use of the map()
built-in function. You may have to abandon that approach since there's no easy way to catch and handle exceptions in map()
.
Modify the code so that warning messages are issued using the logging
module. In addition, give optional debugging information indicating the reason for failure. For example:
>>> import reader
>>> import logging
>>> logging.basicConfig(level=logging.DEBUG)
>>> port = reader.read_csv_as_dicts('missing.csv', types=[str, int, float])
WARNING:reader:Row 4: Bad row: ['C', '', '53.08']
DEBUG:reader:Row 4: Reason: invalid literal for int() with base 10: ''
WARNING:reader:Row 7: Bad row: ['DIS', '50', 'N/A']
DEBUG:reader:Row 7: Reason: could not convert string to float: 'N/A'
WARNING:reader:Row 8: Bad row: ['GE', '', '37.23']
DEBUG:reader:Row 8: Reason: invalid literal for int() with base 10: ''
WARNING:reader:Row 13: Bad row: ['INTC', '', '21.84']
DEBUG:reader:Row 13: Reason: invalid literal for int() with base 10: ''
WARNING:reader:Row 17: Bad row: ['MCD', '', '51.11']
DEBUG:reader:Row 17: Reason: invalid literal for int() with base 10: ''
WARNING:reader:Row 19: Bad row: ['MO', '', '70.09']
DEBUG:reader:Row 19: Reason: invalid literal for int() with base 10: ''
WARNING:reader:Row 22: Bad row: ['PFE', '', '26.40']
DEBUG:reader:Row 22: Reason: invalid literal for int() with base 10: ''
WARNING:reader:Row 26: Bad row: ['VZ', '', '42.92']
DEBUG:reader:Row 26: Reason: invalid literal for int() with base 10: ''
>>>
Congratulations! You have completed the Exception Handling and Logging lab. You can practice more labs in LabEx to improve your skills.