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__()
Related
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
I think about how to use ObjectListView fitting the Model-View-Controller Pattern with wxPython & SQLAlchemy. And I am not sure about it so I created a simple example as a working basis not as a solution.
The concrete question related to the code below is: What should happen if a new MyData object is generated?
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import wx
import sqlalchemy as sa
import sqlalchemy.ext.declarative as sad
import ObjectListView as olv
_Base = sad.declarative_base()
class MyData(_Base):
"""the database table representing class"""
__tablename__ = 'MyData'
__name = sa.Column('name', sa.String, primary_key=True)
__count = sa.Column('count', sa.Numeric(10, 2))
def __init__(self, name, count):
super(MyData, self).__init__()
self.__name = name
self.__count = count
def GetName(self):
return self.__name
def GetCount(self):
return self.__count
def CreateData():
"""
helper creating data
imagnine this as a SELECT * FROM on the database
"""
return [
MyData('Anna', 7),
MyData('Bana', 6)
]
class MyView(olv.ObjectListView):
def __init__(self, parent):
super(MyView, self).__init__(parent, wx.ID_ANY, style=wx.LC_REPORT)
self.SetColumns([
olv.ColumnDefn('Name', valueGetter='GetName'),
olv.ColumnDefn('Count', valueGetter='GetCount')
])
data = CreateData()
self.SetObjects(data)
def ColDef(self):
return
class MyApp(wx.App):
def OnInit(self):
frame = wx.Frame(None)
view = MyView(frame)
frame.Show()
return True
if __name__ == '__main__':
app = MyApp()
app.MainLoop()
What whould you think about...
Create a controller "MyDataController" that handle all the sqlalchemy-stuff for MyData objects. e.g. GetAllMyDataObjects AddMyDataObjectToDatabase, QueryMyData, ...
Related to the Observer-Pattern the ObjectListView observer the controller as the subject.
I am not sure if this is an elegant solution.
The point is the confusion about, what is the model? The one (and new) MyData instance or the list of all MyData instances? There is no intelligent list which could act like a model.
With regards to OLV. In my case when an update to the SA model happens I use pubsub to inform the world about the change add/update/delete.
Then my OLV base class subscribes to the 'itemAdded', 'itemModified' and 'itemDeleted' messages and the following are the methods called:
def pubListItemAdded(self, dbitem):
"""
Add list if dbitem instance matches dbScKlass
:param dbitem: an SA model instance
If dbitem instance matches the list controls model it is added.
"""
# protect from PyDeadObjectError
if self:
# E.g. Externalimp is a faked class and does not exist in db
# so we need to protect for that
if hasattr(db, self._klassName):
tList = self.getList()
cInst = getattr(db, self._klassName)
if isinstance(dbitem, cInst):
log.debug("olvbase - added: %s", dbitem)
log.debug("olvbase - added: %s", self)
# for some reason this creates dups on e.g. rating/tasting/consumption
# so, lets check if it is there and only add if not
idx = tList.GetIndexOf(dbitem)
if idx == -1:
tList.AddObject(dbitem)
else:
tList.RefreshObject(dbitem)
# bring it into view
self.resetSelection()
tList.SelectObject(dbitem, deselectOthers=True,
ensureVisible=True)
def pubListItemModified(self, dbitem):
"""
Update list if dbitem instance matches dbScKlass
:param dbitem: an SA model instance
If dbitem instance matches the list controls model it is updated.
"""
# protect from PyDeadObjectError
if self:
# E.g. Externalimp is a faked class and does not exist in db
# so we need to protect for that
if hasattr(db, self._klassName):
cInst = getattr(db, self._klassName)
if isinstance(dbitem, cInst):
log.debug("olvbase - modified: %s", dbitem)
log.debug("olvbase - modified: %s", self)
tList = self.getList()
# need to refresh to ensure relations are loaded
wx.GetApp().ds.refresh(dbitem)
tList.RefreshObject(dbitem)
tList.SelectObject(dbitem, deselectOthers=True,
ensureVisible=True)
# deselect all, so if we select same item again
# we will get a select event
tList.DeselectAll()
def pubListItemDeleted(self, dbitem):
"""
Delete from list if dbitem instance matches dbScKlass
:param dbitem: an SA model instance
If dbitem instance matches the list controls model it is updated.
"""
# protect from PyDeadObjectError
if self:
# E.g. Externalimp is a faked class and does not exist in db
# so we need to protect for that
if hasattr(db, self._klassName):
cInst = getattr(db, self._klassName)
if isinstance(dbitem, cInst):
log.debug("olvbase - deleted: %s", dbitem)
log.debug("olvbase - deleted: %s", self)
tList = self.getList()
tList.RemoveObject(dbitem)
self.currentObject = None
self.currentItemPkey = None
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.
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 :)
I'm trying to figure out the best way to create a class that can modify and create new users all in one. This is what I'm thinking:
class User(object):
def __init__(self,user_id):
if user_id == -1
self.new_user = True
else:
self.new_user = False
#fetch all records from db about user_id
self._populateUser()
def commit(self):
if self.new_user:
#Do INSERTs
else:
#Do UPDATEs
def delete(self):
if self.new_user == False:
return False
#Delete user code here
def _populate(self):
#Query self.user_id from database and
#set all instance variables, e.g.
#self.name = row['name']
def getFullName(self):
return self.name
#Create a new user
>>u = User()
>>u.name = 'Jason Martinez'
>>u.password = 'linebreak'
>>u.commit()
>>print u.getFullName()
>>Jason Martinez
#Update existing user
>>u = User(43)
>>u.name = 'New Name Here'
>>u.commit()
>>print u.getFullName()
>>New Name Here
Is this a logical and clean way to do this? Is there a better way?
Thanks.
You can do this with metaclasses. Consider this :
class MetaCity:
def __call__(cls,name):
“”“
If it’s in the database, retrieve it and return it
If it’s not there, create it and return it
““”
theCity = database.get(name) # your custom code to get the object from the db goes here
if not theCity:
# create a new one
theCity = type.__call__(cls,name)
return theCity
class City():
__metaclass__ = MetaCity
name = Field(Unicode(64))
Now you can do things like :
paris = City(name=u"Paris") # this will create the Paris City in the database and return it.
paris_again = City(name=u"Paris") # this will retrieve Paris from the database and return it.
from : http://yassinechaouche.thecoderblogs.com/2009/11/21/using-beaker-as-a-second-level-query-cache-for-sqlalchemy-in-pylons/
Off the top of my head, I would suggest the following:
1: Use a default argument None instead of -1 for user_id in the constructor:
def __init__(self, user_id=None):
if user_id is None:
...
2: Skip the getFullName method - that's just your Java talking. Instead use a normal attribute access - you can convert it into a property later if you need to.
What you are trying to achieve is called Active Record pattern. I suggest learning existing systems providing this sort of things such as Elixir.
Small change to your initializer:
def __init__(self, user_id=None):
if user_id is None: