snippetpythonMinor
A class to create and modify SQLite3 databases with a terminal
Viewed 0 times
databasescreateterminalwithsqlite3andclassmodify
Problem
I would like feedback on the class I've written. The purpose is to dynamically create and interact with SQLite3 databases, accepting lists of complete or incomplete statements.
```
import sqlite3
class DB(object):
"""DB initializes and manipulates SQLite3 databases."""
def __init__(self, database='database.db', statements=[]):
"""Initialize a new or connect to an existing database.
Accept setup statements to be executed.
"""
#the database filename
self.database = database
#holds incomplete statements
self.statement = ''
#indicates if selected data is to be returned or printed
self.display = False
self.connect()
#execute setup satements
self.execute(statements)
self.close()
def connect(self):
"""Connect to the SQLite3 database."""
self.connection = sqlite3.connect(self.database)
self.cursor = self.connection.cursor()
self.connected = True
self.statement = ''
def close(self):
"""Close the SQLite3 database."""
self.connection.commit()
self.connection.close()
self.connected = False
def incomplete(self, statement):
"""Concatenate clauses until a complete statement is made."""
self.statement += statement
if self.statement.count(';') > 1:
print ('An error has occurerd: ' +
'You may only execute one statement at a time.')
print 'For the statement: %s' % self.statement
self.statement = ''
if sqlite3.complete_statement(self.statement):
#the statement is not incomplete, it's complete
return False
else:
#the statement is incomplete
return True
def execute(self, statements):
"""Execute complete SQL statements.
Incomplete statements are concatenated to self.statement until they
are comple
```
import sqlite3
class DB(object):
"""DB initializes and manipulates SQLite3 databases."""
def __init__(self, database='database.db', statements=[]):
"""Initialize a new or connect to an existing database.
Accept setup statements to be executed.
"""
#the database filename
self.database = database
#holds incomplete statements
self.statement = ''
#indicates if selected data is to be returned or printed
self.display = False
self.connect()
#execute setup satements
self.execute(statements)
self.close()
def connect(self):
"""Connect to the SQLite3 database."""
self.connection = sqlite3.connect(self.database)
self.cursor = self.connection.cursor()
self.connected = True
self.statement = ''
def close(self):
"""Close the SQLite3 database."""
self.connection.commit()
self.connection.close()
self.connected = False
def incomplete(self, statement):
"""Concatenate clauses until a complete statement is made."""
self.statement += statement
if self.statement.count(';') > 1:
print ('An error has occurerd: ' +
'You may only execute one statement at a time.')
print 'For the statement: %s' % self.statement
self.statement = ''
if sqlite3.complete_statement(self.statement):
#the statement is not incomplete, it's complete
return False
else:
#the statement is incomplete
return True
def execute(self, statements):
"""Execute complete SQL statements.
Incomplete statements are concatenated to self.statement until they
are comple
Solution
Overall this looks good. Documentation and comments look pretty good, and the code is fairly sensible. Some comments:
-
Beware of mutable default arguments! In particular,
Although perhaps it would be better to defer this checking to the point where you’re about to connect and run the command – if there are no commands to execute (whether the user skipped that argument, or supplied an empty list) – you could skip setting up and closing the DB connection entirely.
-
It’s common to print errors to stderr, so I’d modify the
-
It’s better to use exceptions to indicate control flow, not just printing errors. This allows to caller to handle them accordingly. Within
-
In
This is both simpler and more Pythonic.
-
PEP 8 convention is that comments start by a hash following by a space, not a hash and then straight into prose.
-
There’s use of
to the top of the file. This is future-proofing for Python 3.
-
Because you have separate
You might want to consider defining a context manager for your class. This allows people to use
And then the cleanup code on the context manager always runs, even if you hit an exception in the body of the
-
I don’t know what the two lists defined at the end of the file are. Left-over cleanup code?
-
Beware of mutable default arguments! In particular,
statements=[]. If the statements variable gets mutated within the class, that persists through all instances of the class. Better to have a default value of None, and compare to that, i.e.:def __init__(self, database='database.db', statements=None):
if statements is None:
statements = []Although perhaps it would be better to defer this checking to the point where you’re about to connect and run the command – if there are no commands to execute (whether the user skipped that argument, or supplied an empty list) – you could skip setting up and closing the DB connection entirely.
-
It’s common to print errors to stderr, so I’d modify the
print() on line 46–7 accordingly. Also, you’ve misspelt occurred.-
It’s better to use exceptions to indicate control flow, not just printing errors. This allows to caller to handle them accordingly. Within
DB.incomplete(), I’d consider throwing a ValueError if the user passes multiple statements. Likewise lines 96–8 in DB.execute().-
In
DB.incomplete(), you can simplify the return statement: return not sqlite3.complete_statement(self.statement)This is both simpler and more Pythonic.
-
PEP 8 convention is that comments start by a hash following by a space, not a hash and then straight into prose.
-
There’s use of
print as a statement and as a function. You should be consistent – I’d recommend going to the print function, and adding from __future__ import print_functionto the top of the file. This is future-proofing for Python 3.
-
Because you have separate
connect() and close() methods, it’s possible that somebody could call connect(), execute some statements, and then hit an exception before they could close(). This means the database connection could stick around for longer than you were expecting.You might want to consider defining a context manager for your class. This allows people to use
with statement and your class, similar to the with open(file) construction: with DB(database='chat.db') as mydb:
# do stuff with mydbAnd then the cleanup code on the context manager always runs, even if you hit an exception in the body of the
with statement.-
I don’t know what the two lists defined at the end of the file are. Left-over cleanup code?
Code Snippets
def __init__(self, database='database.db', statements=None):
if statements is None:
statements = []return not sqlite3.complete_statement(self.statement)from __future__ import print_functionwith DB(database='chat.db') as mydb:
# do stuff with mydbContext
StackExchange Code Review Q#134535, answer score: 4
Revisions (0)
No revisions yet.