[svn r63869] * moving execnet events to become api plugin calls.

* defining Execnet hooks in an explicit API

--HG--
branch : trunk
This commit is contained in:
hpk 2009-04-08 19:50:14 +02:00
parent 92a06c3787
commit 66c64e6b97
8 changed files with 79 additions and 70 deletions

View File

@ -25,8 +25,8 @@ version = "1.0.0b1"
initpkg(__name__, initpkg(__name__,
description = "pylib and py.test: agile development and test support library", description = "pylib and py.test: agile development and test support library",
revision = int('$LastChangedRevision: 63808 $'.split(':')[1][:-1]), revision = int('$LastChangedRevision: 63869 $'.split(':')[1][:-1]),
lastchangedate = '$LastChangedDate: 2009-04-07 22:46:50 +0200 (Tue, 07 Apr 2009) $', lastchangedate = '$LastChangedDate: 2009-04-08 19:50:14 +0200 (Wed, 08 Apr 2009) $',
version = version, version = version,
url = "http://pylib.org", url = "http://pylib.org",
download_url = "http://codespeak.net/py/%s/download.html" % version, download_url = "http://codespeak.net/py/%s/download.html" % version,
@ -146,6 +146,7 @@ initpkg(__name__,
# gateways into remote contexts # gateways into remote contexts
'execnet.__doc__' : ('./execnet/__init__.py', '__doc__'), 'execnet.__doc__' : ('./execnet/__init__.py', '__doc__'),
'execnet._API' : ('./execnet/gateway.py', 'ExecnetAPI'),
'execnet.SocketGateway' : ('./execnet/register.py', 'SocketGateway'), 'execnet.SocketGateway' : ('./execnet/register.py', 'SocketGateway'),
'execnet.PopenGateway' : ('./execnet/register.py', 'PopenGateway'), 'execnet.PopenGateway' : ('./execnet/register.py', 'PopenGateway'),
'execnet.SshGateway' : ('./execnet/register.py', 'SshGateway'), 'execnet.SshGateway' : ('./execnet/register.py', 'SshGateway'),

View File

@ -36,26 +36,8 @@ class MultiCall:
def execute(self, firstresult=False): def execute(self, firstresult=False):
while self.methods: while self.methods:
self.currentmethod = currentmethod = self.methods.pop() currentmethod = self.methods.pop()
# provide call introspection if "__call__" is the first positional argument res = self.execute_method(currentmethod)
if hasattr(currentmethod, 'im_self'):
varnames = currentmethod.im_func.func_code.co_varnames
needscall = varnames[1:2] == ('__call__',)
else:
try:
varnames = currentmethod.func_code.co_varnames
except AttributeError:
# builtin function
varnames = ()
needscall = varnames[:1] == ('__call__',)
if needscall:
res = currentmethod(self, *self.args, **self.kwargs)
else:
#try:
res = currentmethod(*self.args, **self.kwargs)
#except TypeError:
# print currentmethod.__module__, currentmethod.__name__, self.args, self.kwargs
# raise
if hasattr(self, '_ex1'): if hasattr(self, '_ex1'):
self.results = [res] self.results = [res]
break break
@ -70,6 +52,28 @@ class MultiCall:
if self.results: if self.results:
return self.results[-1] return self.results[-1]
def execute_method(self, currentmethod):
self.currentmethod = currentmethod
# provide call introspection if "__call__" is the first positional argument
if hasattr(currentmethod, 'im_self'):
varnames = currentmethod.im_func.func_code.co_varnames
needscall = varnames[1:2] == ('__call__',)
else:
try:
varnames = currentmethod.func_code.co_varnames
except AttributeError:
# builtin function
varnames = ()
needscall = varnames[:1] == ('__call__',)
if needscall:
return currentmethod(self, *self.args, **self.kwargs)
else:
#try:
return currentmethod(*self.args, **self.kwargs)
#except TypeError:
# print currentmethod.__module__, currentmethod.__name__, self.args, self.kwargs
# raise
def exclude_other_results(self): def exclude_other_results(self):
self._ex1 = True self._ex1 = True

View File

@ -57,6 +57,17 @@ class ExecnetAPI:
""" signal initialisation of new gateway. """ """ signal initialisation of new gateway. """
def pyexecnet_gateway_exit(self, gateway): def pyexecnet_gateway_exit(self, gateway):
""" signal exitting of gateway. """ """ signal exitting of gateway. """
def pyexecnet_gwmanage_newgateway(self, gateway, platinfo):
""" called when a manager has made a new gateway. """
def pyexecnet_gwmanage_rsyncstart(self, source, gateways):
""" called before rsyncing a directory to remote gateways takes place. """
def pyexecnet_gwmanage_rsyncfinish(self, source, gateways):
""" called after rsyncing a directory to remote gateways takes place. """
# ---------------------------------------------------------- # ----------------------------------------------------------
# Base Gateway (used for both remote and local side) # Base Gateway (used for both remote and local side)
@ -76,12 +87,11 @@ class Gateway(object):
self._io = io self._io = io
self._channelfactory = ChannelFactory(self, _startcount) self._channelfactory = ChannelFactory(self, _startcount)
self._cleanup.register(self) self._cleanup.register(self)
try: if _startcount == 1: # only import 'py' on the "client" side
from py._com import PluginAPI from py._com import PluginAPI
except ImportError:
self.api = ExecnetAPI()
else:
self.api = PluginAPI(ExecnetAPI) self.api = PluginAPI(ExecnetAPI)
else:
self.api = ExecnetAPI()
def _initreceive(self, requestqueue=False): def _initreceive(self, requestqueue=False):
if requestqueue: if requestqueue:

View File

@ -21,6 +21,7 @@ class GatewayManager:
if not spec.chdir and not spec.popen: if not spec.chdir and not spec.popen:
spec.chdir = defaultchdir spec.chdir = defaultchdir
self.specs.append(spec) self.specs.append(spec)
self.api = py._com.PluginAPI(py.execnet._API)
def trace(self, msg): def trace(self, msg):
self.notify("trace", "gatewaymanage", msg) self.notify("trace", "gatewaymanage", msg)
@ -34,7 +35,8 @@ class GatewayManager:
gw = py.execnet.makegateway(spec) gw = py.execnet.makegateway(spec)
self.gateways.append(gw) self.gateways.append(gw)
gw.id = "[%s]" % len(self.gateways) gw.id = "[%s]" % len(self.gateways)
self.notify("gwmanage_newgateway", gw, gw._rinfo()) self.api.pyexecnet_gwmanage_newgateway(
gateway=gw, platinfo=gw._rinfo())
def getgateways(self, remote=True, inplacelocal=True): def getgateways(self, remote=True, inplacelocal=True):
if not self.gateways and self.specs: if not self.gateways and self.specs:
@ -79,9 +81,15 @@ class GatewayManager:
rsync.add_target_host(gateway, finished=finished) rsync.add_target_host(gateway, finished=finished)
seen[spec] = gateway seen[spec] = gateway
if seen: if seen:
self.notify("gwmanage_rsyncstart", source=source, gateways=seen.values()) self.api.pyexecnet_gwmanage_rsyncstart(
source=source,
gateways=seen.values(),
)
rsync.send() rsync.send()
self.notify("gwmanage_rsyncfinish", source=source, gateways=seen.values()) self.api.pyexecnet_gwmanage_rsyncfinish(
source=source,
gateways=seen.values()
)
else: else:
self.trace("rsync: nothing to do.") self.trace("rsync: nothing to do.")

View File

@ -20,16 +20,15 @@ class TestGatewayManagerPopen:
for spec in GatewayManager(l, defaultchdir="abc").specs: for spec in GatewayManager(l, defaultchdir="abc").specs:
assert spec.chdir == "abc" assert spec.chdir == "abc"
def test_popen_makegateway_events(self, eventrecorder): def test_popen_makegateway_events(self, _pytest):
rec = _pytest.getcallrecorder(py.execnet._API)
hm = GatewayManager(["popen"] * 2) hm = GatewayManager(["popen"] * 2)
hm.makegateways() hm.makegateways()
event = eventrecorder.popevent("gwmanage_newgateway") call = rec.popcall("pyexecnet_gwmanage_newgateway")
gw, platinfo = event.args[:2] assert call.gateway.id == "[1]"
assert gw.id == "[1]" assert call.platinfo.executable == call.gateway._rinfo().executable
platinfo.executable = gw._rinfo().executable call = rec.popcall("pyexecnet_gwmanage_newgateway")
event = eventrecorder.popevent("gwmanage_newgateway") assert call.gateway.id == "[2]"
gw, platinfo = event.args[:2]
assert gw.id == "[2]"
assert len(hm.gateways) == 2 assert len(hm.gateways) == 2
hm.exit() hm.exit()
assert not len(hm.gateways) assert not len(hm.gateways)
@ -60,18 +59,17 @@ class TestGatewayManagerPopen:
assert dest.join("dir1", "dir2").check() assert dest.join("dir1", "dir2").check()
assert dest.join("dir1", "dir2", 'hello').check() assert dest.join("dir1", "dir2", 'hello').check()
def test_hostmanage_rsync_same_popen_twice(self, source, dest, eventrecorder): def test_hostmanage_rsync_same_popen_twice(self, source, dest, _pytest):
rec = _pytest.getcallrecorder(py.execnet._API)
hm = GatewayManager(["popen//chdir=%s" %dest] * 2) hm = GatewayManager(["popen//chdir=%s" %dest] * 2)
hm.makegateways() hm.makegateways()
source.ensure("dir1", "dir2", "hello") source.ensure("dir1", "dir2", "hello")
hm.rsync(source) hm.rsync(source)
event = eventrecorder.popevent("gwmanage_rsyncstart") call = rec.popcall("pyexecnet_gwmanage_rsyncstart")
source2 = event.kwargs['source'] assert call.source == source
gws = event.kwargs['gateways'] assert len(call.gateways) == 1
assert source2 == source assert hm.gateways[0] == call.gateways[0]
assert len(gws) == 1 call = rec.popcall("pyexecnet_gwmanage_rsyncfinish")
assert hm.gateways[0] == gws[0]
event = eventrecorder.popevent("gwmanage_rsyncfinish")
def test_multi_chdir_popen_with_path(self, testdir): def test_multi_chdir_popen_with_path(self, testdir):
import os import os

View File

@ -77,18 +77,6 @@ class Events:
def pyevent__NOP(self, *args, **kwargs): def pyevent__NOP(self, *args, **kwargs):
""" the no-operation call. """ """ the no-operation call. """
def pyevent__gateway_init(self, gateway):
""" called after a gateway has been initialized. """
def pyevent__gateway_exit(self, gateway):
""" called when gateway is being exited. """
def pyevent__gwmanage_rsyncstart(self, source, gateways):
""" called before rsyncing a directory to remote gateways takes place. """
def pyevent__gwmanage_rsyncfinish(self, source, gateways):
""" called after rsyncing a directory to remote gateways takes place. """
def pyevent__trace(self, category, msg): def pyevent__trace(self, category, msg):
""" called for tracing events. """ """ called for tracing events. """

View File

@ -11,12 +11,12 @@ class ExecnetcleanupPlugin:
if self._debug: if self._debug:
print "[execnetcleanup %0x] %s %s" %(id(self), msg, args) print "[execnetcleanup %0x] %s %s" %(id(self), msg, args)
def pyevent__gateway_init(self, gateway): def pyexecnet_gateway_init(self, gateway):
self.trace("init", gateway) self.trace("init", gateway)
if self._gateways is not None: if self._gateways is not None:
self._gateways.append(gateway) self._gateways.append(gateway)
def pyevent__gateway_exit(self, gateway): def pyexecnet_gateway_exit(self, gateway):
self.trace("exit", gateway) self.trace("exit", gateway)
if self._gateways is not None: if self._gateways is not None:
self._gateways.remove(gateway) self._gateways.remove(gateway)

View File

@ -86,18 +86,18 @@ class TerminalReporter:
for line in str(excrepr).split("\n"): for line in str(excrepr).split("\n"):
self.write_line("INTERNALERROR> " + line) self.write_line("INTERNALERROR> " + line)
def pyevent__gwmanage_newgateway(self, gateway, rinfo): def pyexecnet_gwmanage_newgateway(self, gateway, platinfo):
#self.write_line("%s instantiated gateway from spec %r" %(gateway.id, gateway.spec._spec)) #self.write_line("%s instantiated gateway from spec %r" %(gateway.id, gateway.spec._spec))
d = {} d = {}
d['version'] = repr_pythonversion(rinfo.version_info) d['version'] = repr_pythonversion(platinfo.version_info)
d['id'] = gateway.id d['id'] = gateway.id
d['spec'] = gateway.spec._spec d['spec'] = gateway.spec._spec
d['platform'] = rinfo.platform d['platform'] = platinfo.platform
if self.config.option.verbose: if self.config.option.verbose:
d['extra'] = "- " + rinfo.executable d['extra'] = "- " + platinfo.executable
else: else:
d['extra'] = "" d['extra'] = ""
d['cwd'] = rinfo.cwd d['cwd'] = platinfo.cwd
infoline = ("%(id)s %(spec)s -- platform %(platform)s, " infoline = ("%(id)s %(spec)s -- platform %(platform)s, "
"Python %(version)s " "Python %(version)s "
"cwd: %(cwd)s" "cwd: %(cwd)s"
@ -105,14 +105,14 @@ class TerminalReporter:
self.write_line(infoline) self.write_line(infoline)
self.gateway2info[gateway] = infoline self.gateway2info[gateway] = infoline
def pyevent__gwmanage_rsyncstart(self, source, gateways): def pyexecnet_gwmanage_rsyncstart(self, source, gateways):
targets = ", ".join([gw.id for gw in gateways]) targets = ", ".join([gw.id for gw in gateways])
msg = "rsyncstart: %s -> %s" %(source, targets) msg = "rsyncstart: %s -> %s" %(source, targets)
if not self.config.option.verbose: if not self.config.option.verbose:
msg += " # use --verbose to see rsync progress" msg += " # use --verbose to see rsync progress"
self.write_line(msg) self.write_line(msg)
def pyevent__gwmanage_rsyncfinish(self, source, gateways): def pyexecnet_gwmanage_rsyncfinish(self, source, gateways):
targets = ", ".join([gw.id for gw in gateways]) targets = ", ".join([gw.id for gw in gateways])
self.write_line("rsyncfinish: %s -> %s" %(source, targets)) self.write_line("rsyncfinish: %s -> %s" %(source, targets))
@ -460,17 +460,17 @@ class TestTerminal:
executable = "hello" executable = "hello"
platform = "xyz" platform = "xyz"
cwd = "qwe" cwd = "qwe"
rep.pyevent__gwmanage_newgateway(gw1, rinfo) rep.pyexecnet_gwmanage_newgateway(gw1, rinfo)
linecomp.assert_contains_lines([ linecomp.assert_contains_lines([
"X1*popen*xyz*2.5*" "X1*popen*xyz*2.5*"
]) ])
rep.pyevent__gwmanage_rsyncstart(source="hello", gateways=[gw1, gw2]) rep.pyexecnet_gwmanage_rsyncstart(source="hello", gateways=[gw1, gw2])
linecomp.assert_contains_lines([ linecomp.assert_contains_lines([
"rsyncstart: hello -> X1, X2" "rsyncstart: hello -> X1, X2"
]) ])
rep.pyevent__gwmanage_rsyncfinish(source="hello", gateways=[gw1, gw2]) rep.pyexecnet_gwmanage_rsyncfinish(source="hello", gateways=[gw1, gw2])
linecomp.assert_contains_lines([ linecomp.assert_contains_lines([
"rsyncfinish: hello -> X1, X2" "rsyncfinish: hello -> X1, X2"
]) ])