Create an instance of a class from SQL query - python

I have the following class:
class SomeClass:
def __init__(self, name, date):
self.name = name
self.date = date
Now I have a function in another module, which connects to a SQLite database and executes a query:
def getEntry(user):
data = []
connection = lite.connect(database)
with connection:
cur = connection.cursor()
cur.execute("SELECT name, date FROM table WHERE column = ?", [user])
events = cur.fetchall()
# instantiate an instance of `SomeClass`
return data
So how would I create an instance of SomeClass and pass name and date entries to my newly created instance?

Since fetchall() returns a list of the rows, you should be able to do this (this should cover occasions where multiple results are returned as well):
for result in events:
my_instance = SomeClass(result[0], result[1])
# Do whatever you want to do with the instances, which looks like
# it may be appending to data
data.append(my_instance) # Or data.append(SomeClass(result[0], result[1]))
Can't test it right now, so apologies if it is way off :)

Related

Class inheritance in a python

Hello my practice question states
Create a YPSurvey class in its own file, that extends the Survey class. Here is the header for the constructor:
def__init__(self, database)
The YPSurvey constructor will call the Survey class constructor to create a connection. The YPSurvey class will have its own private cursor created from the Connection object of the database
This is how my survey class looks like
"""
File survey.py
Accesses the demographics data in a sqlite3 survey database
"""
import sqlite3
class Survey:
"""Represents survey information contained in a Demographic table"""
def __init__(self, database):
"""Constructor creates a Survey object and connects to a
Survey database using the input database parameter.
A cursor is also initialized to execute queries and hold the data.
Initializes a List for use in retrieving demographic information."""
self.__databaseName = database
self.__conn = sqlite3.connect(database)
self.__cur = self.__conn.cursor()
self.__demographicList = list()
def __str__(self):
"""Returns the database name"""
return print("Connected to "+str(self.__databaseName))
def getConn(self):
"""Returns the database connection for use by child class objects"""
return self.__conn
def clearDemographicList(self):
"""Clears the demographicList for reuse"""
self.__demographicList.clear()
def getNumberOfPersonIDs(self):
"""Returns the total number of people who took the survey"""
self.__cur.execute('Select count(PersonID) from Demographics')
for row in self.__cur:
total = row
return total
def getNumberByDemographic(self, userDemographic):
"""Returns a copy of the demographicList, filled with the number of
people in a particular demographic.
Example: if userDemographic = "Gender", demographicList will contain
a list of tuples with the number of females and males who took the survey"""
self.clearDemographicList()
self.__cur.execute("Select "+userDemographic+", count(?) from Demographics group by "
+userDemographic,(userDemographic,) )
for row in self.__cur:
self.__demographicList.append(row)
return self.__demographicList
and this is my YPSurvey class looks like
import sqlite3
class YPSurvey_Final:
def __init__(self, database):
self.__databaseName = database
self.__conn = sqlite3.connect(database)
self.__cur = self.__conn.cursor()
self.__phobiaList = list()
self.__demographicList = list()
self.__phobia_nameList = list()
def getNumberOfEachPhobia(self):
"""Returns the total number of people who took the survey"""
self.__cur.execute("SELECT Phobia, COUNT(*) FROM Phobias GROUP BY Phobia ORDER BY Phobia DESC")
for row in self.__cur:
self.__phobiaList.append(row)
return self.__phobiaList
def phobias(self):
print('I counted this many phobias: {}'.format(len(self.__phobiaList)))
for phobia in self.__phobiaList:
print('Phobia and # of people: {}'.format(phobia))
def phobias_names(self):
print('There is this many:{}'.format(len(self.__phobia_nameList)))
for phobias_n in self.__phobia_nameList:
print ("test",phobias_n)
def clearDemographicList(self):
"""Clears the demographicList for reuse"""
self.__demographicList.clear()
def getNumberByDemographic(self, userDemographic, phobia_name):
self.clearDemographicList()
self.__cur.execute("SELECT "+userDemographic+", phobia, 1.0 * COUNT(*) / (SELECT COUNT(*) FROM Phobias) AS percentage FROM Demographics,Phobias WHERE Phobia = ? GROUP BY "+userDemographic+"",(phobia_name,))
for row in self.__cur:
self.__demographicList.append(row)
return self.__demographicList
def demographics(self):
for demographic in self.__demographicList:
print(demographic)
def phobia_names(self):
for phobia_name in self.__phobia_nameList:
print(phobia_name)
So i dont understand what "extends the Survey class" means and how i can change my YP survey class to work with Survey class?
If you are looking out for extending the YPSurvey_Final from Survey class, you would need to replace the class definition for YPSurvey_Final as follow:
class YPSurvey_Final(Survey):
....
"extends" is often used in OOP to signal inheritance. You can make your class inherit from the other one Like this:
class MyClass(BaseClass):
And you can do stuff like delegate a call to the super-/baseclass constructor with the super method Like this:
def __init__(self):
super().__init__()

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

