PyQt4: прерванный системный вызов при вызове commands.getoutput () в таймере - PullRequest
1 голос
/ 14 октября 2011

Проблема оказалась очень простой, но я не могу найти никакого решения после дня поиска в Google и изучения stackoverflow.Первоначально я разрабатывал простой плазмоид, который будет отправлять определенный запрос на локальный веб-сервер каждые 30 минут, анализировать вывод и отображаться в метке на панели.Я взял пример плазмоида - BWC-Balance - и модифицировал его.Вот код:

#!/usr/bin/env python
# coding: utf-8

"""
BWC Balance plasmoid

Site: http://bitbucket.org/svartalf/bwc-balance-plasmoid/

Author: SvartalF (http://svartalf.info)
Original idea: m0nochr0me (http://m0nochr0me.blogspot.com)
"""
import re
from urllib import urlencode
import urllib2
import cookielib
import datetime
import sys
import re
import string
import os
import gobject
import commands

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyKDE4.kio import *
from PyKDE4.kdeui import *
from PyKDE4.kdecore import *
from PyKDE4.plasma import Plasma
from PyKDE4 import plasmascript
from PyKDE4.solid import Solid

from settings import SettingsDialog

parsed_ok = 0
curr_day = ''

class BWCBalancePlasmoid(plasmascript.Applet):
    """Applet main class"""

    def __init__(self, parent, args=None):
        plasmascript.Applet.__init__(self, parent)

    def init(self):
        """Applet settings"""

        self.setHasConfigurationInterface(True)
        self.setAspectRatioMode(Plasma.Square)

        self.theme = Plasma.Svg(self)
#       self.theme.setImagePath("widgets/background")
#       self.setBackgroundHints(Plasma.Applet.DefaultBackground)

        self.layout = QGraphicsLinearLayout(Qt.Horizontal, self.applet)

        # Main label with balance value
        self.label = Plasma.Label(self.applet)
        self.label.setText(u'<b><font color=blue size=3>No data...</font></b>')

        self.layout.addItem(self.label)
        self.applet.setLayout(self.layout)
        self.resize(350, 30)

        self.startTimer(2500)

    def postInit(self):
        """Start timer and do first data fetching

        Fired only if user opened access to KWallet"""

        self.setLabelText()

    def update(self, value):
        """Update label text"""

        self.label.setText(value)

    def timerEvent(self, event):
        """Create thread by timer"""

        self.setLabelText()
        pass

    def setLabelText(self):
        login = 'mylogin'

        request = 'curl --ntlm -sn http://some.local.resource'

        out_exp = ""
        out_exp = commands.getoutput(request)

        table_name_exp = re.findall(r"some_regular_expression",out_exp)

        tp =  '| html2text | grep -i -A3 ' + login


        out_exp = ''
        try:
            cmd_exp = 'curl --ntlm -sn ' + table_name_exp[0] + ' ' + tp
            out_exp = commands.getoutput(cmd_exp)
        except:
            cmd_exp = ''

        date_check = re.findall(r"one_more_regular_expression", out_exp)

        times_exp  = re.findall(r"[0-9][0-9]:[0-9][0-9]", out_exp )
        if len(times_exp) != 0 and len(date_check) != 0:
            self.label.setText(u'<b><font color=blue size=3>Start: ' + times_exp[0] + u' --- Finish: ' + str(int(string.split(times_exp[0], ':')[0]) + 9) + ':' + string.split(times_exp[0], ':')[1] + ' </span></b>')
        else:
            self.label.setText(u'<b><font color=blue size=3>No data...</span></b>')

def CreateApplet(parent):
    return BWCBalancePlasmoid(parent)

И что я получаю, это следующая ошибка:

# plasmoidviewer bwc-balance

plasmoidviewer(25255)/kdecore (services) KServiceFactory::findServiceByDesktopPath: "" not found
plasmoidviewer(25255)/libplasma Plasma::FrameSvg::resizeFrame: Invalid size QSizeF(0, 0) 
plasmoidviewer(25255)/libplasma Plasma::FrameSvg::resizeFrame: Invalid size QSizeF(0, 0) 

Traceback (most recent call last):
  File "/home/grekhov/.kde/share/apps/plasma/plasmoids/bwc-balance/contents/code/main.py", line 116, in timerEvent
    self.setLabelText()
  File "/home/grekhov/.kde/share/apps/plasma/plasmoids/bwc-balance/contents/code/main.py", line 146, in setLabelText
    out_exp = commands.getoutput(request)
  File "/usr/lib/python2.7/commands.py", line 50, in getoutput
    return getstatusoutput(cmd)[1]
  File "/usr/lib/python2.7/commands.py", line 60, in getstatusoutput
    text = pipe.read()
IOError: [Errno 4] Interrupted system call

Как я понял после нескольких часов поиска в Google: чтение из канала прерывается каким-то сигналом.Но единственный сигнал, который у меня есть, это таймер.Единственная рекомендация, которую я нашел, это «избавиться от сигнала, который прерывает ваше чтение».И это кажется немного странным и нереальным для меня: читать данные периодически без таймера.Я что-то пропустил?Может быть, нужно использовать какой-то другой механизм доступа к веб-ресурсу и анализа его вывода?Или «Прерванный системный вызов» - это нормальная ситуация, и ее нужно как-то обрабатывать?

Заранее спасибо за помощь.

1 Ответ

1 голос
/ 14 октября 2011

Похоже, что сигнал доставляется, пока канал все еще читает.

Поэтому попробуйте остановить таймер перед вызовом setLabelText(), а затем снова запустить его.

EDIT

Вам также следует попробовать переписать свой код, чтобы использовать subprocess вместо устаревшего commands модуля.Например:

pipe = subprocess.Popen(['curl', '--ntlm', '-sn', 
                         'http://some.local.resource'],
                         stdout=subprocess.PIPE)
output = pipe.communicate()[0]
...