sqlite3.Connection class inheritance, commit not working - python

This is my first time using sqlite3 through class inheritance, and I've run into a problem where I get no traceback errors, but the queries I execute won't commit. I simplified my code
import sqlite3 as lite
class BaseModel(lite.Connection):
def __init__(self, **args):
lite.Connection.__init__(self, **args)
self.cur = self.cursor()
def execute(self, query):
self.cur.execute(query)
class Model(BaseModel):
def __init__(self, **args):
BaseModel.__init__(self, **args)
def _new_(self):
queries = []
queries.append(' '.join(['CREATE TABLE IF NOT EXISTS tb1',
'(id INTEGER PRIMARY KEY,',
'column1 TEXT,',
'column2 INT)']))
for q in queries:
self.execute(q) # execute the queries
self.commit() # write changes to db
def tables(self):
query = 'SELECT name FROM sqlite_master WHERE type="table" ORDER BY name'
results = self.execute(query)
return results#.fetchall()
if __name__ == '__main__':
model = Model(database='test.db')
model._new_()
# Test Fails because the queries aren't being saved in the db
# see Model.__new__ for details
tables = model.tables() # get all tables
print 'Tables Created:'
if tables:
for t in model.tables():
print '\t%s' % str(t[0])
else: print tables

You need to call self.commit():
self.commit() # write changes to db
Without the () you are merely referencing the method, not invoking it.
Next, your execute() function doesn't return anything:
def execute(self, query):
return self.cur.execute(query)

Related

Python unitest mock to check that a method returns a method call

I'm trying to figure out how I can simply check that the execute_db returns
a method call with the name cursor.fetchone?
I'm not interested to see if the db works, that will be done in a integration test later on.
I've written a small unittest already, but here I'm only mocking the return value.. I want to find a way to test that the method with the given name is being called as well.
class DataChecker:
def __init__(self):
# Initialize class
self.conn = sqlite3.connect("pos.db")
self.cursor = self.conn.cursor()
def execute_db(self, query, params=None):
# Execute SQL query with parameters and return data
self.cursor.execute(query, [params])
self.conn.commit()
return self.cursor.fetchone()
Test:
def test_execute_db():
mock_datachecker = Mock()
mock_datachecker.cursor.fetchone.return_value = "one"
assert DataChecker.execute_db(mock_datachecker, "SELECT * FROM Customers;", 1) == "one"
You would mock the method fetchone from sqlite3 that is imported in DataChecker module.
db.py
import sqlite3
class DataChecker:
def __init__(self):
# Initialize class
self.conn = sqlite3.connect("pos.db")
self.cursor = self.conn.cursor()
def execute_db(self, query, params=None):
# Execute SQL query with parameters and return data
if params:
self.cursor.execute(query, params)
else:
self.cursor.execute(query)
self.conn.commit()
return self.cursor.fetchone()
Then you could use the db.sqlite3 to mock the connect().cursor().fetchone method.
def test_execute_db():
with patch('db.sqlite3') as mock_db:
mock_db.connect().cursor().fetchone.return_value = "one"
assert DataChecker().execute_db("SELECT * FROM Customers") == "one"

Library program in Python 3 (beginner) with psycopg2

I need help with this program. I am making a program for a library in Python 3 (psycopg2) and I am making my modules to handle my tables, I have already done the "create" module and I am doing the "delete" module, I need help to do it, the code used is the following:
This is my class ConnectioDB: (it works to connect to my database in postgresql)
class ConnectionDB:
"""Connection class."""
bd = None
cursor = None
def __init__(self, **param):
"""Connection constructor."""
try:
self.db = connect(
host = '127.0.0.1', # localhost
user = 'postgres'
password = #$#!#*
database = 'national-library'
)
self.cursor = self.db.cursor()
except Error as e:
write_errors(e, 'Failed to connect to database')
with the following lines are used to execute sql code:
def execute_sql(
self,
sentence_sql,
param=None,
write_in_db=True
):
"""Execute SQL code."""
try:
execute = self.cursor.execute(sentence_sql, param)
if write_in_db:
result = self.db.commit()
except Exception as e:
write_errors(e, f"An error occurred while executing the SQL statement:\n\n{sentence_sql}\n")
if write_in_db:
self.db.rollback()
now this is my Model class that has the "create" module
class Model():
"""Generic model class."""
table_name = None
connection = ConnectionDB()
def create(self):
"""Save in database."""
table_name = self.table_name
keys = ", ".join(self.__dict__.keys())
values_placeholders = ", ".join(["%s" for i in range(len(self.__dict__.keys()))])
values = self.__dict__.values()
sql = f"INSERT INTO {table_name} ({keys}) VALUES ({values_placeholders})"
self.connection.execute_sql(sql, tuple(values))
I was trying to do the following code for my "delete" module but I'm not sure if it's ok:
def delete(self, column_id):
"""Delete an item in the database."""
table_name = self.table_name
sql = f"DELETE FROM {table_name} WHERE id = %s"
self.connection.execute_sql(sql, (column_id, ))
I hope you can help me. Thank you!

