Testing methods

Alex Martelli aleax at aleax.it
Sat Apr 19 15:25:45 EDT 2003


Anton Muhin wrote:
   ...
> try:
>      foo.absent_method()
> except (AttributeError, TypeError), e:
>      print "Failed. Message @%s@" % e, "Type: %s" % e.__class__.__name__
> else:
>      print "OK"

Careful!!!  There's a LITTLE trap here.  If foo DOES have absent_method
BUT that method's body propagates one of these exceptions, this will
catch the propagated exception AS IF it had been generated in the attempt
to access / call it.  You can split the access-and-call in two to help:

try:
    bound = foo_absent_method
    if not callable(bound):
        raise TypeError, "type %s is not callable" % type(bound)
except (AttributeError, TypeError), e:
    print "Failed. Message @%s@" % e, "Type: %s" % e.__class__.__name__
else:
    bound()
    print "OK"

this isn't QUITE satisfactory here, because, when compared to your
code, it doesn't correctly catch the case where foo.absent_method IS
both present and callable BUT requires at least one mandatory
argument.  Unfortunately, catching that particular case (which is
going to raise TypeError when bound is called) requires analyzing the
traceback to see if the TypeError is raised right at the call operation
or INSIDE the execution of bound -- too much trouble to be worth it,
IMHO.  Opinions may differ on this.  But I want to emphasize the
need to keep AS LITTLE AS POSSIBLE inside the try clause, to avoid
accidentally "masking" unexpected errors that should propagate; in
particular, it's OFTEN worth splitting an access-and-call such as

    someobject.amethod(args)

into a just-access-it part to keep inside the try clause:

    bound = someobject.amethod

and a separate just-call-it part to keep inside the else clause:

    bound(args)

so that errors caused INSIDE the body of bound don't accidentally
get trapped and reported as if they were something else (i.e. as
if they were errors caused by ACCESSING someobject.amethod).


Alex





More information about the Python-list mailing list