views:

419

answers:

5

Example:

>>> try:
...    myapp.foo.doSomething()
... except Exception, e:
...    print 'Thrown from:', modname(e)

Thrown from: myapp.util.url

In the above example, the exception was actually thrown at myapp/util/url.py module. Is there a way to get the __name__ of that module?

My intention is to use this in logging.getLogger function.

A: 

This should do the trick:

import inspect
def modname():
    t=inspect.trace()
    if t:
        return t[-1][1]
Mark Roddy
That returns the module in which the Exception was *defined*, no?
Stephan202
@Stephan202: sorry, misunderstood the question, the above function will give you the name of the module that raised the errror
Mark Roddy
It returns the module name (`url`), but not the value of its `__name__` (`myapp.util.url`)
Sridhar Ratnakumar
I meant - `url.py`
Sridhar Ratnakumar
+3  A: 

You can use the traceback module, along with sys.exc_info(), to get the traceback programmatically:

try:
    myapp.foo.doSomething()
except Exception, e:
    exc_type, exc_value, exc_tb = sys.exc_info()
    filename, line_num, func_name, text = traceback.extract_tb(exc_tb)[-1]
    print 'Thrown from: %s' % filename
Adam Rosenfield
Filename is not the same as `__name__`
Sridhar Ratnakumar
filename + linenumber is more useful to me, so I appreciate this answer to the question :)
warpr
+4  A: 

This should work:

import inspect

try:
    some_bad_code()
except Exception, e:
    frm = inspect.trace()[-1]
    mod = inspect.getmodule(frm[0])
    print 'Thrown from', mod.__name__

EDIT: Stephan202 mentions a corner case. In this case, I think we could default to the file name.

import inspect

try:
    import bad_module
except Exception, e:
    frm = inspect.trace()[-1]
    mod = inspect.getmodule(frm[0])
    modname = mod.__name__ if mod else frm[1]
    print 'Thrown from', modname

The problem is that if the module doesn't get loaded (because an exception was thrown while reading the code in that file), then the inspect.getmodule call returns None. So, we just use the name of the file referenced by the offending frame. (Thanks for pointing this out, Stephan202!)

ars
Indeed this works. Note that there is a corner case in which it will fail, apparently (just tried): if some_bad_code() is an import statement which immediately causes an exception (because of some code in said module).
Stephan202
Good point, Stephan202. I've made an edit, which I hope addresses this adequately.
ars
@ars I've been implementing something like this recently. I think defaulting to a file name is not enough — I additionally look through sys.path and if the file name is a child of one of the entries, I make it relative. Sometimes this fails, because not every import is from sys.path, but if it succeeds, I can then remove the extension and replace('\\', '/').replace('/', '.') and most likely get the missing module name.
Andrey Tarantsov
A: 

Python's logging package already supports this - check the documentation. You just have to specify %(module)s in the format string. However, this gives you the module where the exception was caught - not necessarily the same as the one where it was raised. The traceback, of course, gives you the precise location where the exception was raised.

Vinay Sajip
I want to use `__name__` in `logging.getLogger` argument and not in the logger output.
Sridhar Ratnakumar
Let's step back a bit. Why is it so important to have it in the logger name? You can find the exact file and line number where the exception was thrown, which seems the most important thing.
Vinay Sajip
A: 

I have a story about how CrashKit computes class names and package names from Python stack traces on the company blog: “Python stack trace saga”. Working code included.

Andrey Tarantsov