I want to handle certain exceptions by catching the exception and issuing a warning. When the warning is displayed (e.g. on stderr or in a log file, I use the logging module for that) I want it to display the stack trace of the warning followed by "caused by" plus the stack trace of the original exception.
If I were to raise another exception I would use the from keyword (assume XException, YException are custom exception classes derived from Exception and YWarning is derived from the Warning class):
def do_x():
riase XException("Failed to do X")
def do_y():
try:
# do other things
do_x()
# maybe do some more things
except XException as x_exc:
raise YException("Failed to do Y") from x_exc
But in my case, if doing X fails, it's not such a big deal and I can continue to do Y. I want to issue a warning though.
from warnings import warn
def do_x():
raise XException("Failed to do X")
def do_y():
try:
# do other things
do_x() # if this fails, we can live with it
except XException as x_exc:
warn(YWarning("Things went not so smooth with doing Y", cause=x_exc))
Here I made up the cause= optional argument, so what I'd like to know is how do I instantiate any Exception subclass (which includes Warning and its subclasses) and specify the cause.
So while writing this question I came up with a possible answer.
ywarn = YWarning("Things went not so smooth with doing Y")
ywarn.__cause__ = x_exc
warn(ywarn)
It turns out, according to PEP 3134, that from does exactly that.
One could even actually implement the imaginary cause= optional argument. After all, the YWarning is a custom subclass.
class YWarning(Warning):
def __init__(self, msg, cause=None):
self.__cause__ = cause
Related
This example code worked in 2.x:
exc = None
try:
raise Exception
except Exception as exc:
pass
print(exc)
But in 3.x I get an error that says NameError: name 'exc' is not defined. If I put the code in a function instead, I get UnboundLocalError: local variable 'exc' referenced before assignment.
I thought perhaps I could work around the issue with an explicit assignment, like so:
exc = None
try:
raise Exception
except Exception as exc:
exc = exc
But this did not work. Why not? How can I access the exception from outside the except block?
The try statement explicitly limits the scope of the bound exception, to prevent circular references causing it to leak.
When an exception has been assigned using as target, it is cleared at the end of the except clause.
[...]
This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.
Emphasis mine; to use the exception afterward, it must be bound to a new name. exc = exc will not help because except isn't creating a new scope, but instead the name specified in the except statement is being removed from the scope.
In Python 2, exceptions did not have a reference to the traceback, so this clearing was not necessary to prevent the garbage collection problem. Now they do, so it changed.
However, even in Python 2, you are explicitly warned about cleaning up tracebacks:
Warning: Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. Since most functions don’t need access to the traceback, the best solution is to use something like exctype, value = sys.exc_info()[:2] to extract only the exception type and value. If you do need the traceback, make sure to delete it after use (best done with a try ... finally statement) or to call exc_info() in a function that does not itself handle an exception.
If you do re-bind the exception, you may want to clear the traceback explicitly:
try:
raise Exception("foo")
except Exception as e:
exc = e
exc.__traceback__ = None
I'm creating an interface Mixins that contains methods that will throw error if it is not implemented, however it only happens during run time when the method is called, i would like to have python check if method is implemented before run time.
class TestInterface():
def get_testing_name(self):
raise NotImplementedError
def do_something(self):
return self.get_testing_name()
class Testing(TestInterface):
def __init__(self):
super().do_something()
In my Testing class, i didn't defined get_testing_name method, hence it will raise NotImplementedError. However this will only happen on run time
How do i make sure python check if method is not implemented before run time?
I don't know if I understood you.
Maybe that was what you wanted ?:
try:
t = Testing()
except NotImplementedError:
print("Fail")
In JVM languages there is a data type called Optional which says value can be Null/None. By using the data type of a function as Option(for example Option(Int)). Calling statement of function can take action.
How does one implement a similar approach in Python.
I want to create a function and the return value of function should tell me
1. Function was successful so I have a value returned.
2. Function was not successful and so there is nothing to return.
I also wanted to tackle this problem and made a library called optional.py to do so. It can be installed using pip install optional.py. It is fully test covered and supports python2 and python3. Would love some feedback, suggestions, contributions.
To address the concerns of the other answer, and to head off any haters, yes, raising exceptions is more idiomatic of python, however it leads to ambiguity between exceptions for control-flow and exceptions for actual exceptional reasons.
There are large discussions about preventing defensive programming which mask the core logic of an application and smart people on both sides of the conversation. My personal preference is towards using optionals and so I provided the library to support that preference. Doing it with exceptions (or returning None) are acceptable alternatives, just not my preference.
To your original question: Raise an exception instead of returning None. This is an idiom in Python and therefore well understood by users. For example
def get_surname(name):
if name == "Monty":
return "Python"
else:
raise KeyError(name)
You'll see this usage pattern a lot in Python:
try:
print(get_surname("foo"))
except KeyError:
print("Oops, no 'foo' found")
Based on your feedback, it also seemed like you wanted to make sure that certain return values are actually used. This is quite tricky, and I don't think there is an elegant way to enforce this in Python, but I'll give it a try.
First, we'll put the return value in a property so we can track if it has indeed been read.
class Result(object):
def __init__(self, value):
self._value = value
self.used = False
#property
def value(self):
self.used = True # value was read
return self._value
Secondly, we require that the Result object must be retrieved in a with-block. When the block is exited (__exit__), we check if the value has been read. To handle cases where a user doesn't use the with-statement, we also check that the value has been read when it is being garbage collected (__del__). An exception there will be converted into a warning. I usually shy away from __del__ though.
class RequireUsage(object):
def __init__(self, value):
self._result = Result(value)
def __enter__(self):
return self._result
def __exit__(self, type, value, traceback):
if type is None: # No exception raised
if not self._result.used:
raise RuntimeError("Result was unused")
def __del__(self):
if not self._result.used:
raise RuntimeError("Result was unused (gc)")
To use this system, simply wrap the return value in RequireUsage like so:
def div2(n):
return RequireUsage(n/2)
To use such functions, wrap them in a block and extract the value:
with div2(10) as result:
print(result.value)
If you don't invoke result.value anywhere, you will now get an exception:
with div2(10) as result:
pass # exception will be thrown
Likewise, if you just call div2 without with at all, you will also get an exception:
div2(10) # will also raise an exception
I wouldn't particularly recommend this exact approach in real programs, because I feel it makes usage more difficult while adding little. Also, there are still edge-cases that aren't covered, like if you simply do res = div2(10), because a held reference prevents __del__ from being invoked.
One approach would be to return either () or (<type>,) (int in your case). You could then come up with some helper functions like this one:
def get_or_else(option: tuple, default):
if option:
return option[0]
else:
return default
One benefit of this approach is that you don't need to depend on a third-party library to implement this. As a counterpart, you basically have to make your own little library.
Is there any way to know the context in which an object is instantiated? So far I've been searching and tried inspect module (currentcontext) with poor results.
For example
class Item:
pass
class BagOfItems:
def __init__(self):
item_1 = Item()
item_2 = Item()
item_3 = Item()
I'd want to raise an exception in the instantiation of item_3 (because its outside a BagOfItems), while not doing so in item_1 and item_2. I dont know if a metaclass could be a solution to this, since the problem occurs at instantiation not at declaration.
The holder class (BagOfItems) can't implement the check because when Item intantiation happens outside it there would be no check.
When you instantiate an object with something like Item(), you are basically doing type(Item).__call__(), which will call Item.__new__() and Item.__init__() at some point in the calling sequence. That means that if you browse up the sequence of calls that led to Item.__init__(), you will eventually find code that does not live in Item or in type(Item). Your requirement is that the first such "context" up the stack belong to BagOfItem somehow.
In the general case, you can not determine the class that contains the method responsible for a stack frame1. However, if you make your requirement that you can only instantiate in a class method, you are no longer working with the "general case". The first argument to a method is always an instance of the class. We can therefore move up the stack trace until we find a method call whose first argument is neither an instance of Item nor a subclass of type(Item). If the frame has arguments (i.e., it is not a module or class body), and the first argument is an instance of BagOfItems, proceed. Otherwise, raise an error.
Keep in mind that the non-obvious calls like type(Item).__call__() may not appear in the stack trace at all. I just want to be prepared for them.
The check can be written something like this:
import inspect
def check_context(base, restriction):
it = iter(inspect.stack())
next(it) # Skip this function, jump to caller
for f in it:
args = inspect.getargvalues(f.frame)
self = args.locals[args.args[0]] if args.args else None
# Skip the instantiating calling stack
if self is not None and isinstance(self, (base, type(base))):
continue
if self is None or not isinstance(self, restriction):
raise ValueError('Attempting to instantiate {} outside of {}'.format(base.__name__, restriction.__name__))
break
You can then embed it in Item.__init__:
class Item:
def __init__(self):
check_context(Item, BagOfItems)
print('Made an item')
class BagOfItems:
def __init__(self):
self.items = [Item(), Item()]
boi = BagOfItems()
i = Item()
The result will be:
Made an item
Made an item
Traceback (most recent call last):
...
ValueError: Attempting to instantiate Item outside of BagOfItems
Caveats
All this prevents you from calling methods of one class outside the methods of another class. It will not work properly in a staticmethod or classmethod, or in the module scope. You could probably work around that if you had the motivation. I have already learned more about introspection and stack tracing than I wanted to, so I will call it a day. This should be enough to get you started, or better yet, show you why you should not continue down this path.
The functions used here might be CPython-specific. I really don't know enough about inspection to be able to tell for sure. I did try to stay away from the CPython-specific features as much as I could based on the docs.
References
1. Python: How to retrieve class information from a 'frame' object?
2. How to get value of arguments passed to functions on the stack?
3. Check if a function is a method of some object
4. Get class that defined method
5. Python docs: inspect.getargvalues
6. Python docs: inspect.stack
What is the indented lines directly below try: called/reffered to? I have heard "the body of try:" and "the expression of try:". Please clarify. (See user - poke´s - answer)
What is try:, except:, while: etc. reffered to? Like True and False are reffered to as "statements". (See user - poke´s - answer)
Is there any reason to change function1 into function2. The only difference between them is ValueError. The functions are only supposed to force the user to input an integer. (See user - poke´s - answer)
function1
def get_integer(LIMIT_PROMPT):
while True:
try:
return int(input(LIMIT_PROMPT))
except:
pass
I have seen lots of except statement: and in the body/expression there is a piece of code that does something if an error occured in the body/expression of try:
I have used this particular function in two programs and have not run into any trouble.
function2
def get_integer(LIMIT_PROMPT):
while True:
try:
return int(input(LIMIT_PROMPT))
except ValueError:
pass
Like True and False are referred to as "statements"
True and False are both variables referring to singleton values of the bool type. As variables, they are atomic expressions.
try, except, while etc. are statements, or more accurately, compound statements because they contain a group of other statements. Usually you would refer to that group of statements as a block, as in other languages they are encapsulated within block creating tokens (e.g. { and }). In the Python specification, they are being referred to as suite.
The suites of each compound statement does not really have a special name, so I guess you could just call them “try suite”, “except suite” etc., or “try block” and “except block”.
Is there any reason to change this function into this (the only change is ValueError)
Usually, when you check for exceptions, you should be as specific as possible. If you know that what you do within the try block can throw an exception of type X, then catch/except exception X only.
Not specifying a type will make the except catch any exception including those you might not know of that they could be thrown there, so you would lose useful information there. There are a lot questions on SO that already handle that topic, so I’ll just lead you to a random one I just found. Exception management is language agnostic, so you can just apply what you read to Python.