0

I'm running a local MySQL server for developing my PyQt application. It would be nice if I could display a QMessageBox if server is down, so that endusers would have some idea why is application not starting.

If I shut down the server and run my program from terminal, I get the usual response:

pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '127.0.0.1' (2)")

my code is simple

import pymysql as lite

con = lite.connect(host='127.0.0.1',unix_socket='/run/mysqld/mysqld.sock', user='ivica',passwd='pass',db='baza',charset='utf8')

#define one class that inherits QMainWindow and so on...

Is there a way for me to actually display a QMessageBox stating "MySQL server is down!" or something similar? If MySQL server is not running, my application window will not even show, just the terminal error.

:EDIT:

After proposed changes, my code looks like this:

con = None #this is how I make it global, eg. not in any method or class (?)

def dbconnect():
    global con
    #con = None
    try:
        if os.name == 'nt':
            con = lite.connect(host='127.0.0.1', user='ivica',passwd='pass',db='baza',charset='utf8')
        else:
            con = lite.connect(host='127.0.0.1',unix_socket='/run/mysqld/mysqld.sock', user='ivica',passwd='pass',db='baza',charset='utf8')
    except lite.err.OperationalError as err:
        msgBox = QtGui.QMessageBox()
        msgBox.setText(str(err))
        msgBox.show()
    return con

class Logon(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        self.ui=Ui_dlgLogovanje()
        self.ui.setupUi(self)
        QtCore.QObject.connect(self.ui.dugmeUloguj, QtCore.SIGNAL("clicked()"), self.doLogin)

    def doLogin(self):          
        with dbconnect():
            cur = dbconnect().cursor()

and error I get is:

Traceback (most recent call last):
  File "main.py", line 59, in doLogin
    with dbconnect():
AttributeError: __exit__

:EDIT 2:

After unutbu's answer, and some of my fiddling with the code, this is the solution I was looking for:

con = None

def dbconnect():
    global con
    try:
        if os.name == 'nt': 
            con = lite.connect(host='127.0.0.1', user='ivica',passwd='pass',db='baza',charset='utf8')
        else:
            con = lite.connect(host='127.0.0.1',unix_socket='/run/mysqld/mysqld.sock', user='ivica',passwd='pass',db='baza',charset='utf8')
    except lite.err.OperationalError as err:
        msgBox = QtGui.QMessageBox()
        msgBox.setText(str(err))
        msgBox.show()
    return con

class Logon(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        self.ui=Ui_dlgLogovanje()
        self.ui.setupUi(self)
        QtCore.QObject.connect(self.ui.dugmeUloguj, QtCore.SIGNAL("clicked()"), self.doLogin)

    def doLogin(self):      
        if con == None:
            reply = QtGui.QMessageBox.warning(self, 'Greška',
            "Can't establish connection to database!", QtGui.QMessageBox.Ok)
            if reply == QtGui.QMessageBox.Ok:
                self.close() #and when user clicks OK program closes

        else:
        with dbconnect():
            cur = dbconnect().cursor()
                    #do other database stuff, check credentials etc.
ivica
  • 1,388
  • 1
  • 22
  • 38
  • 1
    Do you get this `AttributeError` only when `lite.connect` fails, or do you get it even if a successful connection is made? – unutbu Sep 14 '12 at 20:29
  • If there is no MySQL server running, that is the error I get. If the server is running everything is fine, no errors. – ivica Sep 14 '12 at 20:43
  • 1
    When the connection fails, `con` equals `None`, which does not have an `__exit__` method. This is why the `with dbconnect()` fails. What do you want to happen if the connection fails? – unutbu Sep 14 '12 at 21:19
  • Show a simple message box, stating that there is no connection. – ivica Sep 14 '12 at 21:52
  • Yes, but should the program quit after the user acknowledges the message, or should the program continue except without a MySQL connection? – unutbu Sep 14 '12 at 22:37
  • It should show the message, and after user clicks "OK" button, program should exit, as it uses MySQL server for its basic operations. – ivica Sep 15 '12 at 07:43
  • I will accept your answer, but I'll also provide my addition to it in the original post. Once again, thank you. – ivica Sep 15 '12 at 20:44
  • I was WRONG. No data is written to database with dbconnect method. :/ – ivica Sep 15 '12 at 22:54
  • 1
    Get rid of the `with`. Just call `dbconnect()` once at the beginning of the script. You can then use the global `con` anywhere in the script. It makes writing the script easy, though I should mention it has at least two potential problems: (1) your server may allow a limited number of connections, so hogging a connection for the entire duration of your program may be bad. (2) If the connection is not used for a long time, it may timeout, in which case your program may unexpectedly fail unless you add more code to handle this... – unutbu Sep 16 '12 at 00:46

1 Answers1

1

Use a try...except block to handle the OperationalError exception:

import sys
from PyQt4 import QtGui
import pymysql as lite


def dbconnect():
    global con
    config = {
        'host' : '127.0.0.1',
        'user' = 'ivica',
        'passwd' = 'pass',
        'db' = 'baza',
        'charset' = 'utf8'
        }
    try:
        if os.name == 'nt':
            con = lite.connect(**config)
        else:
            con = lite.connect(unix_socket = '/run/mysqld/mysqld.sock', **config))
    except lite.err.OperationalError as err:
        msgBox = QtGui.QMessageBox()
        msgBox.setText(str(err))
        msgBox.exec_()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    con = None
    dbconnect()
    if con is not None:
        sys.exit(app.exec_())

It sounds like the MySQL connection is a core part of your program, so you might as well establish the connection at the very beginning or exit if the connection process is unsuccessful.

Also, using

with dbconnect():
    ...

is not compatible with defining a global con, since the connection is closed when Python exits the with-block.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • I see, nice approach. One other thing bothers me; somewhere in my code I use `with con: cur = con.cursor()` and with your code I get the error `NameError: global name 'con' is not defined` . Any advice? Thank you, I will accept your answer as soon as I get this error of my terminal. – ivica Sep 14 '12 at 19:05
  • 1
    With the way I've defined it, `con` is a local variable in `main`, not a global variable. You either need to define it as a global variable, or pass `con` as a parameter to the function that uses it, or use `with dbconnect() as con:` where you need it. – unutbu Sep 14 '12 at 19:23