Upload
ashley-craig
View
222
Download
0
Embed Size (px)
DESCRIPTION
TestingExceptions Things go wrong External
Citation preview
Exceptions
Copyright © Software Carpentry 2010This work is licensed under the Creative Commons Attribution LicenseSee http://software-carpentry.org/license.html for more information.
Testing
Testing Exceptions
Things go wrong
Testing Exceptions
Things go wrongExternal
Testing Exceptions
Things go wrongExternal– Missing or badly-formatted file
Testing Exceptions
Things go wrongExternal– Missing or badly-formatted fileInternal
Testing Exceptions
Things go wrongExternal– Missing or badly-formatted fileInternal– Bug in code
Testing Exceptions
Things go wrongExternal– Missing or badly-formatted fileInternal– Bug in code
Testing Exceptions
Things go wrongExternal– Missing or badly-formatted fileInternal– Bug in codeHandling errors sensibly is easy
Testing Exceptions
Option #1: return status code
Testing Exceptions
Option #1: return status codeparams, status = read_params(param_file)if status != OK: log.error('Failed to read', param_file) sys.exit(ERROR)
grid, status = read_grid(grid_file)if status != OK: log.error('Failed to read', grid_file) sys.exit(ERROR)
Testing Exceptions
Option #1: return status code
This is what we really care about
params, status = read_params(param_file)if status != OK: log.error('Failed to read', param_file) sys.exit(ERROR)
grid, status = read_grid(grid_file)if status != OK: log.error('Failed to read', grid_file) sys.exit(ERROR)
Testing Exceptions
Option #1: return status code
The rest is error handling
params, status = read_params(param_file)if status != OK: log.error('Failed to read', param_file) sys.exit(ERROR)
grid, status = read_grid(grid_file)if status != OK: log.error('Failed to read', grid_file) sys.exit(ERROR)
Testing Exceptions
Hard to see the forest for the trees
Testing Exceptions
Hard to see the forest for the trees
Expectedflow of control
Testing Exceptions
Hard to see the forest for the trees
Expectedflow of control
Errorhandling
Testing Exceptions
Hard to see the forest for the trees
Expectedflow of control
Errorhandling
So people don't even try to handle errors
Testing Exceptions
Hard to see the forest for the trees
Expectedflow of control
Errorhandling
So people don't even try to handle errorsWhich makes them harder to find and fix whenthey do occur
Testing Exceptions
Option #2: use exceptions
Testing Exceptions
Option #2: use exceptionsSeparate "normal" operation from code thathandles "exceptional" cases
Testing Exceptions
Option #2: use exceptionsSeparate "normal" operation from code thathandles "exceptional" casesMake both easier to understand
Testing Exceptions
Rearrange this...
params, status = read_params(param_file)if status != OK: log.error('Failed to read', param_file) sys.exit(ERROR)
grid, status = read_grid(grid_file)if status != OK: log.error('Failed to read', grid_file) sys.exit(ERROR)
Testing Exceptions
...to put "normal" code in one place...
params, status = read_params(param_file)if status != OK: log.error('Failed to read', param_file) sys.exit(ERROR)
grid, status = read_grid(grid_file)if status != OK: log.error('Failed to read', grid_file) sys.exit(ERROR)
params = read_params(param_file) grid = read_grid(grid_file)
Testing Exceptions
...and error handling code in another
params, status = read_params(param_file)if status != OK: log.error('Failed to read', param_file) sys.exit(ERROR)
grid, status = read_grid(grid_file)if status != OK: log.error('Failed to read', grid_file) sys.exit(ERROR)
params = read_params(param_file) grid = read_grid(grid_file)
log.error('Failed to read', filename) sys.exit(ERROR)
Testing Exceptions
...and error handling code in another
params, status = read_params(param_file)if status != OK: log.error('Failed to read', param_file) sys.exit(ERROR)
grid, status = read_grid(grid_file)if status != OK: log.error('Failed to read', grid_file) sys.exit(ERROR)
Only need one copy of the error handling code
params = read_params(param_file) grid = read_grid(grid_file)
log.error('Failed to read', filename) sys.exit(ERROR)
Testing Exceptions
Join the two parts with try and except
params, status = read_params(param_file)if status != OK: log.error('Failed to read', param_file) sys.exit(ERROR)
grid, status = read_grid(grid_file)if status != OK: log.error('Failed to read', grid_file) sys.exit(ERROR)
try: params = read_params(param_file) grid = read_grid(grid_file)except: log.error('Failed to read', filename) sys.exit(ERROR)
Testing Exceptions
You have seen exceptions before
Testing Exceptions
You have seen exceptions before>>> open('nonexistent.txt', 'r')IOError: No such file or directory: 'nonexistent.txt'
Testing Exceptions
You have seen exceptions before>>> open('nonexistent.txt', 'r')IOError: No such file or directory: 'nonexistent.txt'
>>> values = [0, 1, 2]>>> values[99]IndexError: list index out of range
Testing Exceptions
Use try and except to deal with them yourself
Testing Exceptions
Use try and except to deal with them yourself>>> try:... reader = open('nonexistent.txt', 'r')... except IOError:... print 'Whoops!'
Whoops!
Testing Exceptions
Use try and except to deal with them yourself>>> try:... reader = open('nonexistent.txt', 'r')... except IOError:... print 'Whoops!'
Whoops! Blue indicates regular output
Testing Exceptions
Use try and except to deal with them yourself>>> try:... reader = open('nonexistent.txt', 'r')... except IOError:... print 'Whoops!'
Whoops! Try to do this...
Testing Exceptions
Use try and except to deal with them yourself>>> try:... reader = open('nonexistent.txt', 'r')... except IOError:... print 'Whoops!'
Whoops! ...and do this ifan IO error occurs
Testing Exceptions
Use try and except to deal with them yourself
...and do this ifan IO error occurs'IOError' is how Pythonreports 'file not found'
>>> try:... reader = open('nonexistent.txt', 'r')... except IOError:... print 'Whoops!'
Whoops!
Testing Exceptions
Can put many lines of code in a try block
Testing Exceptions
Can put many lines of code in a try blockAnd handle several errors afterward
Testing Exceptions
Can put many lines of code in a try blockAnd handle several errors afterward
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError: log_error_and_exit('IO error')except ArithmeticError: log_error_and_exit('Arithmetic error')
Testing Exceptions
Try to do this
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError: log_error_and_exit('IO error')except ArithmeticError: log_error_and_exit('Arithmetic error')
Can put many lines of code in a try blockAnd handle several errors afterward
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError: log_error_and_exit('IO error')except ArithmeticError: log_error_and_exit('Arithmetic error')
Handle I/Oerrors here
Can put many lines of code in a try blockAnd handle several errors afterward
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError: log_error_and_exit('IO error')except ArithmeticError: log_error_and_exit('Arithmetic error')
and numericalerrors here
Can put many lines of code in a try blockAnd handle several errors afterward
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError: log_error_and_exit('IO error')except ArithmeticError: log_error_and_exit('Arithmetic error')
These messagesaren't very helpful
Can put many lines of code in a try blockAnd handle several errors afterward
Testing Exceptions
Python 2.6
try: x = 1/0except Exception, error: print error
Testing Exceptions
Python 2.6
try: x = 1/0except Exception, error: print error
Stores information about what went wrong
Testing Exceptions
Python 2.6
try: x = 1/0except Exception, error: print error
Stores information about what went wrongDifferent information for different kinds of errors
Testing Exceptions
Python 2.6
try: x = 1/0except Exception, error: print error
Python 2.7
try: x = 1/0except Exception as error: print error
More readable
Testing Exceptions
Better error messages
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError as err: log_error_and_exit('Cannot read/write' + err.filename)except ArithmeticError as err: log_error_and_exit(err.message)
Better error messages
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError as err: log_error_and_exit('Cannot read/write' + err.filename)except ArithmeticError as err: log_error_and_exit(err.message)
Better error messages
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError as err: log_error_and_exit('Cannot read/write' + err.filename)except ArithmeticError as err: log_error_and_exit(err.message)
Better error messagesHelp user figure outwhich file
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError as err: log_error_and_exit('Cannot read/write' + err.filename)except ArithmeticError as err: log_error_and_exit(err.message)
Better error messages
No worse thanthe default
Testing Exceptions
A question of style
Testing Exceptions
A question of style
try: grid = read_grid(grid_file)except IOError: grid = default_grid()
Testing Exceptions
A question of style
if file_exists(grid_file): grid = read_grid(grid_file)else: grid = default_grid()
try: grid = read_grid(grid_file)except IOError: grid = default_grid()
Testing Exceptions
try: grid = read_grid(grid_file)except IOError: grid = default_grid()
A question of style
if file_exists(grid_file): grid = read_grid(grid_file)else: grid = default_grid()
Use exceptions for exceptional cases
Testing Exceptions
Another question of style
Testing Exceptions
Another question of styleBut first...
Testing Exceptions
Exceptions can be thrown a long way
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError as err: log_error_and_exit('Cannot read/write' + err.filename)except ArithmeticError as err: log_error_and_exit(err.message)
Exceptions can be thrown a long way
Testing Exceptions
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError as err: log_error_and_exit('Cannot read/write' + err.filename)except ArithmeticError as err: log_error_and_exit(err.message)
These arefunction calls
Exceptions can be thrown a long way
Testing Exceptions
Any errorsthey don'tcatch...
Exceptions can be thrown a long way
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError as err: log_error_and_exit('Cannot read/write' + err.filename)except ArithmeticError as err: log_error_and_exit(err.message)
Testing Exceptions
Exceptions can be thrown a long way
try: params = read_params(param_file) grid = read_grid(grid_file) entropy = lee_entropy(params, grid) write_entropy(entropy_file, entropy)except IOError as err: log_error_and_exit('Cannot read/write' + err.filename)except ArithmeticError as err: log_error_and_exit(err.message)
...are caughtand handledhere
Testing Exceptions
"Throw low, catch high"
Testing Exceptions
"Throw low, catch high"Many places where errors might occur
Testing Exceptions
"Throw low, catch high"Many places where errors might occurOnly a few where they can sensibly be handled
Testing Exceptions
"Throw low, catch high"Many places where errors might occurOnly a few where they can sensibly be handledA linear algebra library doesn't know how itscallers will want to report errors...
Testing Exceptions
"Throw low, catch high"Many places where errors might occurOnly a few where they can sensibly be handledA linear algebra library doesn't know how itscallers will want to report errors......so it shouldn't try to handle them itself
Testing Exceptions
You can raise exceptions yourself
Testing Exceptions
You can raise exceptions yourselfshould
Testing Exceptions
You can raise exceptions yourselfshould
def read_grid(grid_file): '''Read grid, checking consistency.'''
data = read_raw_data(grid_file) if not grid_consistent(data): raise Exception('Inconsistent grid: ' + grid_file) result = normalize_grid(data)
return result
Testing Exceptions
You can raise exceptions yourselfshould
def read_grid(grid_file): '''Read grid, checking consistency.'''
data = read_raw_data(grid_file) if not grid_consistent(data): raise Exception('Inconsistent grid: ' + grid_file) result = normalize_grid(data)
return result
Testing Exceptions
You can define new types of exceptions too
Testing Exceptions
You can define new types of exceptions tooshould
Testing Exceptions
You can define new types of exceptions tooshould
Need to understand classes and objects first
July 2010
created by
Greg Wilson
Copyright © Software Carpentry 2010This work is licensed under the Creative Commons Attribution LicenseSee http://software-carpentry.org/license.html for more information.