2

我有一个 Python 3 脚本,它从 URL 获取一些 JSON,对其进行处理,并在我获得的数据有任何重大变化时通知我。我已经尝试使用notify2PyGObject的 libnotify 绑定(gi.repository.Notify)并使用任何一种方法都获得了类似的结果。当我从终端运行它时,这个脚本可以正常工作,但是当 cron 尝试运行它时会阻塞。

import notify2
from gi.repository import Notify

def notify_pygobject(new_stuff):
    Notify.init('My App')
    notify_str = '\n'.join(new_stuff)
    print(notify_str)
    popup = Notify.Notification.new('Hey! Listen!', notify_str,
                                    'dialog-information')
    popup.show()

def notify_notify2(new_stuff):
    notify2.init('My App')
    notify_str = '\n'.join(new_stuff)
    print(notify_str)
    popup = notify2.Notification('Hey! Listen!', notify_str,
                                 'dialog-information')
    popup.show()

现在,如果我创建一个使用字符串列表调用的脚本notify_pygobject,cron 会通过邮件假脱机向我抛出此错误:

Traceback (most recent call last):
  File "/home/p0lar_bear/Documents/devel/notify-test/test1.py", line 3, in <module>
    main()
  File "/home/p0lar_bear/Documents/devel/notify-test/test1.py", line 4, in main
    testlib.notify(notify_projects)
  File "/home/p0lar_bear/Documents/devel/notify-test/testlib.py", line 8, in notify
    popup.show()
  File "/usr/lib/python3/dist-packages/gi/types.py", line 113, in function
    return info.invoke(*args, **kwargs)
gi._glib.GError: Error spawning command line `dbus-launch --autolaunch=776643a88e264621544719c3519b8310 --binary-syntax --close-stderr': Child process exited with code 1

...如果我将其更改为调用notify_notify2()

Traceback (most recent call last):
  File "/home/p0lar_bear/Documents/devel/notify-test/test2.py", line 3, in <module>
    main()
  File "/home/p0lar_bear/Documents/devel/notify-test/test2.py", line 4, in main
    testlib.notify(notify_projects)
  File "/home/p0lar_bear/Documents/devel/notify-test/testlib.py", line 13, in notify
    notify2.init('My App')
  File "/usr/lib/python3/dist-packages/notify2.py", line 93, in init
    bus = dbus.SessionBus(mainloop=mainloop)
  File "/usr/lib/python3/dist-packages/dbus/_dbus.py", line 211, in __new__
    mainloop=mainloop)
  File "/usr/lib/python3/dist-packages/dbus/_dbus.py", line 100, in __new__
    bus = BusConnection.__new__(subclass, bus_type, mainloop=mainloop)
  File "/usr/lib/python3/dist-packages/dbus/bus.py", line 122, in __new__
    bus = cls._new_for_bus(address_or_type, mainloop=mainloop)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NotSupported: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11

我做了一些研究并看到了将 aPATH=放入我的 crontab 或导出的建议$DISPLAY(我通过调用在脚本中执行此操作os.system('export DISPLAY=:0')),但都没有导致任何更改......

4

3 回答 3

6

你在正确的轨道上。这种行为是因为 cron 在多用户无头环境中运行(认为它在没有 GUI 的终端中以 root 身份运行,有点),所以他不知道要显示什么(X Window Server 会话)和用户目标。如果您的应用程序打开,例如,打开某些用户桌面的窗口或通知,则会引发此问题。

我想你编辑你的 croncrontab -e并且条目看起来像这样:

m h dom mon dow command

就像是:

0 5 * * 1 /usr/bin/python /home/foo/myscript.py

请注意,我使用 Python 的完整路径,如果这种 PATH 环境变量可能不同的情况会更好。

然后只需更改为:

0 5 * * 1 export DISPLAY=:0 && /usr/bin/python /home/foo/myscript.py

如果这仍然不起作用,您需要允许您的用户控制 X Windows 服务器:

添加到您的.bash_rc

xhost +si:localuser:$(whoami)

于 2013-06-24T18:04:33.570 回答
3

如果你想在 python 中设置 DISPLAY 就像你尝试的那样os.system('export DISPLAY=:0'),你可以做这样的事情

import os

if not 'DISPLAY' in os.environ:
    os.environ['DISPLAY'] = ':0'

这将尊重用户在多座包厢上可能拥有的任何 DISPLAY,并回退到主头:0。

于 2013-08-01T16:02:56.423 回答
0

如果您的通知函数,无论 Python 版本或通知库如何,都不会跟踪通知 id [在 Python 列表中] 并在队列完全满或出错之前删除最旧的,然后取决于 dbus 设置(在 Ubuntu 中为 21 notification max) dbus 将抛出错误,已达到最大通知!

from gi.repository import Notify
from gi.repository.GLib import GError

# Normally implemented as class variables.  
DBUS_NOTIFICATION_MAX = 21
lstNotify = []

def notify_show(strSummary, strBody, strIcon="dialog-information"):
    try:
        # full queue, delete oldest 
        if len(lstNotify)==DBUS_NOTIFICATION_MAX:
            #Get oldest id
            lngOldID = lstNotify.pop(0)
            Notify.Notification.clear(lngOldID)
            del lngOldID
            if len(lstNotify)==0:
                 lngLastID = 0
            else:
                lngLastID = lstNotify[len(lstNotify) -1] + 1
                lstNotify.append(lngLastID)
                notify = Notify.Notification.new(strSummary, strBody, strIcon)
                notify.set_property('id', lngLastID)
                print("notify_show id %(id)d " % {'id': notify.props.id} )
                #notify.set_urgency(Notify.URGENCY_LOW)
                notify.show()
    except GError as e:
        # Most likely exceeded max notifications
        print("notify_show error ", e )
    finally:
        if notify is not None:
            del notify

尽管有可能以某种方式询问 dbus 通知队列的最大限制是多少。也许有人可以提供帮助......改进这个直到完美。

因为 gi.repository 完整的答案是多余的。

于 2014-11-25T02:36:20.970 回答