catch internal error if an error occurs in the query - python

I am trying to connect to postgresql with qt. I managed that last one, but, just like in my previous question, an invisible internal error occurs. The difference is that now it happens when a query fails (for example, when the table does not exist).
The program should print None to the screen. But the program ends before that. Exactly when I call obj.prepare(query).
This is my code:
from PySide2.QtSql import QSqlDatabase, QSqlQuery
from PySide2.QtWidgets import QApplication, QMainWindow
app = QApplication([])
class SqlError(Exception):
pass
def connect(host, port, dbname, user, password):
db = QSqlDatabase.addDatabase("QPSQL")
db.setHostName(host)
db.setPort(port)
db.setDatabaseName(dbname)
if(not db.open(user, password)):
raise SqlError(db.lastError().text())
def execute(query, *args, **kwargs):
obj = QSqlQuery()
if(not obj.prepare(query)):
raise SqlError(obj.lastError().text())
if(kwargs):
for var, value in kwargs.items():
obj.bindValue(var, value)
elif(args):
for value in args:
obj.addBindValue(value)
if(not obj.exec_()):
raise SqlError(obj.lastError().text())
connect(host="localhost",
port=0,
dbname="mydatabase",
user="user",
password="password")
print(execute("SELECT * FROM c_venta"))
Attached screenshot of my idle. This behavior is similar to what happens when running from cmd and importing my script from the interpreter.
What do I need to catch that error, what am I doing wrong?
I've looked at several tutorials and I'm doing the same.
Edit: I tried the script importing it from the interpreter and it closes said interpreter without saying anything.
Edit 2: I tried variants of a certain answer and it didn't work for me either. https://stackoverflow.com/a/33741755/12913664
Edit 3: Pass the result of QSqlDatabase.database() to QSqlQuery (same result), to prepare (says it only accepts one argument), and tried saving the connection to a global variable and using db.exec (same result).

Related

Issue when executing code snippet with "exec" and inheritance

I'm having some issues when trying to execute a string/file from within a QPlainTextEdit, it appears to be some sort of scoping issues. What happens is that when the code EXECUTABLE_STRING is run from the global scope, it works fine. However, when it is run from a local scope, such as through the AbstractPythonCodeWidget, it either can't find the object to do inheritance TypeError: super(type, obj): obj must be an instance or subtype of type or runs into a name error NameError: name 'Test' is not defined. Which oddly changes based on whether or not the exec(EXECUTABLE_STRING) line is commented/uncommented when run. Any help would be greatly appreciated.
import sys
from PyQt5.QtWidgets import QApplication, QPlainTextEdit
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor
app = QApplication(sys.argv)
EXECUTABLE_STRING = """
from PyQt5.QtWidgets import QLabel, QApplication
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor
class Test(QLabel):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
self.setText("Test")
a = Test()
a.show()
a.move(QCursor.pos())
"""
class AbstractPythonCodeWidget(QPlainTextEdit):
def __init__(self, parent=None):
super(AbstractPythonCodeWidget, self).__init__(parent)
self.setPlainText(EXECUTABLE_STRING)
def keyPressEvent(self, event):
if event.modifiers() == Qt.ControlModifier:
if event.key() == Qt.Key_Return:
# this does not work
#exec(compile(self.toPlainText(), "script", "exec"), globals(), locals())
exec(self.toPlainText())
return QPlainTextEdit.keyPressEvent(self, event)
w = AbstractPythonCodeWidget()
w.show()
w.move(QCursor.pos())
w.resize(512, 512)
# this works when run here, but not when run on the keypress event
# exec(EXECUTABLE_STRING)
sys.exit(app.exec_())
First of all, running exec based on user input can be a security issue, but most importantly usually leads to fatal crash unless lots of precautions are taken, since you're using the same interpreter for both your program and the user code: basically, if the code of the user fails, your program fails, but that's not the only problem.
The reason for which your code doesn't run properly is actually a bit complex, and it's related to the scope of the class name, which becomes a bit complex when running exec along with super().[1]
An interesting aspect is that if you remove the arguments of super (and you should, since Python 3), the program won't raise any error.
But that won't be enough: a is a local variable, and it will be garbage collected as soon as exec is finished, and since the label is assigned to that variable, it will be destroyed along with it.
A possible solution would be to make the reference persistent, for example by assigning it to self (since self exists in the scope of the executed script). This is a working example of the EXECUTABLE_STRING:
from PyQt5.QtWidgets import QLabel
from PyQt5.QtGui import QCursor
class Test(QLabel):
def __init__(self, parent=None):
super().__init__(parent)
self.setText("Test")
self.a = Test()
self.a.show()
self.a.move(QCursor.pos())
As you can see, we don't need to import everything again anymore, we only import QLabel, since it wasn't imported in the main script, but everything else already exists in the scope of the script, including the current QApplication instance.
That said, all the above is only for knowledge purposes, as you should NOT use exec to run user code.
For instance, try to paste the following in the text edit, and run it:
self.document().setHtml('This should <b>NOT</b> happen!!!<br/><br/>Bye!')
self.setReadOnly(True)
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication
QTimer.singleShot(2000, QApplication.quit)
As you can see, not only the above code is able to change the input, but also take complete control of the whole application.
You could prevent that by calling a function that would basically limit the scope of the execution:
def runCode(code):
try:
exec(code)
except Exception as e:
return e
class AbstractPythonCodeWidget(QPlainTextEdit):
# ...
def keyPressEvent(self, event):
if event.modifiers() == Qt.ControlModifier:
if event.key() == Qt.Key_Return:
error = runCode(self.toPlainText())
if error:
QMessageBox.critical(self, 'Script crash!', str(error))
return QPlainTextEdit.keyPressEvent(self, event)
But that's just because no self is involved: you could still use w.a = Test() with the example above.
So, if you want to run user made scripts in your program, exec is probably not an acceptable solution, unless you take enough precautions.
If you don't need direct interaction between your program and the user script, a possibility could be to use the subprocess module, and run the script with another python interpreter instance.
[1] If anybody has a valid resource/answer that might shed some light on the topic, please comment.
Found a similar issue that goes into more depth about how the scope works with Globals/Locals in exec here:
globals and locals in python exec()
Don't want to copy/paste the entire thread, but the answer that worked for me in this post was:
d = dict(locals(), **globals())
exec (code, d, d)

