custom exception message in sqlalchemy - python

Im trying to raise a custom exception message when I get an exception but I get the following error -
try:
query_start_time = time.time()
execute_sql_alchemy_query
except Exception as ex:
elapsed_time = (time.time() - query_start_time)/60
print(type(ex))
raise type(ex)("Query elapsed time(in mins) - {0}".format(elapsed_time))
Error:-
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/profiles/sources/impact/test.py", line 110, in _handle_future_exception
future.result()
File "/usr/local/lib/python3.7/concurrent/futures/_base.py", line 428, in result
return self.__get_result()
File "/usr/local/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
TypeError: __init__() missing 2 required positional arguments: 'params' and 'orig'

The exception being raised is probably a subclass of DBAPIError (https://docs.sqlalchemy.org/en/13/core/exceptions.html#sqlalchemy.exc.DBAPIError) which takes 3 positional/mandatory parameters in its constructor (statement, params and orig), by trying to raise it like this, you are only providing a “statement” but not the 2 other arguments.
You could probably manage to make it work by providing the .params and .orig from the initial exception but I’d discourage you to go that way because it’s error prone and a bit fragile (it will break if the exception is not a DBAPIError), instead I’d suggest to simply log the time separately from the error (using logging.warning)

Related

Python ProcessPoolExecutor cannot handle exception

I am executing a Tornado server with ProcessPoolExecutor to handle multiple requests in parallel.
The problem is that, in one particular case, when an exception is raised in one of the processes it doesn't propagates, but instead the process crashes with this error:
concurrent.futures.process._RemoteTraceback:
\n'''\nTraceback (most recent call last):
\n File \"C:\\Users\\ActionICT\\anaconda3\\lib\\concurrent\\futures\\process.py\", line 367, in _queue_management_worker\n result_item = result_reader.recv()
\n File \"C:\\Users\\ActionICT\\anaconda3\\lib\\multiprocessing\\connection.py\", line 251, in recv
\n return _ForkingPickler.loads(buf.getbuffer())\nTypeError: __init__() missing 1 required positional argument: 'is_local'\n'''\n\nThe above exception was the direct cause of the following exception:
\n
\nTraceback (most recent call last):\n File \"C:\\S1\\Product\\Baseline\\PYTHON\\lab\\controller.py\", line 558, in get\n output = exec_future.result()
\n File \"C:\\Users\\ActionICT\\anaconda3\\lib\\concurrent\\futures\\_base.py\", line 428, in result\n return self.__get_result()\n File \"C:\\Users\\ActionICT\\anaconda3\\lib\\concurrent\\futures\\_base.py\", line 384, in __get_result
\n raise self._exception\nconcurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending.\n
I have tried it in debugger, and found that the problem is executing this
def _send_bytes(self, buf):
ov, err = _winapi.WriteFile(self._handle, buf, overlapped=True)
try:
if err == _winapi.ERROR_IO_PENDING:
waitres = _winapi.WaitForMultipleObjects(
[ov.event], False, INFINITE)
assert waitres == WAIT_OBJECT_0
except:
ov.cancel()
raise
finally:
nwritten, err = ov.GetOverlappedResult(True)
assert err == 0
assert nwritten == len(buf)
This is called when the process tries to propagate the exception to the corresponding Future object.
In the first line, when calling _winapi.WriteFile, everything crashes in debugger, and I can't understand why. Any idea?
I have resolved with a workaround: I have wrapped internally the function inside separate process in try except, then copied the old exception in a new exception and raised it. I don't know why... but it works.
def _execute_tuning(tune_parameters: TuneParameters):
# function to parallelize todo to be refactored
# execute scenario, then write result or error in output
try:
config.generate_project_config(
project_name=tune_parameters.project_name,
scenario_name=tune_parameters.scenario_name
)
config.generate_session_log_config(project_name=tune_parameters.project_name,
scenario_name=tune_parameters.scenario_name)
tree = DecisionTreeGenerator(tune_parameters.project_name, tune_parameters.scenario_name)
tree.fit(
# todo refactor
auto_tune=True if tune_parameters == 'true' else False,
max_depth=tune_parameters.max_depth,
columns=tune_parameters.columns,
min_samples_leaf=tune_parameters.min_samples_per_leaf,
max_leaf_nodes=tune_parameters.max_leaf_nodes
)
kpi = KPICalculator(tune_parameters.project_name, tune_parameters.scenario_name)
kpi.run(do_optimization_kpi=False)
except Exception as exc:
Loggers.application.exception(exc)
exc_final = Exception(str(exc))
exc_final.__traceback__ = exc.__traceback__
raise exc_final

How can I reduce Python's Exception raising output?

I have this line of Python code:
raise ValueError(f"Invalid input '{number}'")
When it raises an exception I get:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/snowcrash/Code/Python/mycode/mycode.py", line 8, in __init__
raise ValueError(f"Invalid input '{number}'")
ValueError: Invalid input 'a1b2c3'
however I'd prefer to get:
File "/home/snowcrash/Code/Python/mycode/mycode.py", line 8, in __init__
ValueError: Invalid input 'a1b2c3'
How do I achieve this?
sys.excepthook(type, value, traceback) is the function that does the printing when an exception is raised. You can write your own function (with a similar signature) and simply replace it with:
sys.excepthook = myfunction
You can do whatever you want in this function. You may log to files, or print some information about the state of the program when the exception occurred, for example. You may even arrange for different things to happen depending on the type of exception.
However if all you want to do is format your traceback message, lots of convenient stuff is already provided for you. You can dig into the traceback docs for the details, but here is an example that produces roughly the output you want:
import sys, traceback
def myhook(type, value, tb):
trace = traceback.format_tb(tb, limit=1)
trace = trace[0].split("\n")[0]
exc = traceback.format_exception_only(type, value)[0]
print(trace + "\n" + exc)
sys.excepthook = myhook
number = "a1b2c3"
raise ValueError(f"Invalid input {number}")
which produces an output of:
File "scratch/so.py", line 14, in <module>
ValueError: Invalid input a1b2c3
Note especially the use of traceback.format_tb with limit=1, to limit the stack trace output. There are a bunch of these functions in the traceback module.

Python IndexError being thrown even though it's inside two except blocks

This is probably a really silly error, but alas I am relatively new to Python and I find this error perplexing so any help would be appreciated. It's probably a relatively simple error, but searches on the site have so far not solved the issue. Here is the method that is giving me all of these problems:
def loggable(func):
def log(self, *args, **kwargs):
try:
return func(self, *args, **kwargs)
except Exception as ex:
import traceback
import sys
tb = sys.exc_info()[2]
exception_string = traceback.format_exception(type(ex), ex, tb)
[self.error_log.appendText(item) for item in exception_string]
m = qg.QMessageBox()
m.setIcon(m.Warning)
m.setText(ex.args[0])
try:
m.setInformativeText(str(ex.args[1]))
except IndexError:
pass
try:
m.setDetailedText(str(ex.args[2]))
except IndexError:
pass
m.exec_()
raise
return log
The exception from this line
m.setDetailedText(str(ex.args[2]))
is being thrown even though it's inside of not one but TWO catch blocks. I am trying to figure out what the issue could be and any help would be appreciated.
Here is the traceback:
Traceback (most recent call last):
File "/home/skylion/Git/popupcad/popupcad/guis/editor.py", line 335, in <lambda>
popupcad.manufacturing.joint_operation2.JointOperation2)}})
File "/home/skylion/Git/popupcad/popupcad/guis/editor.py", line 51, in log
m.setDetailedText(str(ex.args[2]))
IndexError: tuple index out of range
Your last line of the outer exception handler is raise which will reraise the last exception, which is apparently attempting to call m.setDetailedText. That fails, but its exception is now the most recent, and gets re-raised when you hit raise at the end.
To raise the original exception, change it from raise to raise ex
According to the docs, your last statement raise will re-raise the previous exception.
https://docs.python.org/2/tutorial/errors.html#raising-exceptions

