Exception object and missing __context__ and __cause__ attributes in IDE - python

The python docs https://docs.python.org/3/library/exceptions.html#built-in-exceptions
and this SO question mention the __cause__ and __context__ attributes on an exception object.
Python 3.x (beazley): __context__ vs __cause__ attributes in exception handling
However, when using a debugger to inspect an exception object (with the debuggers set to work on a raise) the exception object doesn't appear to have these attributes and just appears as a tuple.
(eg from my debugger - pycharm) https://imgur.com/a/63oW1fV
This occured with the debugger started based on the raise on the last line.
try:
response = requests.request(method, url, json=payload, headers=HEADERS)
except (requests.ConnectionError, requests.Timeout) as e:
logger.exception("Api unavailable")
raise errors.Unavailable('Api unavailable') from e
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
logger.exception("Api HTTP error")
try:
raw_data = response.json()
except json.JSONDecodeError as e:
raise errors.ApiHTTPError(f'{response.status_code}, {response.text}',
text=response.text) from e
api_errors = raw_data.get('errors')
message = raw_data.get('message')
raise errors.ApiHTTPError(f'HTTP Error {response.status_code}, {message}, {api_errors}', text=response.text,
api_errors=api_errors) from e
errors.py
class SwitcherError(Exception):
pass
class Unavailable(SwitcherError):
pass
class ApiHTTPError(SwitcherError):
def __init__(self, message=None, text=None, api_errors=None):
self.text = text
self.message = message
self.errors = api_errors
def __str__(self):
return self.message
class ApiJsonError(SwitcherError):
def __init__(self, message=None, text=None):
self.text = text
self.message = message
def __str__(self):
return self.message
class ApiError(SwitcherError):
def __init__(self, message, status_code, data, status=None,):
self.message = message
self.status_code = status_code
self.data = data
self.status = status
def __str__(self):
return self.message

That __exception__ thing isn't an exception. It looks like PyCharm has taken sys.exc_info() and stuffed it into an __exception__ variable. The exception is the second tuple element, and that's where you should be looking for __cause__ and __context__.

Related

Change "Error: response status" details in FastAPI / OpenAPI

I implemented some Custom Exceptions. And now I want to display the Exception name at the red box. Where can I set this value?
class CustomExceptionHandler(Exception):
def __init__(self, exception):
self.message = exception.message
self.status_code_number = exception.status_code_number
#app.exception_handler(CustomExceptionHandler)
async def data_processing_error_handler(request: Request, exc: CustomExceptionHandler):
return JSONResponse(
status_code=exc.status_code_number,
content=jsonable_encoder({exc.message}),
)

Catch any excpetion to avoid memory leak - Python bad/good pratices

I want to make sure a method is called if any exception is raised. In this situation, is it ok (good/bad practices or may lead to unexpected consequences) to try/except any Exception? Here's an example of what's on my mind using a decorator:
# implementation
import sys
import traceback
class AmazingClass:
def __init__(self, arg=None):
self.__att = arg
#property
def att(self, ):
return self.__att
def make_sure_it_quits(method):
def inner(self, *args, **kwargs):
try:
return method(self, *args, **kwargs)
except Exception as err:
print(err, "- This was caught because it couldn't be foreseen.")
traceback.print_exc()
print("\nQuitting what is suppose to be quited...")
self.quit()
return inner
#make_sure_it_quits
def this_may_raise_errors(self, arg):
try:
self.__att += arg
except TypeError as err:
print("This I can handle! Cleaning and exiting...")
self.quit()
# sys.exit(1) # exit, if it's the case
def quit(self, ):
self.__arg = None
print("Everything is very clean now!")
# examples
def no_errors():
obj = AmazingClass("test")
obj.this_may_raise_errors("_01")
print(obj.att)
def with_error_01():
obj = AmazingClass("test")
obj.this_may_raise_erros(1)
print(obj.att)
def with_error_02():
obj = AmazingClass("test")
obj.this_may_raise_errors()
print(obj.att)
# main
if __name__ == '__main__':
no_errors()
with_error_01()
with_error_02()
In this case, with_error_01 represents situations I know in advance that can happen, while with_error_02 is an unexpected use of the class.
In both cases, the use of traceback shows what and where went wrong. Also, the method quit must always be called in case of any error.