QEventLoop in QAxWidget instance failed

I'm working on terminal based PyQt application using Windows OCX api.
And I'm having trouble over implement(calling exec) QEventLoop in QAxWidget instance.
If I call exec() in main QApplication main loop, everthing is fine.
But, calling exec() in instance of QAxWidget which is instantiated in main loop, it does not work as expected.
When exec() called(_on_event_connect in code), error message showed up like
"QEventLoop:exec: instance 0x18479d8 has already called exec()"
And on the moment of calling exit(), QEventLoop seems not running.
And the application is hang after this.
The below is simplified example of my code, It tries call QAxWidget method "dynamicCall" as soon as log-in process finished.
It consists of pyQt signal/slot mechanism, get event from API server.
Please understand that you can not execute this code because of it needs specific APIs installation and registered user-id.
But I hope you can see the points of problem.
main.py
import sys
from PyQt5.QtWidgets import QApplication
from api import OpenApi
class Main():
def __init__(self):
self.api = OpenApi()
self.api.comm_connect()
# self.api.req_basic_stock_info("035420") -> if I call here, works well
if __name__ == "__main__":
app = QApplication(sys.argv)
main = Main()
sys.exit(app.exec_())
api.py
import sys
from PyQt5.QtWidgets import *
from PyQt5.QAxContainer import *
from PyQt5.QtCore import *
class OpenApi(QAxWidget):
def __init__(self):
super().__init__()
self.setControl("KHOPENAPI.KHOpenAPICtrl.1")
self.OnEventConnect.connect(self._on_event_connect)
self.OnReceiveTrData.connect(self._on_receive_tr_data)
self._qloop = QEventLoop()
def loop(self):
if not self._qloop.isRunning():
logger.info(f"-->exec")
self._qloop.exec()
else:
logger.info("exec skipped")
def unloop(self):
if self._qloop.isRunning():
logger.info("-->exit")
self._qloop.exit()
else:
logger.info(f"exit skipped")
def comm_connect(self):
self.dynamicCall("CommConnect()")
self.loop()
def comm_rq_data(self, rqname, trcode, next, screen_no):
self.dynamicCall("CommRqData(QString, QString, int, QString)", rqname, trcode, next, screen_no)
self.loop()
def _on_event_connect(self, err_code):
if err_code == 0:
logger.info("logged in")
else:
logger.info("log-in failed")
self.unloop()
# If I call this function here, QEventLoop fails
self.req_basic_stock_info("000660")
def _on_receive_tr_data(self, screen_no, rqname, trcode, record_name, next,
unused1, unused2, unused3, unused4):
logger.info(f"OnReceivTrData: {rqname}")
self.unloop()
def req_basic_stock_info(self, code):
# I want to call this function inside instance on certain condition.
self.set_input_value("item", code)
scrno = "2000"
self.comm_rq_data("ITEM_INFO_REQ", "opt10080", "0", scrno)
And output is like below.
12:42:53,54 test INFO -->exec
12:42:58,961 test INFO logged in
12:42:58,962 test INFO -->exit
12:42:58,977 test INFO -->exec
QEventLoop::exec: instance 0x35c34a0 has already called exec()
12:42:59,33 test INFO OnReceivTrData:ITEM_INFO_REQ
12:42:59,35 test INFO exit skipped
As eyllanesc told me, I changed functions related assign/deassign QEventLoop like below. And it works.
def loop(self):
self._qloop = QEventLoop()
self._qloop.exec()
def unloop(self):
try:
self._qloop.exit()
except AttributeError as e:
logger.error(e)
update
I'm afraid this issue has not been solved yet. It was successful when req_basic_stock_info function is called on _on_event_connect event, But I call it at another event function, it hang again without any error message. There is no difference in calling mechanism.
Calling the exit() function does not imply that the QEventLoop can be reused, therefore the error message is signaled. In this case it is better to use a new QEventLoop:
def unloop(self):
if self._qloop.isRunning():
logger.info("-->exit")
self._qloop.exit()
self._qloop = QEventLoop()
else:
logger.info(f"exit skipped")