rethrowing python exception. Which to catch?

I'm learning to use python. I just came across this article:
http://nedbatchelder.com/blog/200711/rethrowing_exceptions_in_python.html
It describes rethrowing exceptions in python, like this:
try:
do_something_dangerous()
except:
do_something_to_apologize()
raise
Since you re-throw the exception, there should be an "outer catch-except" statement. But now, I was thinking, what if the do_something_to_apologize() inside the except throws an error. Which one will be caught in the outer "catch-except"? The one you rethrow or the one thrown by do_something_to_apologize() ?
Or will the exception with the highest priotiry be caught first?
Try it and see:
def failure():
raise ValueError, "Real error"
def apologize():
raise TypeError, "Apology error"
try:
failure()
except ValueError:
apologize()
raise
The result:
Traceback (most recent call last):
File "<pyshell#14>", line 10, in <module>
apologize()
File "<pyshell#14>", line 5, in apologize
raise TypeError, "Apology error"
TypeError: Apology error
The reason: the "real" error from the original function was already caught by the except. apologize raises a new error before the raise is reached. Therefore, the raise in the except clause is never executed, and only the apology's error propagates upward. If apologize raises an error, Python has no way of knowing that you were going to raise a different exception after apologize.
Note that in Python 3, the traceback will mention both exceptions, with a message explaining how the second one arose:
Traceback (most recent call last):
File "./prog.py", line 9, in <module>
File "./prog.py", line 2, in failure
ValueError: Real error
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./prog.py", line 11, in <module>
File "./prog.py", line 5, in apologize
TypeError: Apology error
However, the second exception (the "apology" exception) is still the only one that propagates outward and can be caught by a higher-level except clause. The original exception is mentioned in the traceback but is subsumed in the later one and can no longer be caught.
The exception thrown by do_something_to_apologize() will be caught. The line containing raise will never run, because of the exception thrown by do_something_to_apologize. Also, I don't believe there is any idea of "priority" in python exceptions.
I believe a better idea is to use
raise NewException("Explain why") from CatchedException
pattern. In particular, considering Python 3 and the example given by #BrenBarn I use following
def failure():
raise ValueError("Real error")
try:
failure()
except ValueError as ex:
raise TypeError("Apology error") from ex
which yields
--------- ValueError----
Traceback (most recent call last)
4 try:
----> 5 failure()
6 except ValueError as ex:
1 def failure():
----> 2 raise ValueError("Real error")
3
ValueError: Real error
The above exception was the direct cause of the following exception:
-----TypeError-----
Traceback (most recent call last)
5 failure()
6 except ValueError as ex:
----> 7 raise TypeError("Apology error") from ex
TypeError: Apology error

How to manually log exception to be used with ereporter?

I use ereporter in my GAE app to be informed about all uncaught exceptions thru email. But I also would like to be informed other (handled) issues, so, I use the following code:
if something:
pass
else:
logging.exception('something is wrong')
But ereporter fails with such cases with AttributeError:
Traceback (most recent call last):
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ereporter/ereporter.py", line 227, in emit
signature = self.__GetSignature(record.exc_info)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ereporter/ereporter.py", line 175, in __GetSignature
fulltype = '%s.%s' % (ex_type.__module__, ex_type.__name__)
AttributeError: 'NoneType' object has no attribute '__module__'
I understand why it happens - there is no real Exception. But is there any way still to log such cases with ereporter?
As you said yourself - there's no exception to report. Since ereporter seems to only report exceptions, the solution is clear:
if something:
pass
else:
try:
raise Exception()
except Exception:
logging.exception('something is wrong')

Categories