simple CLI todo manager with sqlite3 database storing problem - python

I am currently trying to make a command line todo manager that will allow the user to input a task(s), remove it and list the task(s) out. From what I tried visualizing it didn't do as I thought it would, it's my first time using sqlite3.
What I am trying to achieve:
Storing the task(s) in the database which will automatically add an incrementing ID to it.
Example:
python todo.py -add do the laundry on Sunday
[in the database]
Id Task
1 do the laundry on Sunday
My code.
import sqlite3
import argparse
def parse_args():
desc = 'Todo manager for storing and removing tasks'
parser = argparse.ArgumentParser(description=desc)
parser.add_argument("-a", "--add", "-add", help="To add a new item to the list",
type=str, nargs="+")
parser.add_argument("-r", "-remove", "--remove", help="To remove an item from the list",
type=int)
parser.add_argument("-l", "-list", "--list", help="displays the tasks or task in the list",
nargs="*")
args = parser.parse_args()
return args
#staticmethod
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
def get_todo_list():
database_connection.row_factory = dict_factory
cursor = database_connection.cursor()
cursor.execute("select rowid, * FROM todo_list")
return cursor.fetchall()
def add_to_todo_list(num,task):
cursor = database_connection.cursor()
cursor.execute("INSERT INTO todo_list VALUES (?)", (str(task),))
database_connection.commit()
def remove_from_todo_list(rowid):
cursor = database_connection.cursor()
cursor.execute("DELETE FROM todo_list WHERE rowid = ?", (rowid,))
database_connection.commit()
if __name__ == '__main__':
commands = parse_args()
# Creating table for database using sqlite
database_connection = sqlite3.connect('todo_list.db')
cursor = database_connection.cursor()
cursor.execute('''CREATE TABLE if not exists todo_list(
description TEXT);''')
database_connection.commit()
if commands.add:
# Stops accepting tasks when there is a blank task as input.
if not commands.add == ' ':
add_to_todo_list(commands.add)
elif commands.remove:
remove_from_todo_list(commands.remove)
elif commands.list:
get_todo_list()
However, my database is not accepting any values when I am trying to store data. By putting Id as Id INTEGER PRIMARY KEY when creating the table i.e.
cursor.execute('''CREATE TABLE if not exists todo_list(
Id INTEGER PRIMARY KEY
description TEXT);''')
Will the Id increment as I add data to the database?

sqlite3.InterfaceError: Error binding parameter 1 - probably unsupported type.
Your inputs from argparse are coming in as str, yet you defined your column ID as an INTEGER in your db. Fix is:
cursor.execute("INSERT INTO todo_list VALUES (?,?)", (int(num), task,))
Storing the task(s) in the database which will automatically add an incrementing ID to it.
According to the sqlite docs here, defining a INTEGER PRIMARYKEY will auto-increment. Simply pass a null value to it, and sqlite takes care of the rest for you.
You have a few issues on your code when it comes to displaying and adding the tasks. First, initializing the DB:
cursor.execute(
"""CREATE TABLE if not exists todo_list(
id INTEGER PRIMARY KEY,
description TEXT);"""
)
How you had it before your post edit was fine. Then, the add_to_todo_list:
def add_to_todo_list(task):
cursor = database_connection.cursor()
cursor.execute("INSERT INTO todo_list VALUES (?,?)", (None, str(task)))
database_connection.commit()
Notice the removal of num from the functions input, and the passing of None for the column ID. Within the get_todo_list() you can fetch it more easily as so:
def get_todo_list():
cursor = database_connection.cursor()
cursor.execute("select * FROM todo_list")
return cursor.fetchall()
A fix is also needed in the way you parse your args; for commands.list you need to do the following:
elif commands.list is not None:
print(get_todo_list())
This is since commands.list will be a [] when you do app.py -list, which Python evaluates to False (empty lists are falsey). You also ought to print the contents of the function to terminal -- so don't forget that. With the edits above I can do on my terminal:
python test.py -add Random Task!
python test.py -add Hello World!
python test.py -list
[(1, "['Random', 'Task!']"), (2, "['Hello', 'World!']")]

Related

show sqlite data in several window

I want to know how can I use one data in several windows with python, Tkinter
this is my code for creating the database
def connect():
conn = sqlite3.connect("../database.db")
cur = conn.cursor()
cur.execute(
"CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY , name text , price INTEGER )"
)
conn.commit()
conn.close()
connect()
and this my code for get data and show :
def clear_item_list():
items.delete(0, END)
def fill_item_list(items):
for item_ in items:
items.insert(END, item_)
def item_list_view():
clear_item_list()
items = app.manager.data_1.view()
fill_item_list(items)
I when I want to run project I get an error: 'str' object cannot be interpreted as an integer
I don't know what to do if you can, please help me