How do i use a list that is made in another file

Hello i am trying to get a variable out of another file but i don't know what i am doing wrong.
This is the first file. I am trying to take values from a list that is made in the second file and put them into a combobox but i don't know how to return the list to the first file. I tried the return statement thing but it tells me there should be none
import sys
from PyQt5.QtWidgets import (QWidget, QLabel,
QComboBox, QApplication)
import selectColumn
class Example(QWidget):
def __init__(self):
super().__init__()
ItemList=selectColumn.Column()
print(ItemList)
self.lbl = QLabel("1", self)
combo = QComboBox(self)
for i in range(len(ItemList)):
Item=ItemList[i]
combo.addItem(Item)
combo.move(50, 50)
self.lbl.move(50, 150)
combo.activated[str].connect(self.onActivated)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QComboBox')
self.show()
def onActivated(self, text):
self.lbl.setText(text)
self.lbl.adjustSize()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
This is the second file. This is the file that makes the column values into a list.
import sqlite3
class Column(object):
def __init__(self):
db= sqlite3.connect("SQLite database")
cursor = db.cursor()
cursor.execute("""SELECT Item_ID FROM Items_Table""")
data = cursor.fetchall()
print(data)
db.commit()
cursor.close()
Thank you for your time.
In the second file, selectColumn.py, you define class Column. Its __init__() method performs a select query on the database and retrieves all rows which it stores in the variable data. At the end of the method data goes out of scope and is deleted. Therefore you can not retrieve it again later, it is lost.
What you need to do is assign the results of the query to a member (or attribute) of the object. To do this use self.data = cursor.fetchall(). Now you can access data through a instance of the Column class.
import sqlite3
class Column(object):
def __init__(self):
with sqlite3.connect("SQLite database") as db:
cursor = db.cursor()
cursor.execute("""SELECT Item_ID FROM Items_Table""")
self.data = [item[0] for item in cursor.fetchall()]
Notice that I have changed the code to use a context manager when opening the database. This is a little cleaner as you don't need to worry about closing the cursor or database connection.
Also, cursor.fetchall() will return a list of tuples. Each tuple contains a single element, item ID. It will be more convenient to users of this class to have a list of just the IDs without the tuple wrapper. To do that I have used a list comprehension to extract the first (and only) element of each tuple. This results in a list of IDs.
Now, in the first file you can do this:
column = selectColumn.Column()
...
for item_id in column.data:
combo.addItem(item_id)
It will be a simpler design if you remove the class Column in the second file. As you have shown a function can solve your problem.
import sqlite3
def getData():
db = sqlite3.connect("SQLite database")
cursor = db.cursor()
cursor.execute("""SELECT Item_ID FROM Items_Table""")
data = cursor.fetchall()
db.close()
return data
And, in the first file, change the line ItemList=selectColumn.Column() by itensIds = selectColumn.getData()

