tags:

views:

73

answers:

4

First time python user here, be gentle.... ;-)

Python 2.6 on OSX

Got a class which just has some wrappers around sqlite... here it is

from pysqlite2 import dbapi2 as sqlite

class SqliteDB:
    connection = ''
    curser = ''

    def connect(self):
        try:
            self.connection = sqlite.connect("pagespeed.sqlite")
            self.curser = self.connection.cursor()
         except sqlite.Error, e:
            print "Ooops: ", e.args[0]

    def find_or_create(self, table, column, value):
        self.curser.execute("SELECT id FROM ? WHERE ?=? LIMIT 1", (table, column, value))
        records = self.curser.fetchall()
        if records.count() == false:
            self.curser.execute("INSERT into ? SET ?=?", (table, column, value))
            self.curser.execute("SELECT id FROM ? WHERE ?=? LIMIT 1", (table, column, value))
        print records

and I call it like this in a separate file

import sqlitedb

def main():
    db = sqlitedb.SqliteDB()
    db.connect    
    url_id = db.find_or_create('urls', 'url', 'http://www.example.com')

however I get this error,

Traceback (most recent call last):

  File "update_urls.py", line 17, in <module>

  main()

  File "update_urls.py", line 11, in main

  url_id = db.find_or_create('urls', 'url', 'http://www.example.com')

  File "....../sqlitedb.py", line 16, in find_or_create

  self.curser.execute("SELECT id FROM ? WHERE ?=? LIMIT 1", (table, column, value))

AttributeError: 'str' object has no attribute 'execute'

So it's almost like self.curser is not getting a curser, or is self not correct?

Not to sure if what I am doing is right here....

cheers

+2  A: 

Do Not Do This.

class SqliteDB:
    connection = ''
    curser = ''

It doesn't "declare" any variables. This isn't C++ or Java.

Do this.

class SqliteDB:
    def __init__( self ):
        self.connection = None
        self.cursor= None
S.Lott
Actually, it declares class variables (accessible through `self.connection` or `SqliteDB.connection`). As soon as you write to `self.connection` you create an instance variable (meaning only `SqliteDB.connection` will access the class variable now).
Zooba
Zooba: You're very close. It declares nothing. It **creates** class level variables that are concealed by instance variables. It's a common mistake.
S.Lott
great thanks for the feedback :)
Wizzard
+5  A: 

I don't know what's wrong, but at the very least:

db.connect  

should be

db.connect()

e.g. call the function.

OK. S.Lott had the answer, I just found an other bug :)

extraneon
No... you found the bug, S. Lott found a nitpick. With his correction, OP will just get the same error but with `NoneType` instead of `str`.
aaronasterling
er, scratch that. OP would get an `AttributeError`. Popped into my head when thinking about something completely different. Ad it is good advice.
aaronasterling
@aaronsterling: Huh? You were right first time. Previously, self.curser refers to class attribute, value ''. After S.Lott change (but not fixing not calling connect method): instance attribute, value None. So: from `AttributeError: 'str' object has no attribute 'execute'` to `AttributeError: 'NoneType' object has no attribute 'execute'`
John Machin
@John Machin, no because the change moves the creation of `connection` and `curser_sic` into the `connect` method which is never called. When `find_or_create` is then called, you should get `AttributeError: 'SqliteDB' object has not attribute 'curser_sic'`. right? So it's still an `Attribute` error, just with a different attribute.
aaronasterling
@aaronsterling: You are correct as to outcome. @S.Lott moved the creation of those 2 into the `__init__` method, which would be called, not the `connect` method. However @S.Lott also changed from `curser_sic` to `cursor` on the way to the `__init__`. Had he not done that, the outcome would have been as you suggested initially.
John Machin
@John Machin. You're right, I don't know how I missed that `__init__` runs automatically in my calculations. I really can be remarkably stupid at times.
aaronasterling
@aaronsterling: You were spot-on with the major conclusion (nitpick, not the real problem) :-)
John Machin
+1  A: 

And the 3rd bug:

self.curser.execute("SELECT id FROM ? WHERE ?=? LIMIT 1", (table, column, value))

You can't parameterise table names and column names. All you can parameterise are things that can be an expression in SQL syntax. You'll need to do something like this:

sql = "SELECT id FROM %s WHERE %s = ? LIMIT 1" % (table, column)
self.curser.execute(sql, (value, ))

Oh yeah, to save the flurry of comments: or use the modern string.format(data) method instead of the antique string % data operator.

John Machin
string.format(data) was python 3 I thought? I will recheck but from my OP I am using 2.6. Thanks for the feedback.
Wizzard
`str.format(*args, **kwargs)` (to be more precise) is in 2.6
John Machin
and here's a link: http://docs.python.org/release/2.6/whatsnew/2.6.html#pep-3101-advanced-string-formatting
John Machin
+1  A: 

I will also add that this will not work :

curser.execute("SELECT id FROM ? WHERE ?=? LIMIT 1", (table, column, value))

because placeholders (?) doesn't work for table name, you should rather use string formatting before if you still want to use table name as parameter:

query = "SELECT id FROM %s WHERE %s=? LIMIT 1" % (table, column)
curser.execute(query, (value, ))

and one last thing "curser" is misspelled :)

singularity
great thanks for the feedback, my poor spelling as well :) thnks for your time
Wizzard