Why am I getting this error when creating two buttons in python appJar?

Question:

I am building a simple GUI using appJar for a library system I made for school. I’m trying to make a function that allows users to either upvote or downvote a book (books are stored in a sqlite3 database) given the book ID (one of the columns for each entry in the db). Here is my code:

def upvote(id):
    statement = f"SELECT review from books WHERE id={id}"
    cur.execute(statement)
    rating = cur.fetchall()

    newRating = rating[0][0] + 1
    statement2 = f"UPDATE books SET review={newRating} WHERE id={id}"
    cur.execute(statement2)
    con.commit()

def downvote(id):
    statement = f"SELECT review from books WHERE id={id}"
    cur.execute(statement)
    rating = cur.fetchall()

    newRating = rating[0][0] - 1
    statement2 = f"UPDATE books SET rating={newRating} WHERE id={id}"
    cur.execute(statement2)
    con.commit()

def giveRating():
    app.startSubWindow("Give Rating", modal=True)
    app.show()
    app.setFont(18)
    app.setBg("orange")
    app.setSize(400, 400)

    app.addLabelEntry("Book ID")
    bookId = app.getEntry("Book ID")
    app.addButton("Upvote", upvote(bookId))
    app.addButton("Downvote", downvote(bookId))
    app.stopSubWindow()

The reason for using subwindows is that the rating page is opened upon clicking a button from a dashboard page.

Anyone know why I am getting the following error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/tkinter/__init__.py", line 1948, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "/Users/guilhermelopes/Documents/terminal library sys/venv/lib/python3.11/site-packages/appJar/appjar.py", line 3781, in <lambda>
    return lambda *args: funcName()
                         ^^^^^^^^^^
  File "/Users/guilhermelopes/Documents/terminal library sys/app.py", line 83, in giveRating
    app.addButton("Upvote", upvote(bookId))
                            ^^^^^^^^^^^^^^
  File "/Users/guilhermelopes/Documents/terminal library sys/app.py", line 56, in upvote
    cur.execute(statement)
sqlite3.OperationalError: incomplete input

I feel like I am missing something obvious but I can’t find anything relevant to my issue in the docs. Whilst the input label is created, I expected the two buttons to be created along with it, but instead I get the above error.

Thanks in advance.

Asked By: x1n0_

||

Answers:

Why are you selecting the column review?
It is not the column that you want to update.
You should select the column rating.

But, why do you select anything?

You can do what you want with the UPDATE statement only:

def upvote(id):
    statement = "UPDATE books SET rating = COALESCE(rating, 0) + 1 WHERE id = ?"
    cur.execute(statement, (id,))
    con.commit()

def downvote(id):
    statement = "UPDATE books SET rating = COALESCE(rating, 0) - 1 WHERE id = ?"
    cur.execute(statement, (id,))
    con.commit()

I use COALESCE(rating, 0) just in case rating is nullable.
If it is not, change to just rating.

Also, from http://appjar.info/pythonWidgets/, you should pass only the function’s name as a parameter to addButton:

app.addButton("Upvote", upvote)
app.addButton("Downvote", downvote)
Answered By: forpas

I think this may be the problem, or at least part of the problem:

app.addButton("Upvote", upvote(bookId))

The way you’re referring to upvote (i.e. you put parentheses () after it), it is called right now, instead of later when the button is pressed.

In typical GUI apps like this, you would only pass the function name:

app.addButton("Upvote", upvote)

Which would give the button a reference to the upvote function that it can call later when the button is actually pressed. (Although in this specific case I don’t know how you would do that and also be able to pass the bookId argument…)

And indeed, the appjar documentation for addButton() does it exactly that way. http://appjar.info/pythonWidgets/

You’re using addButton() wrongly.

Answered By: John Gordon
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.