Psycopg2 error messages - python

All,
I am writing error messages to a log file and it's becoming pretty large because it errors on unique constraints in the DB. That is fine and it's actually want it to do so my question is, how can I avoid writing the duplicate key errors to the log file every time they happen?
except Exception as err:
logger.error('FunctionName: %s', err)
Thanks,
Adam

Psycopg passes the PostgreSQL error code along with the exception in the attribute pgcode: you can verify that the error is actually related to a unique violation and avoid logging them. For example:
try:
cursor.execute("...")
except psycopg2.IntegrityError as err:
if err.pgcode != '23505':
logger.error('FunctionName: %s', err)
except Exception as err:
logger.error('FunctionName: %s', err)

Related

How can I better handle this Flask-SQLAlchemy commit/rollback?

I'm reviewing some old code I wrote and was looking at a shared commit function I had written to handle responses to the user on certain failures when attempting to commit changes to the database (such as deletes):
def _commit_to_database():
"""A shared function to make a commit to the database and handle exceptions
if encountered.
"""
flask.current_app.logger.info('Committing changes to database...')
try:
db.session.commit()
except AssertionError as err:
flask.abort(409, err)
except (exc.IntegrityError, sqlite3.IntegrityError) as err:
flask.abort(409, err.orig)
except Exception as err:
flask.abort(500, err)
finally:
db.session.rollback()
I think I understand my thought process: attempt the commit, upon certain failures trigger a flask.abort to send the response back, but I believe I found that the database was left with an open session requiring a rollback when I did this and adding the rollback into a finally statement resolved this allowing me to still use the flask.abort.
The questions I have around me code are:
1) Is this a bug: will the Flask-SQLAlchemy extension not close out the session as normal; is calling the rollback on the finally which will be triggering after the abort going to affect successful commits?
2) If this is a bug: what should I be doing differently in handling the try-except-finally and the db session?
You need to rollback when exception occurs and finally close the session:
def _commit_to_database():
"""A shared function to make a
commit to the database and
handle exceptions if encountered.
"""
flask.current_app.logger.info('Committing changes to db...')
try:
db.session.commit()
except AssertionError as err:
db.session.rollback()
flask.abort(409, err)
except (exc.IntegrityError, sqlite3.IntegrityError) as err:
db.session.rollback()
flask.abort(409, err.orig)
except Exception as err:
db.session.rollback()
flask.abort(500, err)
finally:
db.session.close()

Get error message from Oracle exception using python and cx_oracle

The problem: I need to get error message from oracle database exception, but I don't know how.
Example:
try:
...
cursor.execute("<SOME SQL>")
except DatabaseError, e:
error, = e.args
print e.message
This code outputs something like:
ORA-20000: Some error description
ORA-06512: at "GEN.ERR", line 3
ORA-06512: at "SCHEME_NAME.PACKAGE_NAME", line 49
ORA-06512: at line 1
So, how can I get only error description ("Some error description") in the above example, but not the full error message with table names etc. ? I know that I can parse this output but I think there should be more clever way to get the error message.
Thanks.

Getting error messages from psycopg2 exceptions

