* simplify stdout/stderr handling and modules and for now remove support

for directly stdout/stderr directly on remote_exec

--HG--
branch : trunk
This commit is contained in:
holger krekel 2009-09-02 19:39:24 +02:00
parent 73fc2f01f2
commit 6c3e961bc5
3 changed files with 22 additions and 56 deletions

View File

@ -9,7 +9,6 @@ from py.__.execnet.gateway_base import ExecnetAPI
# XXX we'd like to have a leaner and meaner bootstrap mechanism
startup_modules = [
'py.__.thread.io',
'py.__.execnet.gateway_base',
]
@ -48,7 +47,7 @@ class InitiatingGateway(BaseGateway):
self._remote_bootstrap_gateway(io)
super(InitiatingGateway, self).__init__(io=io, _startcount=1)
# XXX we dissallow execution form the other side
self._initreceive(requestqueue=False)
self._initreceive()
self.hook = py._com.HookRelay(ExecnetAPI, py._com.comregistry)
self.hook.pyexecnet_gateway_init(gateway=self)
self._cleanup.register(self)
@ -103,20 +102,15 @@ class InitiatingGateway(BaseGateway):
self._cache_rinfo = RInfo(**ch.receive())
return self._cache_rinfo
def remote_exec(self, source, stdout=None, stderr=None):
def remote_exec(self, source):
""" return channel object and connect it to a remote
execution thread where the given 'source' executes
and has the sister 'channel' object in its global
namespace. The callback functions 'stdout' and
'stderr' get called on receival of remote
stdout/stderr output strings.
namespace.
"""
source = str(py.code.Source(source))
channel = self.newchannel()
outid = self._newredirectchannelid(stdout)
errid = self._newredirectchannelid(stderr)
self._send(Message.CHANNEL_OPEN(
channel.id, (source, outid, errid)))
self._send(Message.CHANNEL_OPEN(channel.id, source))
return channel
def remote_init_threads(self, num=None):
@ -131,7 +125,7 @@ class InitiatingGateway(BaseGateway):
execpool = WorkerPool(maxthreads=%r)
gw = channel.gateway
while 1:
task = gw._requestqueue.get()
task = gw._execqueue.get()
if task is None:
gw._stopsend()
execpool.shutdown()
@ -141,21 +135,13 @@ class InitiatingGateway(BaseGateway):
""" % num)
self._remotechannelthread = self.remote_exec(source)
def _newredirectchannelid(self, callback):
if callback is None:
return
if hasattr(callback, 'write'):
callback = callback.write
assert callable(callback)
chan = self.newchannel()
chan.setcallback(callback)
return chan.id
def _remote_redirect(self, stdout=None, stderr=None):
""" return a handle representing a redirection of a remote
end's stdout to a local file object. with handle.close()
the redirection will be reverted.
"""
# XXX implement a remote_exec_in_globals(...)
# to send ThreadOut implementation over
clist = []
for name, out in ('stdout', stdout), ('stderr', stderr):
if out:
@ -164,7 +150,7 @@ class InitiatingGateway(BaseGateway):
channel = self.remote_exec("""
import sys
outchannel = channel.receive()
outchannel.gateway._ThreadOut(sys, %r).setdefaultwriter(outchannel.send)
ThreadOut(sys, %r).setdefaultwriter(outchannel.send)
""" % name)
channel.send(outchannel)
clist.append(channel)

View File

@ -18,11 +18,6 @@ try:
except ImportError:
import Queue as queue
# XXX the following lines should not be here
if 'ThreadOut' not in globals():
import py
ThreadOut = py._thread.ThreadOut
if sys.version_info > (3, 0):
exec("""def do_exec(co, loc):
exec(co, loc)""")
@ -594,14 +589,14 @@ class ExecnetAPI:
def pyexecnet_gwmanage_rsyncfinish(self, source, gateways):
""" called after rsyncing a directory to remote gateways takes place. """
class BaseGateway(object):
hook = ExecnetAPI()
exc_info = sys.exc_info
class _StopExecLoop(Exception): pass
_ThreadOut = ThreadOut
_requestqueue = None
class _StopExecLoop(Exception):
pass
def __init__(self, io, _startcount=2):
""" initialize core gateway, using the given inputoutput object.
@ -610,9 +605,7 @@ class BaseGateway(object):
self._channelfactory = ChannelFactory(self, _startcount)
self._receivelock = threading.RLock()
def _initreceive(self, requestqueue=False):
if requestqueue:
self._requestqueue = queue.Queue()
def _initreceive(self):
self._receiverthread = threading.Thread(name="receiver",
target=self._thread_receiver)
self._receiverthread.setDaemon(1)
@ -678,36 +671,23 @@ class BaseGateway(object):
self._send(None)
def _stopexec(self):
if self._requestqueue is not None:
self._requestqueue.put(None)
def _local_redirect_thread_output(self, outid, errid):
l = []
for name, id in ('stdout', outid), ('stderr', errid):
if id:
channel = self._channelfactory.new(outid)
out = self._ThreadOut(sys, name)
out.setwritefunc(channel.send)
l.append((out, channel))
def close():
for out, channel in l:
out.delwritefunc()
channel.close()
return close
if hasattr(self, '_execqueue'):
self._execqueue.put(None)
def _local_schedulexec(self, channel, sourcetask):
if self._requestqueue is not None:
self._requestqueue.put((channel, sourcetask))
if hasattr(self, '_execqueue'):
self._execqueue.put((channel, sourcetask))
else:
# we will not execute, let's send back an error
# to inform the other side
channel.close("execution disallowed")
def _servemain(self, joining=True):
self._initreceive(requestqueue=True)
self._execqueue = queue.Queue()
self._initreceive()
try:
while 1:
item = self._requestqueue.get()
item = self._execqueue.get()
if item is None:
self._stopsend()
break
@ -722,17 +702,15 @@ class BaseGateway(object):
def _executetask(self, item):
""" execute channel/source items. """
channel, (source, outid, errid) = item
channel, source = item
try:
loc = { 'channel' : channel, '__name__': '__channelexec__'}
#open("task.py", 'w').write(source)
self._trace("execution starts: %s" % repr(source)[:50])
close = self._local_redirect_thread_output(outid, errid)
try:
co = compile(source+'\n', '', 'exec')
do_exec(co, loc)
finally:
close()
self._trace("execution finished")
except sysex:
pass

View File

@ -429,6 +429,7 @@ class BasicRemoteExecution:
assert err
assert str(err).find("ValueError") != -1
@py.test.mark.xfail
def test_remote_redirect_stdout(self):
out = py.io.TextIO()
handle = self.gw._remote_redirect(stdout=out)
@ -438,6 +439,7 @@ class BasicRemoteExecution:
s = out.getvalue()
assert s.strip() == "42"
@py.test.mark.xfail
def test_remote_exec_redirect_multi(self):
num = 3
l = [[] for x in range(num)]