Reputation: 4287
Consider the following two modules, prog.py and err.py. both of which are examples of a much larger program that exhibits this problem. I need to separate out the functionality into smaller source files, each with a test bench.
Err.py includes a test bench. When it creates a prog object, depending on how the exception is called, the exception is caught or not.
It seems that even though prog.py imports err objects in a "from err import *" statement, the module name is still inferred (wrongly?), but seems the err it refers to is not the same one as the module itself
Is this a bug in Python 2.7 or is it intended behaviour?
simply get both files and run err.py to see what I mean..
The first file:
#prog.py
from err import *
class prog(object):
def func1(self):
raise MySubError
def func2(self):
doError()
And the second file:
#err.py
import prog
import inspect
import sys
class myError(Exception):
pass
class MySubError(myError):
pass
def doError():
raise MySubError
if __name__=="__main__":
p=prog.prog()
try:
doError()
except MySubError as er:
print type(er)
print "Captured 1"
except Exception as er:
print type(er)
print "Not Captured 1"
try:
p.func1()
except MySubError as er:
print type(er)
print "Captured 2"
except Exception as er:
print type(er)
print "Not captured 2"
try:
p.func2()
except MySubError as er:
print type(er)
print "Captured 3"
except Exception as er:
print type(er)
print "Not captured 3"
It seems to me as though somehow err should know what module it is and the exception should be err.MySubError, rather than just MySubError. I can get the module, but not the instance.....
Output:
<class '__main__.MySubError'>
Captured 1
<class 'test.MySubError'>
Not captured 2
<class 'test.MySubError'>
Not captured 3
Upvotes: 3
Views: 2061
Reputation: 50190
The problem is that python doesn't know err.py
is the same as your main script. Normally a module is only imported once, but when the main script imports itself as a module, python gets confused and you're actually loading err.py
twice. (I'm not aware of any good reason for that; maybe @Latty can be more specific).
You can see the problem with this simple script:
# File: recur.py
import recur
print "This is the module"
if __name__ == '__main__':
print "This is main"
If you run it you will not get infinite recursion, because modules are only imported once. But you'll see "This is the module" twice.
As long as your main script does not import itself (directly or indirectly), there's no problem with importing exceptions from one module to another. There's also no problem with having two interdependent modules A and B that each import the other: Try import A
and you'll see that each of them is only loaded once.
Edit: Though I really think you should avoid importing your main script as a module, I just thought of a fix for your example:
# err.py
...
if __name__=="__main__":
from prog.err import * # add this line
This will replace all the duplicate script classes with their module versions, and everything will work as intended.
Upvotes: 1
Reputation: 89017
The issue here is that err
actually acts as two different modules, essentially.
The main module that is run in Python is called __main__
. Everything executed is put into it's namespace. What is happening here is you are then importing the module into your other script and it's called err
, so they are not considered the same.
This is a little bit weird, but it's necessary to keep the way the Python import system works consistent. The best answer here is to move your exceptions outside of your script being called as __main__
. This is good design anyway, as you are essentially creating a circular import here.
Upvotes: 2