This is my first project using psycopg2 extensively. I'm trying to find a way to extract the psql error message for whenever a connection attempt fails. I've tested the code below will work if all the variables are set correctly, however whenever an error condition occurs (e.g. user chooses a database that doesn't exist), Python will give me the following:
I am unable to connect to the database
None
Traceback (most recent call last):
File "./duplicate_finder.py", line 163, in <module>
main(sys.argv[1:])
File "./duplicate_finder.py", line 142, in main
print e.diag.message_detail
AttributeError: 'OperationalError' object has no attribute 'diag'
Is there a simple, catch-all method to catch whatever error message psql generates when a connection fails, or do I need to write except blocks for multiple psycopg2 exceptions?
Extract from my script:
import sys, getopt, os, time, csv, psycopg2
...
...
conn_string = "host=" + dbhost + " dbname=" + database + " user=" + dbuser + " password=" + dbpass
try:
conn = psycopg2.connect(conn_string)
except psycopg2.Error as e:
print "Unable to connect!"
print e.pgerror
print e.diag.message_detail
sys.exit(1)
else:
print "Connected!"
cur = conn.cursor()
cur.execute("SELECT id, lastname, firstname, location FROM test ORDER BY ctl_upd_dttm DESC;")
print cur.fetchone()
...
conn.close()
When I try to catch exceptions, e.pgerror is always None for connection errors. The following code block gets around this by directly printing 'e'.
try:
conn = psycopg2.connect(conn_string)
except psycopg2.OperationalError as e:
print('Unable to connect!\n{0}').format(e)
sys.exit(1)
else:
print('Connected!')
# do stuff
For example, in the case of password authentication failure:
Unable to connect!
FATAL: password authentication failed for user "user"
I realize this question is a year old but hopefully might help someone in the future
Ended up here because of
class 'psycopg2.errors.InvalidCursorName'
on Django. If that's your case, be sure to makemigrations
You are catching all exceptions with the base class psycopg2.Error. Your problem is probably that the diag attribute is new in psycopg2 2.5. What is your version?
>>> print psycopg2.__version__
2.5.1 (dt dec pq3 ext)
Since Python 3.9 (.removesuffix(), f-strings) I use
except psycopg2.Error as e:
log.error(f"{type(e).__module__.removesuffix('.errors')}:{type(e).__name__}: {str(e).rstrip()}")
if conn: conn.rollback()
where log is logger.
Connection errors lives directly in psycopg2 module while syntax errors in psycopg2.errors submodule. There is an unwanted newline at the end of every psycopg2 error message.

Can exceptions be written for specific errors? Like database "XXX" does not exist

I would like to write and exception for the database does not exist, so I can create it and return back to the top (retry the connection).
How do you get specific when writing exceptions?
Can you have two or more exceptions?
try:
db_con = psycopg2.connect(host='HOSTNAME', database='MYDB', user='USERNAME', password='PASSWORD')
cur = db_con.cursor()
cur.execute('SELECT version()')
ver = cur.fetchone()
print ver
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
finally:
if db_con:
db_con.close()
You should read the python documentation on Exceptions.
But generally speaking yes, you can define your own exception types just like any other class by extending Exception or any other appropriate error type (in this case I'd probably use IOError)
Example:
class NoDatabaseError(IOError):
pass
And then in the code above the database open:
try:
open_database(database)
except NoDatabaseError as e:
print('Could Not Open The Database: '+str(e))
except Exception as e:
print('Something Unexpected Went On:'+str(e))
If that's not what you're asking, you should clarify your question.
Creating your own Exception is just a matter of inheritance:
class DatabaseDoesNotExist(IOError):
pass
raise DatabaseDoesNotExist()
You can also raise nested exceptions by listing one as cause for the other:
except psycopg2.DatabaseError as e:
raise DatabaseDoesNotExist('message', e) # python 2
raise DatabaseDoesNotExist('message') from e # python 3
This will preserve the traceback prior to your intervention.

How can I get an error when no results are fetched with DB query?

I'm trying to learn and advance with SQLAlchemy. Today I wanted to learn about exceptions it raises.
I'm working on a Pyramid based project, MySQL server (InnoDB) and SQLAlchemy.
I am trying to except all errors since NoResultFound error would not raise or print in console. So I except exc.SQLAlchemyError.
When I query my table and no results are found, it does not raise or catch or except anything whatsoever and continues operating.
Questions:
How can I and How should I query for .all() or .one(), and deal with
the issue of not having any rows returned?
How can I and how should I deal with others SQL or System related errors? I would like to record them and observe them to fix issues.
My code is:
try:
query = Session.query(MyTable).filter(Terms.column == my_string).all()
except exc.SQLAlchemyError, e:
print e
return False
(Instead of exc.SQLAlchemyError, I first tried NoResultFound, e)
Indeed this code will not raise an exception if no records are found. So instead you should throw your own exception:
import logging
try:
records = Session.query(MyTable).\
filter(Terms.column == my_string).all()
if len(records) == 0:
raise MyException('No records found')
except MyException, e:
logging.info('No records found')
except exc.SQLAlchemyError, e:
logging.exception('Some problem occurred')

Categories