How to write test case for executing except block at least once for a non-failing method in python

I have created a python class as below -
class MyClass:
mydict = {}
error = None
traceback = None
message = None
def create_log_message(self, **kwargs):
try:
error = kwars.get("error", self.error)
traceback = kwargs.get("traceback", self.traceback)
message = kwargs.get("message", self.message)
self.mydict = {"error": error, "traceback": traceback, "message": message}
return self.mydict
except Exception as e:
error = e
traceback = tb.format_exc()
message = kwargs.get("message", self.message)
self.mydict = {"error": error, "traceback": traceback, "message": message}
return self.mydict
Below is my test class -
import unittest import TestCase
import traceback as tb
import MyClass
class TestMyClass(TestCase):
def test_success(self): # Test in case of success
inst = MyClass()
mydict = inst.create_log_message(message="success")
self.assertEqual(mydict["error"], None)
self.assertEqual(mydict["traceback"], None)
self.assertEqual(mydict["message"], "success")
def test_failure(self): # test in case of exception
try:
1/0
except ArithmeticError as e:
error = e
traceback = tb.format_exc()
inst = MyClass()
mydict = inst.create_log_message(error=error, traceback=traceback, message="failure")
self.assertEqual(mydict["error"], error)
self.assertEqual(mydict["traceback"], traceback)
self.assertEqual(mydict["message"], "failure")
def test_no_args(self): # test for no argument being passed
inst = MyClass()
mydict = inst.create_log_message()
self.assertEqual(mydict["error"], None)
self.assertEqual(mydict["traceback"], None)
self.assertEqual(mydict["message"], None)
def test_extra_args(self): # test for any other argument
inst = MyClass()
mydict = inst.create_log_message(name="test")
with self.assertRaises(KeyError):
self.assertEqual(mydict["name"], "test")
self.assertEqual(mydict["error"], None)
self.assertEqual(mydict["traceback"], None)
self.assertEqual(mydict["message"], None)
My problem is except block in MyClass is not getting called not even once, even if I pass no arguements, matching arguments or any other/extra arguments, hence code coverage is failing(not meeting 100%), how to execute the except block via test case at least once? I am using python3.8x/ubuntu20.04.
Any help in this regard will be really helpful :)
PS: Please forgive if I have missed any details as this is my first post on stack overflow.
The except block is not getting executed since you have mentioned default value as None inside try block in MyClass i.e kwars.get("error", self.error).Just remove the default value and it will work.
class MyClass:
mydict = {}
error = None
traceback = None
message = None
def create_log_message(self, **kwargs):
try:
error = kwargs["error"]
traceback = kwargs["traceback"]
message = kwargs["message"]
self.mydict = {"error": error, "traceback": traceback, "message": message}
return self.mydict
except Exception as e:
error = e
traceback = tb.format_exc()
error = kwargs.get("error", self.error)
traceback = kwargs.get("traceback", self.traceback)
message = kwargs.get("message", self.message)
self.mydict = {"error": error, "traceback": traceback, "message": message}
return self.mydict
If you want to test failing case, you might try unittest.mock. If you pass an exception to side_effect parameter of the mock, this exception will be raised.
Docs: https://docs.python.org/3/library/unittest.mock.html
But first think about real case when this exception can occur and try to mock this case. If there is no way exception will be raised, there is no need in code handling it.
First, do you really need that except clause? What errors are you handling? The code in your try block doesn't raise any exceptions, so there's no way to cause an exception. Rather than focus on how to test that code, I would simply remove it. You don't need it.

Async call and not wait while using pubnub with django