Python + MySQL: Search function returning all entries

I'm putting together an inventory program using Python and MySQL. I want to implement a search function that returns entries based on user input (programmed in a separate GUI file). In the code below, I expected that the search function would return entries with the brand "UGreen". Instead, it returns all of the entries in the table.
I'm not sure what I'm doing wrong here. I have used a similar structure in another program with a sqlite database instead and the search worked fine.
Any and all help/suggestions would be greatly appreciated :)
import mysql.connector
equipdb = mysql.connector.connect(
host = "localhost",
user = "root",
password = "REDACTED",
database = "tel_inventory"
)
def view():
cur = equipdb.cursor()
cur.execute("SELECT * FROM equipment")
result = cur.fetchall()
return result
def search(name="", brand="", model="", consumables="", storage="", room="", photo=""):
cur = equipdb.cursor()
cur.execute("SELECT * FROM equipment WHERE name=%s OR brand=%s OR model=%s OR consumables=%s OR storage=%s OR room=%s OR photo=%s", (name, brand, model, consumables, storage, room, photo))
result = cur.fetchall()
return result
#print(view())
print(search(brand="UGreen"))
Try using keyword argument directly
def search(**kwargs):
cur = equipdb.cursor()
key = str(list(kwargs.keys())[0])
value = str(kwargs[key])
cur.execute('SELECT * FROM equipment WHERE {} = "{}"'.format(key,value))
result = cur.fetchall()
return result

Python: Display table names, get user selection, display that table report from SQLite

