Is it possible to prevent the initialization of a python object if an exception is catched in __init__?
Example
class pwm():
def __init__(self):
try:
wiring_pi = cdll.LoadLibrary('/home/lib.so')
except:
print "Problem with loading the library:", sys.exc_info()
#DON'T CREATE THE OBJECT, FOR IT IS USELES WITHOUT lib.so
You can raise an exception from __init__, sure. Then the caller will see the exception. Strictly speaking, the object has been created, but it will be reclaimed when the exception is thrown because there are no references to it.
In your example code, either omit the except clause entirely, or raise an exception from it.
Override __new__ and load the dll there. If it fails, raise an exception before the call to super().__new__(...) in __new__.
you can use a static methode who catch the execption in the init and then return None or whatever...
class AesSedai(object):
def __init__(name="Moiraine"):
wiring_pi = cdll.LoadLibrary('/home/lib.so')
#staticmethod
def create_wizard(cls,*args, **kwargs):
try:
wiring_pi = cdll.LoadLibrary('/home/lib.so')
return cls(*args, **kwargs)
except:
print "Problem with loading the library:", sys.exc_info()
return
Related
How can I catch the Exception from a method when I calling it in "clicked.connect".What I did was:
try:
self.parameter_search.clicked.connect(self.search.filter)
except Exception as e :
self.error_msg.setText(str(e))
self.error_msg.exec_()
def filter(self):
if self.path is None:
raise Exception("No file was choosen")
if self.Enter.text()=="":
raise Exception("No parameter was enterd")
value=self.Enter.text()
data=self.read_file(self.path)
choosen_parameter=self.parameter.currentText()
if choosen_parameter=="Choose a Paramter":
raise Exception("No Parameter was choosen")
if value.isdigit():
data=data[data[choosen_parameter]==str(float(value)).replace('.',',')]
else:
data=data[data[choosen_parameter]==str(value)]
if data.empty:
raise Exception("This Value isn't existed please try again!")
value=self.correct(value)
data.to_csv(self.dir+choosen_parameter+"="+value+".csv", index=False,sep=";")
self.prog_msg.exec_()
when I did it nothing happened what should I do to get to catch the Exception
It cannot, it should be understood that the connection only indicates to the Qt eventloop that when the signal is emitted then some callable will be invoked and nothing else.
If you want to handle an exception then an intermediate function:
self.parameter_search.clicked.connect(self.on_clicked)
def on_clicked(self):
try:
self.search.filter()
except Exception as e :
self.error_msg.setText(str(e))
self.error_msg.exec_()
I have a problem with inheriting from the ContextDecorator class. I can't understand why the method session_manager() works:
#contextmanager
def session_manager():
session = Session()
yield session
try:
session.commit()
except Exception as e:
session.rollback()
raise e
finally:
session.close()
But exactly the same code with ContextDecorator successor class gives an error:
class SessionManager(ContextDecorator):
def __init__(self):
self.session = Session()
def __enter__(self):
try:
yield self.session
self.session.commit()
except Exception as e:
self.session.rollback()
raise e
def __exit__(self, *exc):
self.session.close()
Exception:
AttributeError: 'generator' object has no attribute 'add'
The documentation and tutorials do not have complex examples (only with 'print' statements) and they works great: https://docs.python.org/3/library/contextlib.html
I don't understand why method session_manager() works, although it returns a generator:
yield session
Here I write some small and simple code:
https://gist.github.com/tranebaer/46f94263030dd8f7c1bfcf72d0e37610
The __enter__ method is not supposed to be a generator, unless you want to treat the return value as such in the runtime context. It is called when entering the block governed by the with-statement and its return value is bound to the target(s) specified in the as clause, if any. So the attribute error is the result of calling the method add() on the generator inside the block, when you meant it to be the Session object. Possible cleanup and exception handling should take place in the __exit__ method:
from contextlib import closing, ContextDecorator, ExitStack
class SessionManager(ContextDecorator):
def __init__(self, session_cls=Session):
self.session = session_cls()
def __enter__(self):
return self.session
def __exit__(self, type, value, tb):
with closing(self.session), ExitStack() as stack:
stack.callback(self.session.rollback)
if not value:
self.session.commit()
# If commit raises an exception, then rollback is left
# in the exit stack.
stack.pop_all()
Note that you don't need to inherit from ContextDecorator in order to make a context manager. Just implementing __enter__ and __exit__ is enough. In fact in this case it is a bit pointless, because a function decorated with SessionManager has no access to the Session object.
Question
Why do virtual subclasses of an abstract Exception created using the ABCMeta.register not match under the except clause?
Background
I'd like to ensure that exceptions that get thrown by a package that I'm using are converted to MyException, so that code which imports my module can catch any exception my module throws using except MyException: instead of except Exception so that they don't have to depend on an implementation detail (the fact that I'm using a third-party package).
Example
To do this, I've tried registering an OtherException as MyException using an abstract base class:
# Tested with python-3.6
from abc import ABC
class MyException(Exception, ABC):
pass
class OtherException(Exception):
"""Other exception I can't change"""
pass
MyException.register(OtherException)
assert issubclass(OtherException, MyException) # passes
try:
raise OtherException("Some OtherException")
except MyException:
print("Caught MyException")
except Exception as e:
print("Caught Exception: {}".format(e))
The assertion passes (as expected), but the exception falls to the second block:
Caught Exception: Some OtherException
Alright, I looked into this some more. The answer is that it's a long-outstanding open issue in Python3 (there since the very first release) and apparently was first reported in 2011. As Guido said in the comments, "I agree it's a bug and should be fixed." Unfortunately, this bug has lingered due to concerns about the performance of the fix and some corner cases that need to be handled.
The core issue is that the exception matching routine PyErr_GivenExceptionMatches in errors.c uses PyType_IsSubtype and not PyObject_IsSubclass. Since types and objects are supposed to be the same in python3, this amounts to a bug.
I've made a PR to python3 that seems to cover all of the issues discussed in the thread, but given the history I'm not super optimistic it's going to get merged soon. We'll see.
The why is easy:
from abc import ABC
class MyException(Exception, ABC):
pass
class OtherException(Exception):
"""Other exception I can't change"""
pass
MyException.register(OtherException)
assert issubclass(OtherException, MyException) # passes
assert OtherException in MyException.__subclasses__() # fails
Edit: This assert mimics the outcome of the except clause, but does not represent what actually happens. Look at the accept answer for an explanation.
The workaround also is easy:
class OtherException(Exception):
pass
class AnotherException(Exception):
pass
MyException = (OtherException, AnotherException)
It seems that CPython once again takes some shortcuts and doesn't bother calling the metaclass's __instancecheck__ method for the classes listed in except clauses.
We can test this by implementing a custom metaclass with __instancecheck__ and __subclasscheck__ methods:
class OtherException(Exception):
pass
class Meta(type):
def __instancecheck__(self, value):
print('instancecheck called')
return True
def __subclasscheck__(self, value):
print('subclasscheck called')
return True
class MyException(Exception, metaclass=Meta):
pass
try:
raise OtherException("Some OtherException")
except MyException:
print("Caught MyException")
except Exception as e:
print("Caught Exception: {}".format(e))
# output:
# Caught Exception: Some OtherException
We can see that the print statements in the metaclass aren't executed.
I don't know if this is intended/documented behavior or not. The closest thing to relevant information I could find was from the exception handling tutorial:
A class in an except clause is compatible with an exception if it is
the same class or a base class thereof
Does that mean that classes have to be real subclasses (i.e. the parent class must be part of the subclass's MRO)? I don't know.
As for a workaround: You can simply make MyException an alias of OtherException.
class OtherException(Exception):
pass
MyException = OtherException
try:
raise OtherException("Some OtherException")
except MyException:
print("Caught MyException")
except Exception as e:
print("Caught Exception: {}".format(e))
# output:
# Caught MyException
In the case that you have to catch multiple different exceptions that don't have a common base class, you can define MyException as a tuple:
MyException = (OtherException, AnotherException)
Well, this doesn't really answer your question directly, but if you're trying to ensure a block of code calls your exception, you could take a different strategy by intercepting with a context manager.
In [78]: class WithException:
...:
...: def __enter__(self):
...: pass
...: def __exit__(self, exc, msg, traceback):
...: if exc is OtherException:
...: raise MyException(msg)
...:
In [79]: with WithException():
...: raise OtherException('aaaaaaarrrrrrggggh')
...:
---------------------------------------------------------------------------
OtherException Traceback (most recent call last)
<ipython-input-79-a0a23168647e> in <module>()
1 with WithException():
----> 2 raise OtherException('aaaaaaarrrrrrggggh')
OtherException: aaaaaaarrrrrrggggh
During handling of the above exception, another exception occurred:
MyException Traceback (most recent call last)
<ipython-input-79-a0a23168647e> in <module>()
1 with WithException():
----> 2 raise OtherException('aaaaaaarrrrrrggggh')
<ipython-input-78-dba8b409a6fd> in __exit__(self, exc, msg, traceback)
5 def __exit__(self, exc, msg, traceback):
6 if exc is OtherException:
----> 7 raise MyException(msg)
8
MyException: aaaaaaarrrrrrggggh
My code:
class AError(Exception):
print 'error occur'
for i in range(3):
try:
print '---oo'
raise AError
except AError:
print 'get AError'
else:
print 'going on'
finally:
print 'finally'
When I run the above code, the output is this:
error occur
---oo
get AError
finally
---oo
get AError
finally
---oo
get AError
finally
I think the string "error occur" should occur three times, like "---oo", but it only occurs once; why?
To clarify Paul's answer, here's a simple example:
class Test(object):
print "Class being defined"
def __init__(self):
print "Instance being created"
for _ in range(3):
t = Test()
The output from this will be:
Class being defined
Instance being created
Instance being created
Instance being created
Code within the class definition but outside a method definition runs only once, when the class is defined.
If you want code to run whenever an instance is created, it should be in the __init__ instance method (or, occasionally, the __new__ class method). However, note that if you define __init__ for a subclass, you should probably ensure that it also calls the superclass's __init__:
class AError(Exception):
def __init__(self, *args, **kwargs):
Exception.__init__(self, *args, **kwargs) # call the superclass
print 'error occur' # print your message
This ensures that the subclass supports the arguments for the superclass; in the case of Exception, you can e.g. pass an error message:
>>> raise AError("Something went wrong.")
error occur # your message gets printed when the instance is created
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
raise AError("Something went wrong.")
AError: Something went wrong. # the error message passes through to the traceback
For an explanation of the *args, **kwargs syntax, if you aren't familiar with it, see e.g. What does ** (double star) and * (star) do for parameters?. You can also use super to call the superclass methods, see e.g. Understanding Python super() with __init__() methods.
'error occur' only gets printed once, for the entire class.
You probably expected it to get run for each instance of the class that was created.
For that to happen, put it in the __init__ function,
class AError(Exception):
def __init__(self):
print 'error occur'
__init__ is called when an instance of AError is created.
I strongly recommend not to place any print statements in your Exception, esp. not their constructors! Exceptions are semantic entities and you can print them out if you need to. If you must automate the printing at least use logging or a similar package.
What you might not be aware of is that you can collect the exception instance for use in the except clause like so:
class MyError(Exception):
pass
for i in range(3):
try:
print '---oo'
raise MyError("error msg no. {}".format(i))
# Exception usually always accept a string as their first parameter
except MyError, ex:
# Exception instance available inside the except clause as `ex`
print ex
else:
print 'going on'
finally:
print 'finally'
The 'error occur' string appears only one because Python executes it when parsing your AError class definition.
If you want to get it executed every time you create an instance of your class, you must define the class's initialiser:
class AError(Exception):
def __init__(self):
print 'error occur'
for i in range(3):
try:
print '---oo'
raise AError
except AError:
print 'get AError'
else:
print 'going on'
finally:
print 'finally'
Have fun (and read the language manual maybe...)
I was wondering, is there a simple magic method in python that allows customization of the behaviour of an exception-derived object when it is raised? I'm looking for something like __raise__ if that exists. If no such magic methods exist, is there any way I could do something like the following (it's just an example to prove my point):
class SpecialException(Exception):
def __raise__(self):
print('Error!')
raise SpecialException() #this is the part of the code that must stay
Is it possible?
I don't know about such magic method but even if it existed it is just some piece of code that gets executed before actually raising the exception object. Assuming that its a good practice to raise exception objects that are instantiated in-place you can put such code into the __init__ of the exception. Another workaround: instead of raising your exception directly you call an error handling method/function that executes special code and then finally raises an exception.
import time
from functools import wraps
def capture_exception(callback=None, *c_args, **c_kwargs):
"""捕获到异常后执行回调函数"""
assert callable(callback), "callback 必须是可执行对象"
def _out(func):
#wraps(func)
def _inner(*args, **kwargs):
try:
res = func(*args, **kwargs)
return res
except Exception as e:
callback(*c_args, **c_kwargs)
raise e
return _inner
return _out
def send_warning():
print("warning message..............")
class A(object):
#capture_exception(callback=send_warning)
def run(self):
print('run')
raise SystemError("测试异常捕获回调功能")
time.sleep(0.2)
if __name__ == '__main__':
a = A()
a.run()