python - Why don't the signals emit? -


the application

i'm trying build python shell pyqt5 application using stdlib interactiveconsole can let users script live plots. i'm using qtextedit display stdout shell.

the problem

when loops in shell, application freezes because insertplaintext() qtextedit fast. wrote buffer delay inserts few milliseconds. however, noticed ran blocking functions time.sleep() in loops, freeze. prints inside loops displayed after loop done. not happen if buffer disabled.

for eg, if in shell:

>>>for in range(10): ...    time.sleep(1) ...    print(i) ... 

this print after 10 seconds.

code

this minimal version write according mvce guidelines.

here main.ui file:

<?xml version="1.0" encoding="utf-8"?> <ui version="4.0">  <class>main_window</class>  <widget class="qmainwindow" name="main_window">   <property name="geometry">    <rect>     <x>0</x>     <y>0</y>     <width>800</width>     <height>600</height>    </rect>   </property>   <property name="sizepolicy">    <sizepolicy hsizetype="preferred" vsizetype="preferred">     <horstretch>0</horstretch>     <verstretch>0</verstretch>    </sizepolicy>   </property>   <property name="windowtitle">    <string>mainwindow</string>   </property>   <property name="tabshape">    <enum>qtabwidget::rounded</enum>   </property>   <widget class="qwidget" name="central_widget">    <layout class="qhboxlayout" name="horizontallayout">     <item>      <layout class="qvboxlayout" name="console_layout">       <item>        <widget class="qtextedit" name="console_log">         <property name="undoredoenabled">          <bool>false</bool>         </property>        </widget>       </item>       <item>        <layout class="qhboxlayout" name="horizontallayout_4">         <item>          <widget class="qlabel" name="console_prompt">           <property name="text">            <string/>           </property>          </widget>         </item>         <item>          <widget class="qlineedit" name="console_input">           <property name="frame">            <bool>true</bool>           </property>          </widget>         </item>        </layout>       </item>      </layout>     </item>    </layout>   </widget>   <widget class="qmenubar" name="menu_bar">    <property name="geometry">     <rect>      <x>0</x>      <y>0</y>      <width>800</width>      <height>26</height>     </rect>    </property>   </widget>   <widget class="qstatusbar" name="status_bar"/>  </widget>  <resources/>  <connections/> </ui> 

here themain.py file:

