I'd like to add an action to my Notification with a callback. I'm using pygobject with the following code:
import logging
from time import sleep
import gi
gi.require_version('Notify', '0.7')
from gi.repository import Notify
def callback(*args, **kwargs):
print("Got callback")
print(locals())
def main():
Notify.init("Hello World")
notification = Notify.Notification.new("Testing")
notification.add_action("my action", "Submit", callback)
notification.show()
sleep(5)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
main()
When I run the script, I see the notification with the "Submit" button, but when I click the button the callback isn't run (as far as I can tell).
When I use ipython to inspect things, I get this help for add_action:
In [65]: Notify.Notification.add_action?
Type: FunctionInfo
String form: gi.FunctionInfo(add_action)
File: /usr/lib/python3.5/site-packages/gi/__init__.py
Docstring: add_action(self, action:str, label:str, callback:Notify.ActionCallback, user_data=None)
So I see that the callback should be an ActionCallback? I then inspect that class:
In [67]: Notify.ActionCallback
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<ipython-input-67-aa40d4997598> in <module>()
----> 1 Notify.ActionCallback
/usr/lib/python3.5/site-packages/gi/module.py in __getattr__(self, name)
231 wrapper = info.get_value()
232 else:
--> 233 raise NotImplementedError(info)
234
235 # Cache the newly created wrapper which will then be
NotImplementedError: gi.CallbackInfo(ActionCallback)
...and I get a NotImplementedError. So are notification actions just not implemented in PyGObject? Or am I doing something wrong in passing my callback to the add_action method?
I'm on arch linux, using the package python-gobject 3.22.0-1, running with python 3.5.2.
It turns out I needed to run the Gtk main loop:
from gi.repository import Gtk
Gtk.main()
Then the callback was called just fine
Related
I've been following this amazing (video) tutorial to create custom user defined GDB command using python
here is my code
import os
import gdb
class BugReport (gdb.Command):
"""Collect required info for a bug report"""
def __init__(self):
super(BugReport, self).__init__("bugreport", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
pagination = gdb.parameter("pagination")
if pagination: gdb.execute("set pagination off")
f = open("/tmp/bugreport.txt", "w")
f.write(gdb.execute("thread apply all backtrace full", to_string=True))
f.close()
os.system("uname -a >> /tmp/bugreport.txt")
if pagination: gdb.execute("set pagination on")
BugReport()
but when I try to source this code inside gdb I get following error:
(gdb) source mybugreport.py
Traceback (most recent call last):
File "mybugreport.py", line 19, in <module>
BugReport()
TypeError: function missing required argument 'name' (pos 1)
what I'm doing wrong?
what I'm doing wrong?
Python is indentation-sensitive. You want:
class BugReport (gdb.Command):
"""Collect required info for a bug report"""
def __init__(self):
super(BugReport, self).__init__("bugreport", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
pagination = gdb.parameter("pagination")
...
BugReport()
My PyQt application no longer prints the error (stderr?) to the console.
I use QtDesigner and import the UI like this:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from PyQt5.uic import loadUiType
Ui_MainWindow, QMainWindow = loadUiType("test.ui")
class Main(QMainWindow, Ui_MainWindow):
"""Main window"""
def __init__(self,parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.testfunc)
def testfunc(self):
print(9/0)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
test.ui contains a QPushButton and a label. When I call testfunc (which obviously gives an error) in a non-Qt application, I get the error message, traceback, etc. When I execute this code, it just exits.
I wrote a PyQt application without QtDesigner before and it printed the errors to the console as expected. What's the difference with QtDesigner and inheritance?
This is probably due to changes in the way exceptions are dealt with in PyQt-5.5. To quote from the PyQt5 Docs:
In PyQt v5.5 an unhandled Python exception will result in a call to
Qt’s qFatal() function. By default this will call abort() and the
application will terminate. Note that an application installed
exception hook will still take precedence.
When I run your example in a normal console, this is what I see:
$ python test.py
Traceback (most recent call last):
File "test.py", line 213, in testfunc
print(9/0)
ZeroDivisionError: division by zero
Aborted (core dumped)
So the main difference is that the application will now immediately abort when encountering an unhandled exception (i.e. just like a normal python script would). Of course, you can still control this behaviour by using a try/except block or globally by overriding sys.excepthook.
If you're not seeing any traceback, this may be due to an issue with the Python IDE you're using to run your application.
PS:
As a bare minimum, the old PyQt4 behaviour of simply printing the traceback to stdout/stderr can be restored like this:
def except_hook(cls, exception, traceback):
sys.__excepthook__(cls, exception, traceback)
if __name__ == "__main__":
import sys
sys.excepthook = except_hook
I've been using python's traceback module in conjunction with a try/except statement to make sure the traceback is printed before exiting:
https://docs.python.org/3/library/traceback.html
Spefically, I use traceback.print_exc()
This is my first attempt at using the Tkinter plugin, I know very little past what tutorials I could find. All the answers I've seen so far put a class inside the py file that your building, I however have a plethora of tests that are already compiled into a Test class that runs many separate tests. All the tests run and no errors are encountered before trying to add to the ui.
I would like to be able to run each suite by clicking a button. My problem seems that I'm missing a step some where but not getting any errors or action when I click the button, but an error after I click and close the ui window. I should point out that importing the settings file (which contains most of the webdriver imports) does not help either. I get the same error.
Traceback:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python37\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Python37\lib\unittest\case.py", line 663, in __call__
return self.run(*args, **kwds)
File "C:\Python37\lib\unittest\case.py", line 590, in run
testMethod = getattr(self, self._testMethodName)
AttributeError: 'Test' object has no attribute 'runTest'
My ui code:
import sys, os, tkinter, TESTadmin
top = tkinter.Tk()
a = TESTadmin.Test()
B = tkinter.Button(top, text= "Test Window", command=a )
B.pack()
top.mainloop()
for clarity my main test file:
from helpers.settings import *
from pieces import adminLogin, adminLogout, docs
class Test(unittest.TestCase):
def setUp(self):
# Maximize Window (remove quotes to use)
'''sel.maximize_window()'''
self.browser = webdriver.Firefox()
self.browser.get("https://mywebsite.net")
# We instantiate and start the browser
def testCases(self):# Add Tests Below
#log in to admin side
login = adminLogin.AdminLogin.do(self)
#docs page
docpage = docs.Docs.do(self)
#log out
logout = adminLogout.Logout.do(self)
if G.log:
for k in G.log.items():
print(k)
### Uncomment to close browser after test ###
def tearDown(self):
self.browser.close()
if __name__ == "__main__":
unittest.main()
As it would turn out, the answer like I thought is simple.
this line :
def testCases(self):
needs to read:
def runTest(self):
after that change every thing works percectly.
My confusion is because originally when building these tests I was following the directions here -> https://selenium-python.readthedocs.io/
They show you to use the testCases() method, and this works! Just not for calling the class. I didn't know where to put the function let alone know that Webdriver had a built in function other than what i was using.
How can I check errors in my code using NVDA error log? I've created an addon, which seemingly doesn't works due to some error. How can I debug my code using error log or any other method possible?
The error I'm facing is in the following code:
import globalPluginHandler
import ui
import versionInfo
from NVDAObjects.window.scintilla import Scintilla
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
def _messag(self, gesture):
ui.message("notepad++ opened") # speak hello when notepad++ is the current screen
def chooseNVDAObjectOverlayClasses(self, obj, clsList):
if obj.windowClassName == u'Scintilla' and obj.windowControlID == 0:
clsList.insert(0, self._messag)
I don't know anything about NVDA, but when python programs fail, they do it by raising an exception. You could perhaps include a mechanism to catch these exceptions and send them to a file. For example let's take a plugin from the NVDA developer's guide
--- start ---
# Version announcement plugin for NVDA
# Developer guide example 2
import globalPluginHandler
import ui
import versionInfo
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
#MY_EXCEPTION_CATCHER
def script_announceNVDAVersion(self, gesture):
ui.message(versionInfo.version)
__gestures={
"kb:NVDA+shift+v": "announceNVDAVersion",
}
--- end ---
I added a decorator to the code that catches the exceptions that may occur and displays them in an html file that can be displayed in browser for example
import functools
import cgitb
import sys
def MY_EXCEPTION_CATCHER(func):
#functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception:
with open('exception.html', 'w') as outfile:
outfile.write(cgitb.html(sys.exc_info())
raise
return wrapper
I hope it helps.
I have a problem with python and dbus. I checked out the developer docs and specifications, but I don't understand how to set up a main loop. I want to listen for notification events.
See
http://dbus.freedesktop.org/doc/dbus-python/doc/
and
http://www.galago-project.org/specs/notification/0.9/index.html
My example script:
import dbus
from dbus.mainloop.glib import DBusGMainLoop
class MessageListener:
def __init__(self):
DBusGMainLoop(set_as_default=True)
self.bus = dbus.SessionBus()
self.proxy = self.bus.get_object('org.freedesktop.Notifications',
'/org/freedesktop/Notifications')
self.proxy.connect_to_signal('NotificationClosed',
self.handle_notification)
def handle_notification(self, *args, **kwargs):
print args, kwargs
if __name__ == '__main__':
MessageListener()
DBusGMainLoop has no further methods like run().
If I use a loop from gobject and change the sourcecode:
import gobject
loop = gobject.MainLoop()
dbus.set_default_main_loop(loop)
...
loop.run()
I get following error message:
Traceback (most recent call last):
File "dbus_example.py", line 40, in <module>
MessageListener()
File "dbus_example.py", line 9, in __init__
dbus.set_default_main_loop(loop)
TypeError: A dbus.mainloop.NativeMainLoop instance is required
Any idea what to do about it?
Thanks in advance.
phineas
Put import gobject at the top of your code, and after instantiating your object, do gobject.MainLoop().run(). I think that the MainLoop has to be created after the DBusGMainLoop is created.
I had the same problem. After getting my code to work, I came across this question.
Dan's answer is partially correct. You import gobject first, but you can also instantiate your MainLoop before the DBusGMainLoop is created. You should run it after the DBusGMainLoop is created.