capturing the error when using sys.exit() - python-3.x

Is it possible to capture the errors generated and return them to the caller script?
p1.py
def fun1():
try:
...
except Exception as err:
print('ERROR from p1.py')
sys.exit(1)
p2.py
import p1
def fun2():
try:
...
except Exception as err:
print('ERROR from p2.py')
sys.exit(1)
p3.py
import p2
#want to catch the errors here
errors1 = 'ERROR from p1.py'
errors2 = 'ERROR from p2.py'
Is there a way to get the errors from either p1.py ('ERROR from p1.py') or p2.py ('ERROR from p2.py') in p3.py?

One way could be chaging where you handle the exception when you execute the functions of the p1.py and p2.py file in the p3.py file, you can do a try-except in p3.py(instead of catching the exception inside of every function):
p3.py
from p1 import fun1
from p2 import fun2
# calling the function from p1.py
try:
fun1()
except Exception as err:
print('You have the error from fun1 in p1.py, you can make your logic here')
sys.exit(1)
# calling function from p2.py
try:
fun2()
except Exception as err:
print('You have the error from fun2 in p2.py, you can make your logic here')
sys.exit(1)

Related

catch exception while a calling a function from different .py file

I have a main_etl.py and watcher.py
main_etl.py
def test_function():
try:
do sometihng....
except Exception as e:
raise e
def main(arg1='', arg2='', arg3=''):
try:
test_function()
except Exception as e:
raise e
watcher.py
import main_etl
def main_function():
try:
main_etl.main(arg1='', arg2='', arg3='')
except Exception as e:
raise e
else:
do something....
And I am running - python watcher.py
I tried the above code, But it didn't catch any exception in the watcher.py file
I wanted to catch the exception in the calling function script (watcher.py).
Can anyone suggest me like how to catch this error or is there any other way of implementing this.
I know os.system() and subprocess.call(), But how can I call the main() function inside main_etl.py ?

In pytest, how to test for sys.exit('some error message')?

I'm a beginner to python and pytest. I have a function that I'm trying to test for the exceptions part with Pytest:
def read_data(args) -> tuple[Polyline, str]:
parsed_args = input_parsing_1(args)
try:
with open(parsed_args.f) as f_input:
reader = csv.reader(f_input)
polyline = fill_poly_with_data(reader)
except FileNotFoundError as e:
sys.exit('Invalid input file \n')
else:
return (polyline, parsed_args.f)
I want to test if exceptions are risen and if the error message matches the one I put in the code above.
My attempts
#patch('project.open')
def test_read_data_error_SE(mock_open):
mock_open.side_effect = SystemExit
with pytest.raises(SystemExit):
assert read_data(['-f', ''])
#patch('project.open')
def test_read_data_error_FNFE2(mock_open):
mock_open.side_effect = FileNotFoundError
with pytest.raises(SystemExit):
with pytest.raises(FileNotFoundError):
assert read_data(['-f', 'cos'])
The above tests works fine.
I also wish to assert if sys.exit message matches 'Invalid input file \n'. I've tried:
#patch('project.open')
def test_read_data_error_SE1(mock_open):
mock_open.side_effect = SystemExit
with pytest.raises(SystemExit, match='Invalid input file'):
assert read_data(['-f', ''])
#patch('project.open')
def test_read_data_error_SE2(mock_open):
mock_open.side_effect = SystemExit
with pytest.raises(SystemExit) as e:
assert read_data(['-f', ''])
assert 'Invalid input file' in str(e.value)
but those tests fails:
===================================================== short test summary info ======================================================
FAILED test_project.py::test_read_data_error_SE1 - AssertionError: Regex pattern did not match.
FAILED test_project.py::test_read_data_error_SE2 - AssertionError: assert 'Invalid input file' in ''
I have seen some posts here on stackoverflow, like:
Verify the error code or message from SystemExit in pytest
How to properly assert that an exception gets raised in pytest?
Catch SystemExit message with Pytest
but none of them seems to answer my problem.
My questions:
It seems like my tested message 'Invalid input file' is being matched to an empty string ''? Why? How to properly catch and assert the sys.exit('some error message')?
You're seeing an empty string because you're raising SystemExit with no parameters:
#patch('project.open')
def test_read_data_error_SE1(mock_open):
mock_open.side_effect = SystemExit
with pytest.raises(SystemExit, match='Invalid input file'):
assert read_data(['-f', ''])
You've set mock_open.side_effect = SystemExit, so when you're code calls open(), it raises SystemExit with no parameters. If you want to see a message like Invalid input file, have your code explicitly exit by calling sys.exit('Invalid input file').
Your code already does that, but you're pre-empting that behavior by having the call to open raise SystemExit instead. You probably want open to raise FileNotFound instead:
#patch('project.open')
def test_read_data_error_SE1(mock_open):
mock_open.side_effect = FileNotFound
with pytest.raises(SystemExit, match='Invalid input file'):
assert read_data(['-f', ''])
This will get caught by the except in read_data, which will then call sys.exit.
Here's a complete example (I've included some stub functions here so that I can use your read_data method largely unmodified):
import csv
import sys
import types
import pytest
from unittest import mock
def fill_poly_with_data(x):
return x
def input_parsing_1(args):
return types.SimpleNamespace(f="testing")
def read_data(args) -> tuple:
parsed_args = input_parsing_1(args)
try:
with open(parsed_args.f) as f_input:
reader = csv.reader(f_input)
polyline = fill_poly_with_data(reader)
except FileNotFoundError:
sys.exit('Invalid input file \n')
else:
return (polyline, parsed_args.f)
#mock.patch('builtins.open')
def test_function_that_exits(mock_open):
mock_open.side_effect = FileNotFoundError
with pytest.raises(SystemExit, match="Invalid input file"):
read_data(['-f', 'cos'])