How to call "process" function using ALAudioDevice "subscribe" method

I'm new at NAO programming and I'm having some trouble regarding the ALAudioDevice API.
My problem is the following one: I wrote a python module that should record raw data from the front microphone.
The documentation of the ALAudioDevice API says that the method "subscribe(...)" calls the function "process" automatically
and regularly with raw data from microphones as inputs. I wrote a code to execute this process (see bellow), and it runs without raising
the error flag. However, the subscribe is bypassing the function "process" and the module doesn't get any audio at all.
Has someone had the same problem?
import qi
class AudioModule(object):
def __init__(self):
super(AudioModule, self).__init__()
self.moduleName = "AudioModule"
try :
self.ALAudioDevice = ALProxy("ALAudioDevice")
except Exception, e:
self.logger.error("Error when creating proxy on ALAudioDevice:")
self.logger.error(e)
def begin_stream(self):
self.ALAudioDevice.setClientPreferences(self.moduleName, 16000, 3, 0)
self.ALAudioDevice.subscribe(self.moduleName)
def end_stream(self):
self.ALAudioDevice.unsubscribe(self.moduleName)
def processRemote( self, nbOfChannels, samplesByChannel, altimestamp, buffer ):
nbOfChannels = nbOfChannels
mylogger = qi.Logger("data")
mylogger.info("It works !" + str(nbOfChannels))
class MyClass(GeneratedClass):
def __init__(self):
GeneratedClass.__init__(self, False)
self.audio = AudioModule()
def onLoad(self):
self.serviceId = self.session().registerService("AudioModule", self.audio)
pass
def onUnload(self):
if self.serviceId != -1:
self.session().unregisterService(self.serviceId)
self.serviceId = -1
pass
def onInput_onStart(self):
self.audio.begin_stream()
self.onInput_onStop()
pass
def onInput_onStop(self):
self.audio.end_stream()
self.onUnload
self.onStopped()
pass
It appears you are subscribing to the audio from a Choregraphe box. I'm not sure it is supposed to work.
But in this configuration the Python code is executed from within the same process as the ALAudioDevice service. So probably you should name your callback "process" instead of "processRemote".
Otherwise, you can still do this from a separate Python script.

Exception that emails stack trace when raised

I'd like to have an exception that always sends an email when raised. As for now, I was planning to put that code into __init():
import sendmail
import configparser
def MailException(BaseException):
"""
sends mail when initiated
"""
def __init__(self, message, config=None):
# Call the base class constructor with the parameters it needs
BaseException.__init__(message)
if config is None:
config = configparser.RawConfigParser()
config.read('mail.ini')
config = config['email']
text = 'exception stack trace + message'
sendmail.sendMail(text=text, config=config['email'], title='Alert')
I'd explicitly like to have the mail-sending here, instead of in every except-block I create. Hence I wonder how to get the stack trace, the code has to be compatible with Python 2.7.
The only thing I could find was traceback, but that apparently only works within the except: realm - or is there a way to implement it within the Exception class? Any other ideas?
Firstly, note that (per the docs) you shouldn't subclass BaseException.
Secondly, rather than implement that logic in the exception itself you could define a new sys.excepthook (see e.g. Python Global Exception Handling), then you get access to the full traceback:
import sys
class MailException(Exception):
pass
def mailing_except_hook(exctype, value, traceback):
if exctype == MailException:
... # do your thing here
else:
sys.__excepthook__(exctype, value, traceback)
sys.excepthook = mailing_except_hook

