Exit from subfunction of function to main - python

#!/usr/bin/env python
class Functions() :
def A(self):
print "hey"
self.B()
return 1
def B(self):
print "hello"
exit(0)
func_obj = Functions()
def main() :
A = func_obj.A()
print A
print "awesome"
if __name__ == '__main__' :
main()
Above is my code. What I'm trying to do is that I want to call functionA from the main() function and when functionA executes functionB, I want functionB to raise error and exit back to the main() function without going back to functionA. How can I achieve this? Basically I want the main function to print "awesome" after functionB exits. I'm not sure what is the correct keyword to look it up.

What you're looking for are exceptions - they are actually designed to do just this: break the normal flow of execution and propagate up the call stack until someone take care of them (as a last resort, the runtime will catch them, display the error message and a full traceback, and exit).
There are two parts to the process: first raising the exception, then catching it at the right place. In your example it might look like:
# declare our own exception type so we can catch specifically this one
class MyOwnException(Exception):
pass
def a():
print("in a - before b")
b()
print("in a - after b (shouldn't see this)")
def b():
print("in b, before raise")
raise MyOwnException("hello houston ?")
print("in b, after raise (shouldn't see this)")
if __name__ == "__main__":
print("calling a")
try:
a()
print("after a (shouldn't see this)")
except MyOwnException as e:
print("caugth error {}".format(e))
FWIW, your example using exit() was really close since exit() actually works by raising a SysExit exception. The first and main use case for exception is of course error handling, but it's actually really a way to control the execution flow of your program (as an example the StopIteration exception is used to signal an exhausted iterator).

Hey so after someone pointed out my original answer didnt work i went searching! you can create custom exception classes to achieve what you're looking for!
class HaltException(Exception):
pass
class Functions():
def a(self):
print("hey")
self.b()
return "1"
def b(self):
print("hello")
raise HaltException("This is an exception error.")
def main():
func_obj = Functions()
try:
func_obj.a()
except HaltException as error:
print(error)
print("Awesome")
if __name__ == "__main__":
main()
This would then return the following when run :
hey
hello
This is an exception error.
Awesome

Related

How to stop execution of python program using mock?

I'm using unittest and mock for testing a script which looks like this
class Hi:
def call_other(self):
perform some operation
sys.exit(1)
def f(self):
try:
res = self.do_something()
a = self.something_else(res)
except Exception as e:
print(e)
call_other()
print("hi after doing something") -----> (this_print)
def process(self)
self.f()
and my test script looks like this
class Test_hi(unittest.TestCase)
def mock_call_other(self):
print("called during error")
def test_fail_scenario():
import Hi class here
h = Hi()
h.process()
h.do_something = mock.Mock(retrun_value="resource")
h.something_else = mock.Mock(side_effect=Exception('failing on purpose for testing'))
h.call_other(side_effect=self.mock_call_other) -----> (this_line)
If I don't mock call_other method it will call sys.exit(1) and it will cause some problem in unittest running, so,
I don't want to call sys.exit(1) in call_other during testing.
However, if I mock call_other method as above (in this_line) it will simply print something and continue the execution of method f. Meaning, it will execute the print statement (in this_print)
That should not be the case in the real program, when the exception is caught it will do a sys.exit(1) and stop the program.
How can I achieve the same using unittest and mock when the exception is caught I want to stop the execution of this testcase and move on to next test case.
How to achieve this? Please help
You can use unittest's functionality to assert if you're expecting exceptions without the need of mock:
import unittest
import sys
class ToTest:
def foo(self):
raise SystemExit(1)
def bar(self):
sys.exit(1)
def foo_bar(self):
print("This is okay")
return 0
class Test(unittest.TestCase):
def test_1(self):
with self.assertRaises(SystemExit) as cm:
ToTest().foo()
self.assertEqual(cm.exception.code, 1)
def test_2(self):
with self.assertRaises(SystemExit) as cm:
ToTest().bar()
self.assertEqual(cm.exception.code, 1)
def test_3(self):
self.assertEqual(ToTest().foo_bar(), 0)

Call function or function (python)