How to raise an exception and catch it after function execution complete?

I have a line in my code that has the potential to raise an exception, i would like to handle this execption and continue execution.
def foo():
#good code
if thingThatHappensSometimes:
raise CustomException
#code i want to execute
return resultIwant
def bar():
resultIwant = None
try:
#good code
resultIwant = foo()
except CustomException:
#code that should run if an exception was raised
finally:
print(resultIwant)
print('All done!')
My issue here is that there are situations where foo will raise an exception but there is nothing in the code logic preventing it from generating a result for resultIwant. Currently, if I handle the exception in bar I will not reach the end of execution for foo but If I handle the exception in foo the exception will already be handled and I will not reach the except block in bar. is there a way to solve this issue?
raising an exception stops execution at this point, so you cannot both raise an exception and return a value. But you can return a (value, exception_or_none) tuple:
def foo():
error = None
#good code
if thingThatHappensSometimes:
error = CustomException()
#code i want to execute
return resultIwant, error
def bar():
#good code
resultIwant, error = foo()
if error:
#code that should run if an exception was raised
print(resultIwant)
print('All done!')

why is it not catching index errror?

def dict_items(dict1):
try:
d2={}
for k in dict1.keys():
d2[k+1]=dict1[k]+k
dict1[k]=d2[k]
except IndexError:
print("IndexError")
except ValueError:
print("ValueError")
finally:
print("Finally done")
try:
dict_items({1:1,2:22,3:33})
print("function call done")
except:
print("Exception")
finally:
print("inside finally")
The above executes correctly and prints
Finally done
Exception
inside finally
why is not catching index error is there anything I am missing?
A bare except: isn't very useful. Catch the exception as print its type to see your error:
def dict_items(dict1):
try:
d2={}
for k in dict1.keys():
d2[k+1]=dict1[k]+k
dict1[k]=d2[k]
except IndexError:
print("IndexError")
except ValueError:
print("ValueError")
finally:
print("Finally done")
try:
dict_items({1:1,2:22,3:33})
print("function call done")
except Exception as e:
print("Exception",type(e))
finally:
print("inside finally")
Output:
Finally done
Exception <class 'KeyError'>
inside finally
Dictionaries throw KeyError not IndexError when the key doesn't exist, so the dict_items try block catches nothing and prints Finally done, then the outer try catches the KeyError in the bare except. Exception is the base class of most exceptions so you can see what type and value it has, then the final finally prints inside finally.

Unable to catch TweepError exception

I tried to catch TweepError exception in while - try - except loop but unsuccessful. The following code keeps stop running when TweepError/ RateLimitError occuring.
import tweepy
import time
name_set = ('name1','name2','name3')
result = []
for screen_name in name_set:
while True:
profile = api.get_user(screen_name = screen_name)
try:
print('collecting user %s'%screen_name)
result.append(profile)
break
except tweepy.RateLimitError:
print('sleep 15 minutes')
sleep(900)
continue
except tweepy.TweepError as e:
print(e)
print('Account %s'%screen_name)
break
else:
print('Account %s'%screen_name)
break
TweepError
TweepError: [{'message': 'User not found.', 'code': 50}]
You should put a API call statement in the try block to catch a exception:
try:
profile = api.get_user(screen_name = screen_name)
print('collecting user %s'%screen_name)
...

Resources