I implemented the process to execute SQL query in Redshift using psycopg2 in Python, but I implemented it in a wrapper class to execute it with dry-run, so I will introduce how it was implemented I think that I want to do it.
Wrap psycopg2 to implement dry-run functionality. When executing a query, do not commit, but rollback to perform dry-run.
wrapper.py
import os
import psycopg2
import re
class DBWrapperClass:
__is_dryrun = False #The default is dry-run do not run
def __init__(self):
self.__connection()
def __connection(self):
#DB connection information Please change accordingly
dsn = {
"host" : os.environ.get('DB_HOST'),
"port" : os.environ.get('DB_PORT'),
"database" : os.environ.get('DB_NAME'),
"user" : os.environ.get('DB_USER'),
"password" : os.environ.get('DB_PASS'),
}
self.__conn = psycopg2.connect(**dsn)
#Allows you to specify arguments with with syntax
def __call__(self, **kwargs):
self.__is_dryrun = bool(kwargs['dryrun']) if 'dryrun' in kwargs else False
return self
#Get cursor with with syntax
def __enter__(self):
self.__cursor = self.__conn.cursor()
return self
#Commit or rollback at the end of the with syntax and close the cursor
def __exit__(self, exc_type, exc_value, traceback):
#Roll back if an exception occurs
needs_rollback = True if exc_value else False
self.__commit(needs_rollback)
self.__close_cursor()
#If you do not call it like a function with with syntax, the previous value will be inherited, so initialize it.
self.__is_dryrun = False
def __commit(self, needs_rollback=False):
if self.__conn:
# dry-When you need a run or rollback
if self.__is_dryrun or needs_rollback:
self.__conn.rollback()
else:
self.__conn.commit()
#close cursor
def __close_cursor(self):
if self.__conn:
self.__cursor.close()
#Close the connection
def close(self):
if self.__conn:
self.__conn.close()
#Execute the query
def execute(self, sql):
# dry-For run, truncate is not executed
#Since truncate cannot roll back, this control is included.
if not (self.__is_dryrun and re.match(r'^\s*truncate\s+', sql, flags=re.IGNORECASE)):
self.__cursor.execute(sql)
In order to be able to manage cursor with with syntax like psycopg2, processing related to cursor is implemented in each method of __enter__
and __exit__
.
We've also added a __call__
method so that you can set the dry-run specification in the with syntax.
import wrapper
try:
dbwrapper = wrapper.DBWrapperClass()
with dbwrapper(dryrun=True) as db:
#dry sql-Run with run
db.execute('dry-sql you want to run with run')
finally:
if 'dbwrapper' in locals():
dbwrapper.close()
On the execution side, this is all you need to do. This time, only the argument for dry-run is set to make it as simple as possible, but it will be more convenient if other setting values such as autocommit can also be set with the argument.
I implemented the wrapper class of psycopg2 and added the function of dry-run. I usually write programs in php, so I thought the with syntax of python was quite convenient. Also, what I thought about implementing this time is that python has quite a lot of magic methods and I definitely want to use it when implementing classes for different purposes.
Recommended Posts