Paramiko connection issue

I'm writing my first desktop app and I'm struggling with class instances. This app is a simple ftp program using paramiko. What I've set up so far is a connection.py which looks like this...
#connect.py
import user, db
import paramiko, time, os
paramiko.util.log_to_file('paramiko-log.txt')
class Connection:
def __init__(self):
#Call DB Functions
database = db.Database()
#Set Transport
self.transport = paramiko.Transport((user.hostname, user.port))
#User Credentials
username = user.username
password = user.password
self.transport.connect(username = username, password = password)
self.sftp = paramiko.SFTPClient.from_transport(self.transport)
print "Set your credentials in user.py for now!"
msg = "Connecting as: %s, on port number %d" % (user.username, user.port)
print msg
def disconnect(self):
print "Closing connection..."
self.sftp.close()
self.transport.close()
print "Connection closed."
Pretty straightforward. Connect and disconnect.
This connect.py file is being imported into a main.py (which is my gui)
#main.py
import connect
from PySide import QtCore, QtGui
class Window(QtGui.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
windowWidth = 550
windowHeight = 350
self.establishedConnection = ""
connectButton = self.createButton("&Connect", self.conn)
disconnectButton = self.createButton("&Disconnect", self.disconnect)
grid = QtGui.QGridLayout()
grid.addWidget(connectButton, 3, 3)
grid.addWidget(disconnectButton, 4, 3)
grid.addWidget(self.createList(), 1, 0, 1, 4)
self.setLayout(grid)
self.resize(windowWidth, windowHeight)
self.setWindowTitle("FTP Program")
def conn(self):
connection = connect.Connection()
self.establishedConnection = connection
def disconnect(self):
self.establishedConnection.disconnect()
def createButton(self, text, member):
button = QtGui.QPushButton(text)
button.clicked.connect(member)
return button
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
gui = Window()
gui.show()
sys.exit(app.exec_())
The issue is disconnecting.
I was thinking __init__ would create an instance of the Connection() class. If you look on main.py you can see that I tried to create the variable self.connectionEstablished in order to save the object so I could call disconnect on it later.
Where am I going wrong? I'm fairly new to python and other non-web languages(I spend most of my time writing RoR and php apps).
No errors are shown at any time and I started this app out as a terminal app so I do know that connect.py does work as intended.
Edit: So I guess Senderle got a connection closed message, which is what I'd like to see as well but I'm not. I'll mark a best answer if I see something that solves my problem.
Edit Solved: Pushed connect.py and main.py into one file to simplify things. And for some reason that solved things. So who knows whats going on. I'm still going to hold off on 'best answer'. If someone can tell me why I can't have a split file like that then I'm all ears.
I tried the code and it ran fine. I made only a few changes.
First, I didn't know what "user" and "db" are, so I commented out
import user, db
and
database = db.Database()
and used my own data for username, password, etc.
Second, the PySide module isn't available via my package manager, so I used PyQt4 instead. It didn't like grid.addWidget(self.createList(), 1, 0, 1, 4) so I commented that out, and everything worked as expected.
Further thoughts: When there were connection errors, there was some console feedback consisting of stack traces, but nothing more, and self.establishedConnection remained a string, causing self.establishedConnection.disconnect() to fail. So perhaps there's a connection problem?
EDIT: Aaaahhhhh, I just saw this: "No errors are shown at any time." Are you running this from a terminal or double-clicking an executable? If you start it from a terminal, I bet you'll see stacktraces in the terminal. The gui doesn't close when the code hits an exception.
EDIT2: If joining the files fixes the problem, then I am certain the problem cannot have anything to do with python itself. This has to be a problem with eclipse. You say that connection.py began as a terminal app, so you must be able to run python apps from the command line. Try the following: put main.py, connect.py, etc. in a directory of their own, open a terminal, and run python main.py. If it works as expected, then the problem has something to do with eclipse.
You are not calling conn() in the constructor.

Categories

Resources