I have 4 functions. I want my code to perform the first one AND the second, third, or fourth. I also want at least one (any of them) no matter what unless they all fail.
My initial implementation was:
try:
function1(var)
except:
pass
try:
function2(var) or function3(var) or function4(var)
except:
pass
If function2 doesn't work, it doesn't go to function3, how might this be coded to account for that?
In case the success of failure of a function is determined, whether it raises an exception or not, you could write a helper method, that would try to call a list of functions until a successful one returns.
#!/usr/bin/env python
# coding: utf-8
import sys
def callany(*funs):
"""
Returns the return value of the first successfully called function
otherwise raises an error.
"""
for fun in funs:
try:
return fun()
except Exception as err:
print('call to %s failed' % (fun.__name__), file=sys.stderr)
raise RuntimeError('none of the functions could be called')
if __name__ == '__main__':
def a(): raise NotImplementedError('a')
def b(): raise NotImplementedError('b')
# def c(): raise NotImplementedError('c')
c = lambda: "OK"
x = callany(a, b, c)
print(x)
# call to a failed
# call to b failed
# OK
The toy implementation above could be improved by adding support for function arguments.
Runnable snippet: https://glot.io/snippets/ehqk3alcfv
If the functions indicate success by returning a boolean value, you can use them just as in an ordinary boolean expression.

Function returns None instead raising Exception

I have the next code and it works well.
class AggregateException(Exception):
pass
class Class(object):
def some_method(self):
...
try:
if aggregate(count):
status = Checked
except AggregateException:
status = Rejected
...
def aggregate(count):
if <condition>:
raise AggregateException('Invalid count')
But when I try to simplify logic of some_method() I get an unexpected result. Below you can see code
class Class(object):
def some_method(self):
...
self.aggregate_count(count)
...
def aggregate_count(count):
try:
if aggregate(count):
status = Checked
except AggregateException:
status = Rejected
When an error occurs in aggregate_count(), some_method() continues to run instead finish.
I'm not entirely sure what do you want to do. But as far as I understood you'd like to keep the program running if an exception occur. And that's what your script is doing. The exceptstatement catches your exception and preventing your program from crashing (and change status). Thereafter the rest of the some_method-function is executed. If you want to see it on the command line simply print it in the except block.
If you'd like to crash your program and print the exception to the command line, remove the try and except statement.
Hope that helps.

Confused about try/except with custom Exception

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...)

try: except: not working

So I'm running into a problem where the try: except: mechanism doesn't seem to be working correctly in python.
Here are the contents of my two files.
pytest1.py
import pytest2
class MyError( Exception ):
def __init__( self, value ):
self.value = value
def __str__( self ):
return repr( self.value )
def func1():
raise MyError( 'This is an error' )
def func3():
pytest2.func2()
if __name__ == '__main__':
try:
func3()
except MyError, e:
print 'I should catch here.'
except:
print 'Why caught here?'
pytest2.py
from pytest1 import func1
def func2():
func1()
Executing the first file yields the following output:
$ python pytest1.py
Why caught here?
Basically, the exception isn't being caught. If I print out the exception type, it prints as <pytest1.MyError> instead of just <MyError>. I imagine that this is some weird cyclical reference thing, but it still seems like it should work.
The main python program is always imported as the module __main__.
When you import pytest2, it doesn't reuse the existing module because the originally imported module has the name __main__ not pytest2. The result is that pytest1 is run multiple times generating multiple exception classes. __main__.MyError and pytest1.MyError You end up throwing one and trying to catch the other.
So, don't try to import your main module from other modules.
This problem is caused by importing the script you are running as a module. This produces two separate copies of the module!
Another example:
module.py
import module
class Foo: pass
def test():
print Foo
print module.Foo
print Foo is module.Foo
if __name__ == '__main__': test()
main_script.py
import module
if __name__ == '__main__': module.test()
Result
>python main_script.py
module.Foo
module.Foo
True
>python module.py
__main__.Foo
module.Foo
False
Running python somefile.py creates a module called __main__, not somefile, and runs the code in somefile.py in that module. This is why if __name__ == '__main__': is used to check if this file is being run as a script or imported from some other file.
... at a guess, you have a namespace problem which is producing a different exception.
Try replacing
except:
print 'Why caught here?'
with
except Exception, e:
print e
This may tell you more about what went wrong.

Categories

Resources