python generator

I have homework that I am stuck on. I have gone as far as I can but I am stuck, can someone point me in the right direction.... I am getting stick in making each data row a new object. Normally i would think I could just iterate over the rows, but that will only return last row
Question:
Modify the classFactory.py source code so that the DataRow class returned by the build_row function has another method:
retrieve(self, curs, condition=None)
self is (as usual) the instance whose method is being called, curs is a database cursor on an existing database connection, and condition (if present) is a string of condition(s) which must be true of all received rows.
The retrieve method should be a generator, yielding successive rows of the result set until it is completely exhausted. Each row should be a new object of type DataRow.
This is what I have------
the test:
import unittest
from classFactory import build_row
class DBTest(unittest.TestCase):
def setUp(self):
C = build_row("user", "id name email")
self.c = C([1, "Steve Holden", "steve#holdenweb.com"])
def test_attributes(self):
self.assertEqual(self.c.id, 1)
self.assertEqual(self.c.name, "Steve Holden")
self.assertEqual(self.c.email, "steve#holdenweb.com")
def test_repr(self):
self.assertEqual(repr(self.c),
"user_record(1, 'Steve Holden', 'steve#holdenweb.com')")
if __name__ == "__main__":
unittest.main()
the script I am testing
def build_row(table, cols):
"""Build a class that creates instances of specific rows"""
class DataRow:
"""Generic data row class, specialized by surrounding function"""
def __init__(self, data):
"""Uses data and column names to inject attributes"""
assert len(data)==len(self.cols)
for colname, dat in zip(self.cols, data):
setattr(self, colname, dat)
def __repr__(self):
return "{0}_record({1})".format(self.table, ", ".join([" {0!r}".format(getattr(self, c)) for c in self.cols]))
DataRow.table = table
DataRow.cols = cols.split()
return DataRow
It should roughly be something like the following:
def retrieve(self, curs, condition=None):
query_ = "SELECT * FROM rows"
if condition is not None:
query_ += " %s" %condition
curs.execute(query_)
for row in curs.fetchall(): # iterate over the retrieved results
yield row # and yield each row in turn
Iterate over the rows as normal, but use yield instead of return.

Python method doesn't run in class

I am new to Python and can't seem to figure out why the .getRow method doesn't run. I created a DBMain class in dbMain.py and I am using pyTest.py to create the DBMain object to run getRow. When I run the debugger in Eclipse and DBMain's constructor does run but but when the getRow method is call nothing happens.
pyTest.py
import dbMain
def main():
db = dbMain.DbMain()
db.getRow()
if __name__ == '__main__':
main()
dbMain.py
##PydevCodeAnalysisIgnore
import pyodbc
class DbMain(object):
cncx = ''
def __init__(self):
cnxn = pyodbc.connect(driver='{SQL Server}',
server='server',
database='database',
uid='name',
pwd='pwd')
def getRow():
cursor = cnxn.cursor()
cursor.execute("select user_id, user_name from users")
row = cursor.fetchone()
return row
You do not return anything from getRow. Maybe you want to include something like
...
return row
Your getRow() method is not bound to the class. The signature for an instance method should look something like getRow(self) - the first parameter is the instance, which is received explicitly (but passed implicitly, when you call someinstance.method()).
To have something functional, you maybe should alter your dbMain to something like this:
##PydevCodeAnalysisIgnore
import pyodbc
class DbMain(object):
def __init__(self):
# make cnxn an attribute of the instance
self.cnxn = pyodbc.connect(driver='{SQL Server}', server='server',
database='database', uid='name', pwd='pwd')
# receive `self` explicitly
def getRow(self):
cursor = self.cnxn.cursor()
cursor.execute("select user_id, user_name from users")
row = cursor.fetchone()
# actually return something
return row
Further reading:
Python: Difference between class and instance attributes

Categories

Resources