Use decorator to connect to a postgres database

I am working on a program to store my picture meta data and thumbnails into a postgres database using python and psycopg2. In the example I have defined a class MyDbase with methods to create a table, store a value and load a value. Each of these methods needs to connect to the database and a cursor object to execute sql commands. To avoid repetition of code to make the connection and get the cursor I have made a sub class DbDecorators with a decorator connect.
My question: is this a proper way to handle this and specifically using the with statement and passing the cursor to the Dbase method (func) inside the wrapper?
from functools import wraps
import psycopg2
class MyDbase:
''' example using a decorator to connect to a dbase
'''
table_name = 'my_table'
class DbDecorators:
host = 'localhost'
db_user = 'db_tester'
db_user_pw = 'db_tester_pw'
database = 'my_database'
#classmethod
def connect(cls, func):
#wraps(func)
def wrapper(*args, **kwargs):
connect_string = f'host=\'{cls.host}\' dbname=\'{cls.database}\''\
f'user=\'{cls.db_user}\' password=\'{cls.db_user_pw}\''
result = None
try:
with psycopg2.connect(connect_string) as connection:
cursor = connection.cursor()
result = func(*args, cursor, **kwargs)
except psycopg2.Error as error:
print(f'error while connect to PostgreSQL {cls.database}: '
f'{error}')
finally:
if connection:
cursor.close()
connection.close()
print(f'PostgreSQL connection to {cls.database} is closed')
return result
return wrapper
#staticmethod
def get_cursor(cursor):
if cursor:
return cursor
else:
print(f'no connection to database')
raise()
#classmethod
#DbDecorators.connect
def create_table(cls, *args):
cursor = cls.DbDecorators().get_cursor(*args)
sql_string = f'CREATE TABLE {cls.table_name} '\
f'(id SERIAL PRIMARY KEY, name VARCHAR(30));'
print(sql_string)
cursor.execute(sql_string)
#classmethod
#DbDecorators.connect
def store_value(cls, name, *args):
cursor = cls.DbDecorators().get_cursor(*args)
sql_string = f'INSERT INTO {cls.table_name} (name) VALUES (%s);'
print(sql_string)
cursor.execute(sql_string, (name,))
#classmethod
#DbDecorators.connect
def load_value(cls, _id, *args):
cursor = cls.DbDecorators().get_cursor(*args)
sql_string = f'SELECT * FROM {cls.table_name} where id = \'{_id}\';'
print(sql_string)
cursor.execute(sql_string)
db_row = cursor.fetchone()
return db_row
def test():
my_db = MyDbase()
my_db.create_table()
my_db.store_value('John Dean')
db_row = my_db.load_value(1)
print(f'id: {db_row[0]}, name: {db_row[1]}')
if __name__ == '__main__':
test()
probably I did not get your request correctly. Why you need decorator but don't use context manager? Like define db client in any file where from you can import it later and then use it in context manager –
from psycopg2 import SomeDataBase
db = SomeDataBase(credentials)
def create_table(table_name):
with db:
sql_string = f'CREATE TABLE {table_name} '\
f'(id SERIAL PRIMARY KEY, name VARCHAR(30));'
db.cursor.execute(sql_string)
Using a context manager will not close the connection, only the cursor. So using the decorator pattern actually makes more sense here. More info on the context manager: https://www.psycopg.org/docs/usage.html (scroll down to the "with statement" section.)

Python doctest: how to testing a database insert or delete function?

The question is simple, the answer I dont know...
I'm newbie with testing and I have problems testing class for drive a sql3 database. What is the best way for test a class like this? Test the class or test the init function is not a problem, but the others? the test insert a test row?
import sqlite3
class DataBase:
def __init__(self):
self._database_path = 'data.sql'
self._conn = sqlite3.connect(self._database_path)
self._cursor = self._conn.cursor()
def get(self, sql):
# select
self._cursor.execute(sql)
dataset = []
for row in self._cursor:
dataset.append(row)
return dataset
def post(self, sql):
# insert
self._cursor.execute(sql)
self._conn.commit()
Thank you for all of you, thank you for all your answers!!
You can use the rollback function of the database.
Just replace self._conn.commit() with self._conn.rollback() and you can test the validity of your sql with no effects on the data.
If you need to test a series of actions (i.e: get data->modify data->insert new data->remove some data->get data again) you can remove all the _conn.commit() in your code, run the tests and finally call _conn.rollback().
Example:
import sqlite3
class DataBase:
def __init__(self):
self._database_path = 'data.sql'
self._conn = sqlite3.connect(self._database_path)
self._cursor = self._conn.cursor()
def get(self, sql):
# select
self._cursor.execute(sql)
dataset = []
for row in self._cursor:
dataset.append(row)
return dataset
def post(self, sql):
# insert
self._cursor.execute(sql)
def delete(self, sql):
# delete
self._cursor.execute(sql)
def rollback(self):
self._conn.rollback()
# You do your tests:
db = DataBase()
data = db.get('select name from table')
new_data = ['new' + name for name in data]
db.post('insert into table values {}'.format(','.join('({})'.format(d) for d in new_data)))
db.delete('delete from table where name = \'newMario\'')
check = bool(db.get('select name from table where name = \'newMario\''))
if check:
print('delete ok')
# You make everything as before the test:
db.rollback()
I think the CursorTests in official sqlite3 tests is a good example.
https://github.com/python/cpython/blob/master/Lib/sqlite3/test/dbapi.py#L187
You can write setUp and tearDown methods to set up and rollback the database.
from unittest import TestCase
class TestDataBase(TestCase):
def setUp(self):
self.db = DataBase()
def test_get(self):
pass # your code here
def test_post(self):
pass # your code here

