Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronization mechanism for non-POSIX #15

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions gnuplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,16 @@ class gnuplotlib has a separate gnuplot process and a plot window. If multiple
import numpy as np
import numpysane as nps

from threading import Thread
from queue import Queue, Empty

ON_POSIX = 'posix' in sys.builtin_module_names

def enqueue_output(out, queue):
while True:
result = out.read(1).decode()
queue.put(result)

# setup.py assumes the version is a simple string in '' quotes
__version__ = '0.31'

Expand Down Expand Up @@ -1281,6 +1291,8 @@ def __init__(self, **plotOptions):
self._logEvent("_startgnuplot() finished")




def _startgnuplot(self):

self._logEvent("_startgnuplot()")
Expand Down Expand Up @@ -1311,7 +1323,7 @@ def _startgnuplot(self):
# I need this to make fdDupSTDOUT available to the
# child gnuplot. close_fds=False was default in
# python2, but was changed in python3
close_fds = False,
close_fds = ON_POSIX,

# This was helpful in python3 to implicitly
# encode() strings, but it broke the
Expand All @@ -1329,6 +1341,11 @@ def _startgnuplot(self):
#encoding = 'utf-8',
)

# Handle stderr sync crossplatform
self.stderr_queue = Queue()
self.stderr_thread = Thread(target=enqueue_output, args=(self.gnuplotProcess.stderr, self.stderr_queue))
self.stderr_thread.daemon = True
self.stderr_thread.start()
# What is the default terminal?
self._printGnuplotPipe( "show terminal\n" )
errorMessage, warnings = self._checkpoint('printwarnings')
Expand Down Expand Up @@ -1491,24 +1508,27 @@ def _checkpoint(self, flags=''):

self._logEvent("Trying to read from gnuplot")

rlist,wlist,xlist = select.select([self.gnuplotProcess.stderr],[], [],
None if waitforever else 15)
# rlist,wlist,xlist = select.select([self.gnuplotProcess.stderr],[], [],
# None if waitforever else 15)

if rlist:
try:
byte = self.stderr_queue.get(timeout=None if waitforever else 15)
# if rlist:
# read a byte. I'd like to read "as many bytes as are
# available", but I don't know how to this in a very portable
# way (I just know there will be windows users complaining if I
# simply do a non-blocking read). Very little data will be
# coming in anyway, so doing this a byte at a time is an
# irrelevant inefficiency
byte = self.gnuplotProcess.stderr.read(1).decode()
# byte = self.gnuplotProcess.stderr.read(1).decode()
fromerr += byte
if byte is not None and len(byte):
self._logEvent("Read byte '{}' ({}) from gnuplot child process".format(byte,
hex(ord(byte))))
else:
self._logEvent("read() returned no data")
else:
except Empty:
# else:
self._logEvent("Gnuplot read timed out")
self.checkpoint_stuck = True

Expand Down Expand Up @@ -2312,7 +2332,7 @@ def make_subplot_data_embedded_kwargs(subplot):
# stdout output, then eventually the buffer fills up and gnuplot blocks.
# So keep it going to /dev/null, or make sure to read the test plot from
# stdout
self._printGnuplotPipe( "set output '/dev/null'\n" )
self._printGnuplotPipe( f"set output '{os.devnull}'\n" )
self._printGnuplotPipe( "set terminal dumb\n" )

if self.processOptions.get('multiplot'):
Expand Down