I have a program that currently reads a database and it will print out the list of tables the current database has.
This is the DB LINK: database (Copy and Paste)
What I am trying to do now is to get user input to display the records from the specific table they chose. I am having trouble to get user selection to display the records. I am using SQLite3 as my main database software.
Also I am very aware of this question on here, but
I keep getting an error when I used the .format(category) embedded on my SQL.
sqlite3.ProgrammingError:
Incorrect number of bindings supplied.
The current statement uses 1, and there are 0 supplied.
This is what I have done so far:
import sqlite3
def get_data():
print("\nSelect a table: ", end="")
category = input()
category = str(category)
if '1' <= category <= '11':
print()
return category
else:
raise ValueError
def get_tables():
database = 'Northwind.db'
connection = sqlite3.connect(database)
c = connection.cursor()
sql = "SELECT * FROM sqlite_master WHERE type='table' AND NAME NOT LIKE 'sqlite_sequence' ORDER BY NAME "
x = c.execute(sql)
for row in x.fetchall():
table = row[1]
print(table)
def main():
category = get_data()
print(category)
get_tables()
if __name__ == "__main__":
main()
I hope this all makes sense. I appreciate the help.
Copy comment: My sql statement look like this:
*)multiple lines for readability
sql = ("SELECT * FROM sqlite_master
WHERE type='table'
AND Name = ?
AND NAME NOT LIKE 'sqlite_sequence'".format(category))
Your SQL string should be:
sql = """SELECT * FROM sqlite_master
WHERE type='table'
AND Name = ?
AND NAME NOT LIKE 'sqlite_sequence'"""
and the execute statement should be:
x = c.execute(sql, (category,))
also ensure that you are passing category as a parameter to your get_tables function.

How to test if a table already exists?

I'm working on a scrabblecheat program
Following some examples I have the following code below which uses SQLite for a simple database to store my words.
However it tells me I can't recreate the database table.
How do I write in a check for if there is already a table named spwords, then skip trying to create it?
The error:
(<class 'sqlite3.OperationalError'>, OperationalError('table spwords already exists',), None)
The Code:
def load_db(data_list):
# create database/connection string/table
conn = sqlite.connect("sowpods.db")
#cursor = conn.cursor()
# create a table
tb_create = """CREATE TABLE spwords
(sp_word text, word_len int, word_alpha text, word_score int)
"""
conn.execute(tb_create) # <- error happens here
conn.commit()
# Fill the table
conn.executemany("insert into spwords(sp_word, word_len, word_alpha, word_score) values (?,?,?,?)", data_list)
conn.commit()
# Print the table contents
for row in conn.execute("select sp_word, word_len, word_alpha, word_score from spwords"):
print (row)
if conn:
conn.close()
The query you're looking for is:
SELECT name FROM sqlite_master WHERE type='table' AND name='spwords'
So, the code should read as follows:
tb_exists = "SELECT name FROM sqlite_master WHERE type='table' AND name='spwords'"
if not conn.execute(tb_exists).fetchone():
conn.execute(tb_create)
A convenient alternative for SQLite 3.3+ is to use a more intelligent query for creating tables instead:
CREATE TABLE IF NOT EXISTS spwords (sp_word text, word_len int, word_alpha text, word_score int)
From the documentation:
It is usually an error to attempt to create a new table in a database that already contains a table, index or view of the same name. However, if the "IF NOT EXISTS" clause is specified as part of the CREATE TABLE statement and a table or view of the same name already exists, the CREATE TABLE command simply has no effect (and no error message is returned). An error is still returned if the table cannot be created because of an existing index, even if the "IF NOT EXISTS" clause is specified.
conn = sqlite3.connect('sowpods.db')
curs = conn.cursor()
try:
curs.execute('''CREATE TABLE spwords(sp_word TEXT, word_len INT, word_alpha TEXT,word_score INT)''')
conn.commit()
except OperationalError:
None
https://docs.python.org/2/tutorial/errors.html
I believe if it already exists you can just skip the error and move directly into the inserting of the data
I am not a fan of the bounce the CREATE off the database approach. You should know whether the table exists so that first time initialization can occur.
Here is the same query based answer but based on general purpose functions:
def getTables(conn):
"""
Get a list of all tables
"""
cursor = conn.cursor()
cmd = "SELECT name FROM sqlite_master WHERE type='table'"
cursor.execute(cmd)
names = [row[0] for row in cursor.fetchall()]
return names
def isTable(conn, nameTbl):
"""
Determine if a table exists
"""
return (nameTbl in getTables(conn))
Now the top code is
if not(isTable(conn, 'spwords')):
# create table and other 1st time initialization
Here is an example that shows how to cleanly consume the result from fetchone() call:
table_exists(conn:sqlite3.Connection, tbl_name:string) -> bool:
(count,) = conn.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='{}'".format(tbl_name)).fetchone()
return (count > 0)

python mysqldb, for loop not deleting records

Somewhere in here lies a problem. http://paste.pocoo.org/show/528559/
Somewhere between lines 32 and 37. As you can see the DELETE FROM is inside a for loop.
Running the script just makes the program go through the loop and exit, without actually removing any records.
Any help would be greatly appreciated! Thanks!
#!/usr/bin/env python
# encoding: utf-8
import os, os.path, MySQLdb, pprint, string
class MySQLclass(object):
"""Learning Classes"""
def __init__(self, db):
self.db=db
self.cursor = self.db.cursor()
def sversion(self):
self.cursor.execute ("SELECT VERSION()")
row = self.cursor.fetchone ()
server_version = "server version:", row[0]
return server_version
def getRows(self, tbl):
""" Returns the content of the table tbl """
statmt="select * from %s" % tbl
self.cursor.execute(statmt)
rows=list(self.cursor.fetchall())
return rows
def getEmailRows(self, tbl):
""" Returns the content of the table tbl """
statmt="select email from %s" % tbl
self.cursor.execute(statmt)
rows=list(self.cursor.fetchall())
return rows
def removeRow(self,tbl,record):
""" Remove specific record """
print "Removing %s from table %s" %(record,tbl)
print tbl
self.cursor.execute ("""DELETE FROM maillist_frogs where email LIKE %s""", (record,))
def main():
#####connections removed
sql_frogs = MySQLclass(conn_frogs)
sql_mailgust = MySQLclass(conn_mailgust)
frogs_emails = sql_frogs.getEmailRows ("emails")
frogs_systemcatch = sql_frogs.getEmailRows ("systemcatch")
mailgust_emails = sql_mailgust.getEmailRows ("maillist_frogs")
aa = set(mailgust_emails)
remove = aa.intersection(frogs_emails)
remove = remove.union(aa.intersection(frogs_systemcatch))
for x in remove:
x= x[0]
remove_mailgust = sql_mailgust.removeRow ("maillist_frogs",x)
conn_frogs.close ()
conn_mailgust.close ()
if __name__ == '__main__':
main()
the problem is python-msyqldb specific.:
Starting with 1.2.0, MySQLdb disables autocommit by default, as required by the DB-API standard (PEP-249). If you are using InnoDB tables or some other type of transactional table type, you'll need to do connection.commit() before closing the connection, or else none of your changes will be written to the database.
therefore, after the DELETE, you must self.db.commit
The removeRow() method does not return a value, yet remove_mailgust is expecting to receive this non-existent value.
Also, your removeRow() class method is statically fixed to only search the table maillist_frogs in its query. You should probably set the table name to accept the second parameter of the method, tbl.
Finally, your removeRow() method is comparing the value of a record (presumably, an id) using LIKE, which is typically used for more promiscuous string comparison. Is email your primary key in this table? If so, I would suggest changing it to:
self.cursor.execute ("""DELETE FROM %s where email_id = %s""", (tbl, record,))

Categories

Resources