\[ [Index](index.md) | [Exercise 5.4](ex5_4.md) | [Exercise 5.6](ex5_6.md) \] # Exercise 5.5 *Objectives:* - Learn more about exception handling and logging *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 >>> port = read_csv_as_dicts('Data/missing.csv', types=[str, int, float]) Traceback (most recent call last): File "", line 1, in 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 return list(map(lambda row: converter(headers, row), rows)) File "reader.py", line 13, in lambda headers, row: { name: func(val) for name, func, val in zip(headers, types, row) }) File "reader.py", line 13, in lambda headers, row: { name: func(val) for name, func, val in zip(headers, types, row) }) ValueError: invalid literal for int() with base 10: '' >>> ``` ## (a) Catching Exceptions 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: ```python >>> port = read_csv_as_dicts('Data/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()`. ## (b) Logging 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: ```python >>> import reader >>> import logging >>> logging.basicConfig(level=logging.DEBUG) >>> port = reader.read_csv_as_dicts('Data/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: '' >>> ``` \[ [Solution](soln5_5.md) | [Index](index.md) | [Exercise 5.4](ex5_4.md) | [Exercise 5.6](ex5_6.md) \] ---- `>>>` Advanced Python Mastery `...` A course by [dabeaz](https://www.dabeaz.com) `...` Copyright 2007-2023 ![](https://i.creativecommons.org/l/by-sa/4.0/88x31.png). This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)