i have custom exception for inserting data:
class ErrorOnInsert(BaseException):
"""Exception raised for errors in insert data to db
Attributes:
resource -- resource name
message -- explanation of the error
"""
def __init__(self, resource: str):
self.message = 'Failed to insert data for {}!'.format(resource)
super().__init__(self.message)
exception is used in this insert function to mongo:
def _add(self, data: RunnerRating):
try:
dict_data = data.as_dict()
self.collection[self.document_name].insert_one(
dict_data)
self.list_data.add(data)
except ErrorOnInsert(self.document_name) as e:
raise e
and i try to test the exception with self.repo._add(None) but it shows error something like this:
FAILED tests/integration/test_repo.py::RatingRepoTest::test_add -
TypeError: catching classes that do not inherit from BaseException is
not allowed
Your syntax looks like it's a catch with a pattern match (which isn't a thing in Python).
Are you maybe looking for
def _add(self, data: RunnerRating):
try:
dict_data = data.as_dict()
self.collection[self.document_name].insert_one(dict_data)
self.list_data.add(data)
except Exception as e:
raise ErrorOnInsert(self.document_name) from e
Related
I am struggling to catch specific Exceptions in the durable function orchestrator. If a raise an inbuilt or custom exception it won't be caught. e.g if i rasie TypeError in the durable function activty, it won't be able to be caught in the try and except statement in the orchestrator.
Function Activity:
import requests
import logging
from shared_code.custom_exceptions import *
def main(name: dict) -> str:
raise TypeError()
Orchestrator Function:
import logging
import azure.functions as func
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
json_body = context.get_input()
try:
yield context.call_activity(json_body["activityName"], json_body)
except Exception as e:
logging.info(str(e.__class__.__name__))
return 'fail'
return 'success'
main = df.Orchestrator.create(orchestrator_function)
I expected for the logged class name to be TypeError but instead it was just Excpetion. Hence I was unable to create my own custom Exceptions like below and catch these exceptions in order to handle them accordingly.
class DownloadError(Exception):
def __init__(self, code):
self.code = code
def __str__(self):
return repr(self.code)
try:
# call function activity
except DownloadError as e:
return {"errorCode": e.code}
except LoginError as e:
# some retry logic
except Exception as e:
return {"errorCode": 0}
However the only documentation I can see for catching Exceptions in the orchestrator doesn't specify Exception Types so I don't know if what I was trying to do is possible
I have app for working with database that uses psycopg2. When I try to insert a column with repeating name I got this error:
> self.cursor.execute(str(query))
E psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "deposits_area_name_key"
E DETAIL: Key (area_name)=(test-name) already exists.
dbase-api-server/dbase_api_server/dbase.py:110: UniqueViolation
I use try-except block to catch it and it work. But exception doesn't raise when I run pytests.
import logging
from psycopg2 import connect as connect_to_db
from psycopg2._psycopg import connection as postgres_connection
from psycopg2._psycopg import cursor as db_cursor
from psycopg2.errors import UniqueViolation
from pypika import Query, Table
from dbase_api_server.containers import PostgresConnectionParams
class StorageDBase:
def __init__(self, params: PostgresConnectionParams):
try:
self.__connection = connect_to_db(
host=params.host,
port=params.port,
user=params.user,
password=params.password,
database=params.database
)
except OperationalError as err:
logging.error(err, 'problems with database operation')
raise
#property
def connection(self) -> postgres_connection:
return self.__connection
#property
def cursor(self) -> db_cursor:
return self.__connection.cursor()
def is_success_commit(self) -> bool:
self.connection.commit()
def add_deposit_info(self, area_name: str) -> bool:
table = Table('deposits')
query = str(Query.into(table).columns('area_name').insert(area_name))
try:
self.cursor.execute(query)
return self.is_success_commit()
except UniqueViolation as error:
logging.error(
error,
f'deposit with name {area_name} already exists'
)
return False
Test:
from hamcrest import assert_that, equal_to, is_
from dbase_api_server.dbase import StorageDBase
class TestStorageDBase:
def test_add_deposit_repeating_name(self, up_test_dbase):
area_name = 'test-name'
is_first_added = up_test_dbase.add_deposit_info(area_name)
assert_that(actual_or_assertion=is_first_added, matcher=is_(True))
is_second_added = up_test_dbase.add_deposit_info(area_name)
assert_that(actual_or_assertion=is_second_added, matcher=is_(False))
query_count = f'SELECT COUNT(1) FROM deposits WHERE area_name=\'{area_name}\''
cursor = up_test_dbase.cursor
cursor.execute(query_count)
records_count = cursor.fetchone()[0]
assert_that(actual_or_assertion=records_count, matcher=equal_to(1))
self.remove_records_from_deposits(dbase_adapter=up_test_dbase)
There was a similar question here, but this solutions doesn't help to solve problem.
How I can catch this error?
OperationalError is the wrong error class. See Exceptions:
exception psycopg2.OperationalError
Exception raised for errors that are related to the databaseās operation and not necessarily under the control of the programmer, e.g. an unexpected disconnect occurs, the data source name is not found, a transaction could not be processed, a memory allocation error occurred during processing, etc. It is a subclass of DatabaseError.
The broad exception you want is:
exception psycopg2.DatabaseErrorĀ¶
Exception raised for errors that are related to the database. It is a subclass of Error.
If you want finer grain exceptions you need to look at Errors. For instance the psycopg2.errors.UniqueViolation that shows up in your error message.
So:
try:
<some query>
except psycopg2.errors.UniqueViolation:
<do something>
Problem is in exceptions and logging.There was mistake. I make next fix:
def add_deposit_info(self, area_name: str) -> bool:
table = Table('deposits')
query = str(Query.into(table).columns('area_name').insert(area_name))
try:
self.cursor.execute(query)
return self.is_success_commit()
except UniqueViolation:
logging.error('field(s) has non unique value')
return False
And it`s okay
I am not sure if this is a python question or a Tornado question. But I am struggling to figure out how I can handle an exception if something fails.
Here is the snippet of code:
class iQHandler(myBaseHandler):
#tornado.gen.coroutine
def _initialize(self):
param1 = self.get_argument('media', None)
if not param1:
raise tornado.web.HTTPError(404)
# default the Output parameter to JSON format.
outputFormat = self.get_argument('output', 'json', False)
try:
res = yield self._findfiles(param1)
except Exception, e:
# What do I do here?
print ("Error in _initialize() routine --> ", e)
# The variable, res, doesn't have any value if there is an exception thrown.
raise tornado.gen.Return(res)
#tornado.web.asynchronous
#tornado.gen.coroutine
def get(self):
response = yield self._initialize()
self.clear()
self.finish(response)
How will I go about either raising an exception and returning a value back to the previous routine? Thanks.
This is a python question. The try except block is fine. You can reraise the same exception by saying raise in the except block without anything after raise. That is, replace
raise tornado.gen.Return(res)
by
raise
Note the indent to keep the raise in the except block.
In a code where there are different old-style classes like this one:
class customException: pass
and exceptions are raised this way:
raise customException()
Is there a type to catch all those old-style class exceptions? like this:
try:
...
except EXCEPTION_TYPE as e:
#do something with e
Or at least is there a way to catch everything (old- and new-style) and get the exception object in a variable?
try:
...
except:
#this catches everything but there is no exception variable
The only solution I can think of is using sys.exc_info
import sys
try:
raise customException()
except:
e = sys.exc_info()[1]
# handle exception "e" here...
I'm currently writing a wrapper class. I want to be able to log exceptions properly but allow calling methods to be aware of exceptions which occur. My class looks like this:
import logging
log = logging.getLogger('module')
class MyAPIWrapper(library.APIClass):
def __init__(self):
self.log = logging.getLogger('module.myapiwrapper')
def my_wrapper_method(self):
try:
response = self.call_api_method()
return response.someData
except APIException, e:
self.log.exception('Oh noes!')
raise e #Throw exception again so calling code knows it happened
I'm a bit dubious about catching and exception just to log it and then re-raising it so the calling code can do something about it. What's the proper pattern here?
There is nothing wrong with catching to log. However, I'd recommend:
try:
response = self.call_api_method()
except APIException, e: # or 'as e' depending on your Python version
self.log.exception('Oh noes!')
raise #Throw exception again so calling code knows it happened
else:
return response.someData
By just doing a bare raise you preserve the full traceback info. It's also more explicit to put code that will only happen if you don't have an exception in the else clause, and it's clearer what line you're catching an exception from.
It would also be fine for the calling class to do the logging if it's handling the error anyway, but that may not be convenient for your app.
Edit: The documentation for try ... except ... else ... finally is under compound statements.
That method is correct, although instead of raise e you should just use raise, which will automatically re-raise the last exception. This is also one of the rare cases where using a blanket except is considered acceptable.
Here is an example very similar to what you are doing from the Python docs on Handling Exceptions:
The last except clause may omit the exception name(s), to serve as a wildcard. Use this with extreme caution, since it is easy to mask a real programming error in this way! It can also be used to print an error message and then re-raise the exception (allowing a caller to handle the exception as well):
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError as (errno, strerror):
print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
print "Could not convert data to an integer."
except:
print "Unexpected error:", sys.exc_info()[0]
raise
You can just extend the standard Exception class and add the logger into there.
Like this:
class LoggedException(Exception):
""" An exception that also logs the msg to the given logger. """
def __init__(self, logger: logging.Logger, msg: str):
logger.error(msg)
super().__init__(msg)