[Tutor] How to return a list in an exception object?

Martin A. Brown martin at linux-ip.net
Wed Jun 17 18:22:21 CEST 2015


Greetings David,

> I have a function that compares a set of files with a reference 
> set of files.  All files are compared and then, if any differences 
> were found, an exception is raised:

If you had been trying to compare files, I would have suggested 
examining difflib, but it sounds like you are more interested in set 
math on the elements of your file sets.

See a suggestion below for how to make sets work for you.

> class Error(Exception): pass
>
> def check_results(file_list):
>
>    <snip>
>
>    if isDifferent:
>        raise Error('One or more result files differ from the reference result files')
>
> I would like to pass back to the caller a list of the files that 
> failed. How would I include that list in the exception object?

While often, there is only text in the arguments supplied to 
Exception, you can stuff whatever you like in the args.  The first 
argument to Exception [0] should always be a human-readable string (text).
Here are two examples, the first supplying a list in the arguments:

   raise Exception("A hummingbird stole my boiled turnips.", range(4))
   # -- import os
   raise Exception("Where is my sock-eating goat?", dict(os.environ))

Now, back to the question of comparing file sets.  When you have two 
sets that you want to compare, there are many different ways to look 
at the differences.  I like computing once the full set of 
differences between sets and then working with the results.

When comparing two sets for what is missing, or what is extra, you end
up with three different output sets for any given set called A (your
reference set, let's say) and set called B (the subject of the test).

   same:    There's a set of elements present in both A and B.
   only_a:  There's a set of elements present only in A.
   only_b:  There's a set of elements present only in B.

In this case, you are particularly interested in the 'only_a' set.
These are the files (in your problem) which are in your reference set,
but not the other set/list.

But, don't forget that there are files in B that may not be in A!
Depending on what you are doing with this file set, you may be
undertaking extra work, or risking loss.  [I imagine a file deleter or
file archiver which handles extra files.]

This may be more than you needed or wanted for solving your problem.  I
couldn't help having contributed my thoughts, though, because....I have
made this very mistake, myself.  Anyway, here's a function to show you
what I mean.

   def differing(a, b):
       a = set(a)
       b = set(b)
       same = a.intersection(b)
       a_only = a.difference(b)
       b_only = b.difference(a)
       return same, a_only, b_only

   # -- and now to use it

   import random
   a = random.sample(range(17), 10)
   b = random.sample(range(17), 10)
   same, a_only, b_only = differing(a, b)

If you wanted to make sure that there were no extra files, you could:

   assert 0 == len(b_only)

Anyway, there are many ways to use the above, if you like it.

I wish you exceptional luck,

-Martin

  [0] https://docs.python.org/2/library/difflib.html
  [1] https://docs.python.org/3/library/exceptions.html#Exception

-- 
Martin A. Brown
http://linux-ip.net/


More information about the Tutor mailing list