Calling method to another method in python

I have lots of database queries and I would like to use some methods to not repeat my code. I would like to call methods in other defined methods but it doesn't work
I'm getting such error:
class Main:
File "d.py", line 20, in Main
for word in getUserWords("SELECT users.mail, field_data_field_what_word_are_you_looking_.field_what_word_are_you_looking__value, users.uid FROM users INNER JOIN field_data_field_what_word_are_you_looking_ ON users.uid = field_data_field_what_word_are_you_looking_.entity_id"):
TypeError: getUserWords() takes exactly 2 arguments (1 given)
my code
import MySQLdb as mdb
Class Main:
def connect(self):
con = mdb.connect('***', '*****', '****', '***', charset="utf8", use_unicode=True)
return con
def cursor(self):
cursor = self.connect.cursor()
return cursor()
def getUserWords(self, sql):
self.sql = sql
self.cursor.execute(self.sql)
data = self.cursor.fetchall()
self.connect.commit()
self.connect.close()
return data
for word in getUserWords("SELECT users.mail, field_data_field_what_word_are_you_looking_.field_what_word_are_you_looking__value, users.uid FROM users INNER JOIN field_data_field_what_word_are_you_looking_ ON users.uid = field_data_field_what_word_are_you_looking_.entity_id"):
print word
Simpler example:
class Foo(object):
def __init__(self):
self.foo = "bar"
def function1(self,x):
self.function2(x)
def function2(self,y):
print y
bar = Foo()
bar.function1(3) # calls function1 which in turn calls function2 which prints out 3
bar.function2(4) # calls function 2 directly.
The main takeaway to answer your question:
If you have a class function, it has a first argument which is by convention self. If you call that class function on an instance (as in bar.function2), the self is implicit. If you call that class function from within the class (as when function1 calls function2), you need to do self.functionname, which again implicitly passes the self argument.
First point: instanciate your class and call getUserWords() on your instance:
import MySQLdb as mdb
class Main:
# snip
m = Main()
sql = your_sql_here
for word in m.getUserWords(sql):
print word
Second point: your implementation of Main is flawed.
Class Main:
def connect(self):
# this will open a new connection on each and every call
con = mdb.connect('***', '*****', '****', '***', charset="utf8", use_unicode=True)
return con
def cursor(self):
# this will
# 1. create a new connection on every call - which will
# never be closed since you don't keep a reference
# on it so you can close it
# 2. create a new cursor on every call
cursor = self.connect.cursor()
# and this one will raise a TypeError
# => "'Cursor' object is not callable"
return cursor()
# so I assume your real code is :
return cursor
def getUserWords(self, sql):
# assigning sql to self is totally useless here
self.sql = sql
# so (assuming self.cursor returns the cursor and not
# the call to the cursor), this will:
# - open a new connection
# - create a new cursor
# - execute the sql
# - and discards eveything (cursor and connection)
# without closing them
self.cursor.execute(self.sql)
# now we
# - open a second connection (without closing the first)
# - create a second cursor
# - call .fetchall() on it, which will raise a
# _mysql_exceptions.ProgrammingError
data = self.cursor.fetchall()
# we're not making it until this part because of
# the above error, but if we did, this would:
# - create yet a third connection and call .commit()
# on it - which in this case would mainly be a no-op
# since we have nothing to commit
self.connect.commit()
# and finally create a fourth connection and close it
# immediatly - note that this will be the only one that
# gets closed <g>
self.connect.close()
return data
A fixed version of your code could look something like this:
import MySQLdb as mdb
class Main(object):
def __init__(self, connection_data):
self._connection_data = connection_data.copy()
self._connection_data.update(charset="utf8", use_unicode=True)
self._db = None
#property
def db(self):
if self._db is None:
self._db = mdb.connect(**self._connection_data)
return self._db
def cursor(self):
return self.db.cursor()
def execute(self, sql):
cursor = self.cursor()
cursor.execute(self.sql)
for row in cursor:
yield row
self.db.commit()
cursor.close()
def __del__(self):
try:
self._db.close()
except:
# either it's not set or it's already closed
pass
m = Main(db="***", user="***", passwd="***")
for w in m.getUserWords(your_sql_here):
print w

Categories

Resources