This is a module from PubNub that I'm using to publish a message to a topic from an API. By design I've kept the PubNub object singleton.
class Pubnub:
instance = None
#classmethod
def get(cls):
if cls.instance is None:
cls.instance = cls()
return cls.instance
def __init__(self):
with open('config/config.yaml', 'r') as stream:
try:
conf = yaml.load(stream)
pnconfig = PNConfiguration()
pnconfig.subscribe_key = conf['pubnub']['publish_key']
pnconfig.publish_key = conf['pubnub']['subscribe_key']
pnconfig.ssl = False
self.pubnub = PubNub(pnconfig)
except yaml.YAMLError as e:
logger.error(str(e))
def publish(self, channel):
try:
envelope = self.pubnub.publish().channel(channel).message({
'message': True
}).sync()
print("publish timetoken: %d" % envelope.result.timetoken)
except PubNubException as e:
logger.error(str(e))
This is how I'm calling it,
class SendCommunityTextMessage(views.APIView):
def post(self, request, **kwargs):
try:
client_id = request.GET['client_id']
client_secret = request.GET['client_secret']
if Authenticator.authenticate_client(client_id, client_secret):
try:
//do something
try:
//do something more
pubbub = Pubnub.get()
pubbub.publish(receiver.hex_code)
return Response({"Success": CommunityTextMessageSerializer(message).data},
status=status.HTTP_200_OK)
except KeyError as e:
return Response({"Failure": str(e)}, status=status.HTTP_400_BAD_REQUEST)
except (User.DoesNotExist, CommunityRoom.DoesNotExist) as e:
return Response({"Failure": str(e)}, status=status.HTTP_404_NOT_FOUND)
else:
return Response({"Failure": "Invalid client"}, status=status.HTTP_403_FORBIDDEN)
except KeyError as _:
return Response({"Failure": "Probably a typo, read the docs to use this API."},
status=status.HTTP_400_BAD_REQUEST)
The issue is this slows down the API by minutes. How can I call the two lines,
pubbub = Pubnub.get()
pubbub.publish(receiver.hex_code)
asynchronously and return out of the view without waiting for the call to finish.
Thanks in anticipation.

Exception in thread StompReceiverThread-1

I'm having trouble with this error:
Exception in thread StompReceiverThread-1 (most likely raised during
interpreter shutdown):
That is no traceback at all.. just that.
Usualy everything works fine but rarely it happens and then the action does not conclude.
Any tips?
My code:
class Listener(stomp.ConnectionListener):
def __init__(self, conn, request):
self.conn = conn
self.request = request
def on_error(self, headers, message):
global WAITING_RESPONSE
print('received an error: ' + message)
WAITING_RESPONSE = False
def on_message(self, headers, message):
global WAITING_RESPONSE
try:
msg = json.loads(message)
if str(msg.get('transaction_id','')) == str(CURRENT_ID):
printDebugLine('Queue response:'+str(message))
manageQueueResponse(message,self.request)
WAITING_RESPONSE = False
self.conn.ack(headers['message-id'], '11')
except stomp.exception.ConnectFailedException:
print('Stomp error on message')
sys.exit(3)
except Exception as e:
print('ERROR: %s' % str(e))
sys.exit(3)
class Queue(object):
def __init__(self):
self.host = xx
self.port = xx
self.login = xx
self.passwd = xx
self.request = {}
self.start()
def start(self):
try:
self.conn = stomp.Connection(host_and_ports=[(self.host, self.port)])
self.conn.start()
self.conn.connect(self.login, self.passwd, wait=True)
self.conn.set_listener('xx', Listener(self.conn, self.request))
self.conn.subscribe(destination='xx', id='xx', ack='xx')
except stomp.exception.ConnectFailedException:
print('ERROR: unable to connect')
sys.exit(3)
except Exception as e:
print('ERROR: %s' % str(e))
sys.exit(3)
def send(self, data):
global CURRENT_ID
while WAITING_RESPONSE:
time.time(0.1)
try:
CURRENT_ID = str(uuid.uuid4())
data.update({'transaction_id': CURRENT_ID})
b = json.dumps(data)
self.request.update(data)
printDebugLine('Queue request:'+str(data))
self.conn.send(body=b, destination='xx')
timeout(data,self.request,29)
except stomp.exception.ConnectFailedException:
print('ERROR: unable to connect')
except Exception as e:
print('ERROR: %s' % str(e))
It looks like your main program is exiting, the interpreter is cleaning up things, but the stomp receiver thread was not shutdown first. The receiver thread goes to do something but basic modules are no longer available, so it gives an exception message, but cannot print a Traceback because that fuctionality is no longer available due to the program exiting.
Look at why the main program would be exiting.

Categories