import sys code import interactiveconsole io import stringio queue import queue, empty  pyqt5 import uic pyqt5.qtcore import pyqtslot, qthread, qobject, pyqtsignal, qtimer pyqt5.qtgui import qtextoption, qtextcursor pyqt5.qtwidgets import qapplication  __author__ = "daegontaven" __copyright__ = "daegontaven" __license__ = "gpl3"   class basesignals(qobject):     """     standard set of pyqtsignals.     """     signal_str = pyqtsignal(str)     signal_int = pyqtsignal(int)     signal_float = pyqtsignal(float)     signal_list = pyqtsignal(list)     signal_tuple = pyqtsignal(tuple)     signal_dict = pyqtsignal(dict)     signal_object = pyqtsignal(object)      def __init__(self):         qobject.__init__(self)   class delayedbuffer(qobject):     """     buffer uses queue store strings. removes     first appended string first in constant interval.     """     written = pyqtsignal(str)      def __init__(self, output, delay):         """         :param output: used access basesignals         :param delay: delay emitting         """         super().__init__()         self.output = output          # set delay         self.delay = delay         self.queue = queue()         self.timer = qtimer()         self.timer.timeout.connect(self.process)         self.timer.start(self.delay)      def write(self, string):         self.queue.put(string)      def process(self):         """         try send data stream         """         try:             data = self.queue.get(block=false)             self.written.emit(data)         except empty:             pass      def emit(self, string):         """         force emit of string.         """         self.output.signal_str.emit(string)   class consolestream(stringio):     """     custom streamio class emits signal on each write.     """     def __init__(self, enabled=true, *args, **kwargs):         """         starts delayed buffer store writes due ui         refresh limitations.          :param enabled: set false bypass buffer         """         stringio.__init__(self, *args, **kwargs)         self.enabled = enabled         self.output = basesignals()          # buffer         self.thread = qthread()         self.buffer = delayedbuffer(self.output, delay=5)         self.buffer.movetothread(self.thread)         self.buffer.written.connect(self.get)         self.thread.start()      def write(self, string):         """         overrides parent write method , emits signal         meant received interpreters.          :param string: single write output stdout         """         if self.enabled:             self.buffer.write(string)         else:             self.output.signal_str.emit(string)      def get(self, string):         self.output.signal_str.emit(string)   class pythoninterpreter(qobject, interactiveconsole):     """     reimplementation of builtin interactiveconsole     work threads.     """     output = pyqtsignal(str)     push_command = pyqtsignal(str)     multi_line = pyqtsignal(bool)      def __init__(self):         qobject.__init__(self)         self.l = {}         interactiveconsole.__init__(self, self.l)         self.stream = consolestream()         self.stream.output.signal_str.connect(self.console)         self.push_command.connect(self.command)      def write(self, string):         self.output.emit(string)      def runcode(self, code):         """         overrides , captures stdout , stdin         interactiveconsole.         """         sys.stdout = self.stream         sys.stderr = self.stream         sys.excepthook = sys.__excepthook__         result = interactiveconsole.runcode(self, code)         sys.stdout = sys.__stdout__         sys.stderr = sys.__stderr__         return result      @pyqtslot(str)     def command(self, command):         """         :param command: line retrieved console_input on                         returnpressed         """         result = self.push(command)         self.multi_line.emit(result)      @pyqtslot(str)     def console(self, string):         """         :param string: processed output stream         """         self.output.emit(string)   class mainwindow:     """     main gui window. opens maximized.     """     def __init__(self):          self.ui = uic.loadui("main.ui")         self.ui.showmaximized()          # console properties         self.ui.console_log.document().setmaximumblockcount(1000)         self.ui.console_log.setwordwrapmode(qtextoption.wrapanywhere)          self.ps1 = '>>>'         self.ps2 = '...'         self.ui.console_prompt.settext(self.ps1)          # spawn interpreter         self.thread = qthread()         self.thread.start()          self.interpreter = pythoninterpreter()         self.interpreter.movetothread(self.thread)          # interpreter signals         self.ui.console_input.returnpressed.connect(self.send_console_input)         self.interpreter.output.connect(self.send_console_log)         self.interpreter.multi_line.connect(self.prompt)      def prompt(self, multi_line):         """         sets prompt use.         """         if multi_line:             self.ui.console_prompt.settext(self.ps2)         else:             self.ui.console_prompt.settext(self.ps1)      def send_console_input(self):         """         send input grabbed qlineedit prompt console.         """         command = self.ui.console_input.text()         self.ui.console_input.clear()         self.interpreter.push_command.emit(str(command))      def send_console_log(self, command):         """         set output interactiveconsole in qtextedit.         auto scroll scrollbar.         """         # checks if scrolled         old_cursor = self.ui.console_log.textcursor()         old_scrollbar = self.ui.console_log.verticalscrollbar().value()         new_scrollbar = self.ui.console_log.verticalscrollbar().maximum()         if old_scrollbar == new_scrollbar:             scrolled = true         else:             scrolled = false          # sets text         self.ui.console_log.insertplaintext(command)          # scrolls/moves cursor based on available data         if old_cursor.hasselection() or not scrolled:             self.ui.console_log.settextcursor(old_cursor)             self.ui.console_log.verticalscrollbar().setvalue(old_scrollbar)         else:             self.ui.console_log.movecursor(qtextcursor.end)             self.ui.console_log.verticalscrollbar().setvalue(                 self.ui.console_log.verticalscrollbar().maximum()             )   def main():     app = qapplication(sys.argv)     window = mainwindow()     sys.exit(app.exec_())  if __name__ == "__main__":     main() 

the class basesignals needed communication between main thread , interpreter. here transcript why implemented.

what know

this line responsible inserting plain text self.output.signal_str.emit(data). emit() happens inside qthread. until multiple self.buffer.write() finished emit() won't processed. thought adding qapplication.processevents() in delayedbuffer.process() help. doesn't. admit wrong this.

any appreciated. in advance.

your interpreter thread blocking on interactiveconsole.runcode() call. not able process signals until call completes. why see delayed output.

you can effect you're after changing

self.interpreter.output.connect(self.send_console_log) 

to

self.interpreter.stream.output.signal_str.connect(self.send_console_log) 

for old school debugging, disconnect you're stderr handling , sprinkle print statements around like...

print('runcode after', file=sys.stderr) 

Comments

Popular posts from this blog

ubuntu - PHP script to find files of certain extensions in a directory, returns populated array when run in browser, but empty array when run from terminal -

php - How can i create a user dashboard -

javascript - How to detect toggling of the fullscreen-toolbar in jQuery Mobile? -