问题描述
使用elevate模块中的elevate()函数时,kivy无法启动。代码的相关部分如下:
from elevate import elevate
from os import environ
environ['disPLAY'] = ':0'
environ['KIVY_WINDOW'] = 'sdl2'
elevate()
稍后,我给出了一个kivy应用程序的代码并尝试运行它。这样做时,我收到以下错误:
[INFO ] [Logger ] Record log in /root/.kivy/logs/kivy_20-10-04_91.txt
[INFO ] [Kivy ] v2.0.0rc3,git-20c14b2,20200615
[INFO ] [Kivy ] Installed at "/usr/local/lib/python3.8/dist-packages/Kivy-2.0.0rc3-py3.8-linux-x86_64.egg/kivy/__init__.py"
[INFO ] [Python ] v3.8.5 (default,Aug 2 2020,15:09:07)
[GCC 10.2.0]
[INFO ] [Python ] Interpreter at "/usr/bin/python3"
[INFO ] [Factory ] 185 symbols loaded
[INFO ] [Image ] Providers: img_tex,img_dds,img_sdl2,img_pil (img_ffpyplayer,img_gif ignored)
[INFO ] [KivyMD ] 0.104.2.dev0,git-f0a8217,2020-09-27 (installed at "/usr/local/lib/python3.8/dist-packages/kivymd-0.104.2.dev0-py3.8.egg/kivymd/__init__.py")
[INFO ] [Text ] Provider: sdl2
[INFO ] [Window ] Provider: sdl2
No protocol specified
[CRITICAL] [Window ] Unable to find any valuable Window provider. Please enable debug logging (e.g. add -d if running from the command line,or change the log level in the config) and re-run your app to identify potential causes
sdl2 - RuntimeError: b'No available video device'
File "/usr/local/lib/python3.8/dist-packages/Kivy-2.0.0rc3-py3.8-linux-x86_64.egg/kivy/core/__init__.py",line 70,in core_select_lib
cls = cls()
File "/usr/local/lib/python3.8/dist-packages/Kivy-2.0.0rc3-py3.8-linux-x86_64.egg/kivy/core/window/window_sdl2.py",line 152,in __init__
super(WindowSDL,self).__init__()
File "/usr/local/lib/python3.8/dist-packages/Kivy-2.0.0rc3-py3.8-linux-x86_64.egg/kivy/core/window/__init__.py",line 982,in __init__
self.create_window()
File "/usr/local/lib/python3.8/dist-packages/Kivy-2.0.0rc3-py3.8-linux-x86_64.egg/kivy/core/window/window_sdl2.py",line 287,in create_window
self.system_size = _size = self._win.setup_window(
File "kivy/core/window/_window_sdl2.pyx",line 112,in kivy.core.window._window_sdl2._WindowSDL2Storage.setup_window
File "kivy/core/window/_window_sdl2.pyx",line 74,in kivy.core.window._window_sdl2._WindowSDL2Storage.die
[CRITICAL] [App ] Unable to get a Window,abort.
我该如何解决?我尝试设置environ['disPLAY'] = '*:0'
,但收到相同的错误,除非没有“未找到协议”。请注意,这是一个必须在比我自己的机器更多的机器上运行的应用程序,因此我需要可以在代码中放入一个修复程序,而不是使用bash一次执行命令。
我还应该提到,当我运行sudo python3 main.py
时,该应用程序可以正常运行。只有当我使用python3 main.py
(这会导致elevate()
函数以登录提示我)时,我才会收到此错误。
解决方法
失败的原因是切换到root之后,未设置DISPLAY
和XAUTHORITY
环境变量。您可以设置这些来解决该问题。这是一个可以做到这一点的示例:
def is_root():
return os.getuid() == 0
file_name = os.path.join(gettempdir(),'f.txt')
if not is_root():
print('saving DISPLAY:',os.environ['DISPLAY'])
print('saving XAUTHORITY:',os.environ['XAUTHORITY'])
with open(file_name,mode='w') as f:
f.write(os.environ['DISPLAY'] + ' ' + os.environ['XAUTHORITY'])
else:
with open(file_name) as f:
txt = f.readline()
tokens = txt.split()
os.environ['DISPLAY'] = tokens[0]
os.environ['XAUTHORITY'] = tokens[1]
print('restored DISPLAY:',os.environ['DISPLAY'])
print('rstored XAUTHORITY:',os.environ['XAUTHORITY'])
os.remove(file_name)
这仅仅是概念的证明。您应该考虑安全性和file_name
的选择。显然,这仅适用于posix
系统,不适用于Windows。我考虑过尝试使用python tempfile
模块,但是我相信所有写入的tempfile
在您有机会阅读之前都会被删除。我还没有测试过。