[svn r63888] finally. the event concept is basically gone.

now we only have plugin hooks aka plugin calls

--HG--
branch : trunk
This commit is contained in:
hpk 2009-04-09 02:36:07 +02:00
parent 0c4fc99a6f
commit cd038ee708
12 changed files with 21 additions and 113 deletions

View File

@ -1,21 +1,5 @@
""" """
py lib plugins and events. py lib plugins and plugin call management
you can write plugins that extend the py lib API.
currently this is mostly used by py.test
registering a plugin
++++++++++++++++++++++++++++++++++
::
>>> class MyPlugin:
... def pyevent__plugin_registered(self, plugin):
... print "registering", plugin.__class__.__name__
...
>>> import py
>>> py._com.pyplugins.register(MyPlugin())
registering MyPlugin
""" """
import py import py
@ -92,7 +76,6 @@ class PyPlugins:
def import_module(self, modspec): def import_module(self, modspec):
# XXX allow modspec to specify version / lookup # XXX allow modspec to specify version / lookup
modpath = modspec modpath = modspec
self.notify("importingmodule", modpath)
__import__(modpath) __import__(modpath)
def consider_env(self): def consider_env(self):
@ -155,13 +138,6 @@ class PyPlugins:
return MultiCall(self.listattr(methname, plugins=[plugin]), return MultiCall(self.listattr(methname, plugins=[plugin]),
*args, **kwargs).execute(firstresult=True) *args, **kwargs).execute(firstresult=True)
def notify(self, eventname, *args, **kwargs):
#print "notifying", eventname, args, kwargs
MultiCall(self.listattr("pyevent__" + eventname),
*args, **kwargs).execute()
#print "calling anonymous hooks", args, kwargs
MultiCall(self.listattr("pyevent"), eventname, args, kwargs).execute()
class PluginAPI: class PluginAPI:
def __init__(self, apiclass, plugins=None): def __init__(self, apiclass, plugins=None):

View File

@ -280,5 +280,4 @@ def autoimport(pkgname):
ENVKEY = pkgname.upper() + "_AUTOIMPORT" ENVKEY = pkgname.upper() + "_AUTOIMPORT"
if ENVKEY in os.environ: if ENVKEY in os.environ:
for impname in os.environ[ENVKEY].split(","): for impname in os.environ[ENVKEY].split(","):
py._com.pyplugins.notify("autoimport", impname)
__import__(impname) __import__(impname)

View File

@ -97,21 +97,6 @@ class TestPyPlugins:
assert not plugins.isregistered(my) assert not plugins.isregistered(my)
assert plugins.getplugins() == [my2] assert plugins.getplugins() == [my2]
def test_onregister(self):
plugins = PyPlugins()
l = []
class MyApi:
def pyevent__plugin_registered(self, plugin):
l.append(plugin)
def pyevent__plugin_unregistered(self, plugin):
l.remove(plugin)
myapi = MyApi()
plugins.register(myapi)
assert len(l) == 1
assert l[0] is myapi
plugins.unregister(myapi)
assert not l
def test_call_methods(self): def test_call_methods(self):
plugins = PyPlugins() plugins = PyPlugins()
class api1: class api1:
@ -175,21 +160,6 @@ class TestPyPlugins:
l = list(plugins.listattr('x', reverse=True)) l = list(plugins.listattr('x', reverse=True))
assert l == [43, 42, 41] assert l == [43, 42, 41]
def test_notify_anonymous_ordered(self):
plugins = PyPlugins()
l = []
class api1:
def pyevent__hello(self):
l.append("hellospecific")
class api2:
def pyevent(self, name, args, kwargs):
if name == "hello":
l.append(name + "anonymous")
plugins.register(api1())
plugins.register(api2())
plugins.notify('hello')
assert l == ["hellospecific", "helloanonymous"]
def test_consider_env(self, monkeypatch): def test_consider_env(self, monkeypatch):
plugins = PyPlugins() plugins = PyPlugins()
monkeypatch.setitem(os.environ, 'PYLIB', "unknownconsider_env") monkeypatch.setitem(os.environ, 'PYLIB', "unknownconsider_env")
@ -201,14 +171,7 @@ class TestPyPlugins:
mod.pylib = ["xxx nomod"] mod.pylib = ["xxx nomod"]
excinfo = py.test.raises(ImportError, "plugins.consider_module(mod)") excinfo = py.test.raises(ImportError, "plugins.consider_module(mod)")
mod.pylib = "os" mod.pylib = "os"
class Events(list):
def pyevent__importingmodule(self, mod):
self.append(mod)
l = Events()
plugins.register(l)
plugins.consider_module(mod) plugins.consider_module(mod)
assert len(l) == 1
assert l[0] == (mod.pylib)
def test_api_and_defaults(): def test_api_and_defaults():
assert isinstance(py._com.pyplugins, PyPlugins) assert isinstance(py._com.pyplugins, PyPlugins)
@ -226,30 +189,6 @@ def test_subprocess_env(testdir, monkeypatch):
finally: finally:
old.chdir() old.chdir()
class TestPyPluginsEvents:
def test_pyevent__named_dispatch(self):
plugins = PyPlugins()
l = []
class A:
def pyevent__name(self, x):
l.append(x)
plugins.register(A())
plugins.notify("name", 13)
assert l == [13]
def test_pyevent__anonymous_dispatch(self):
plugins = PyPlugins()
l = []
class A:
def pyevent(self, name, args, kwargs):
if name == "name":
l.extend([args, kwargs])
plugins.register(A())
plugins.notify("name", 13, x=15)
assert l == [(13, ), {'x':15}]
class TestPluginAPI: class TestPluginAPI:
def test_happypath(self): def test_happypath(self):
plugins = PyPlugins() plugins = PyPlugins()

View File

@ -62,7 +62,7 @@ class WarningPlugin(object):
filename = module filename = module
path = py.path.local(filename) path = py.path.local(filename)
warning = Warning(msg, path, lineno) warning = Warning(msg, path, lineno)
self.bus.notify("WARNING", warning) self.bus.call_each("pyevent__WARNING", warning)
# singleton api warner for py lib # singleton api warner for py lib
apiwarner = WarningPlugin(py._com.pyplugins) apiwarner = WarningPlugin(py._com.pyplugins)

View File

@ -50,7 +50,7 @@ class Config(object):
def trace(self, msg): def trace(self, msg):
if getattr(self.option, 'traceconfig', None): if getattr(self.option, 'traceconfig', None):
self.bus.notify("trace", "config", msg) self.api.pytest_trace(category="config", msg=msg)
def _processopt(self, opt): def _processopt(self, opt):
if hasattr(opt, 'default') and opt.dest: if hasattr(opt, 'default') and opt.dest:

View File

@ -96,11 +96,9 @@ class DSession(Session):
loopstate.dowork = True loopstate.dowork = True
callname, args, kwargs = eventcall callname, args, kwargs = eventcall
call = getattr(self.config.api, callname, None) if callname is not None:
if call is not None: call = getattr(self.config.api, callname)
call(*args, **kwargs) call(*args, **kwargs)
else:
self.bus.notify(callname, *args, **kwargs)
# termination conditions # termination conditions
if ((loopstate.testsfailed and self.config.option.exitfirst) or if ((loopstate.testsfailed and self.config.option.exitfirst) or
@ -177,7 +175,7 @@ class DSession(Session):
if isinstance(next, py.test.collect.Item): if isinstance(next, py.test.collect.Item):
senditems.append(next) senditems.append(next)
else: else:
self.bus.notify("collectstart", next) self.config.api.pytest_collectstart(collector=next)
self.queueevent("pytest_collectreport", basic_collect_report(next)) self.queueevent("pytest_collectreport", basic_collect_report(next))
if self.config.option.dist == "each": if self.config.option.dist == "each":
self.senditems_each(senditems) self.senditems_each(senditems)

View File

@ -129,9 +129,9 @@ class TestDSession:
# check that RescheduleEvents are not immediately # check that RescheduleEvents are not immediately
# rescheduled if there are no nodes # rescheduled if there are no nodes
assert loopstate.dowork == False assert loopstate.dowork == False
session.queueevent("anonymous") session.queueevent(None)
session.loop_once(loopstate) session.loop_once(loopstate)
session.queueevent("anonymous") session.queueevent(None)
session.loop_once(loopstate) session.loop_once(loopstate)
assert node.sent == [[item]] assert node.sent == [[item]]
session.queueevent("pytest_itemtestreport", run(item, node)) session.queueevent("pytest_itemtestreport", run(item, node))
@ -204,7 +204,7 @@ class TestDSession:
session.addnode(node) session.addnode(node)
loopstate = session._initloopstate([item]) loopstate = session._initloopstate([item])
session.queueevent("NOP") session.queueevent(None)
session.loop_once(loopstate) session.loop_once(loopstate)
assert node.sent == [[item]] assert node.sent == [[item]]

View File

@ -129,7 +129,7 @@ def slave_runsession(channel, config, fullwidth, hasmarkup):
try: try:
colitem = py.test.collect.Collector._fromtrail(trail, config) colitem = py.test.collect.Collector._fromtrail(trail, config)
except AssertionError, e: except AssertionError, e:
#XXX session.bus.notify of "test disappeared" #XXX send info for "test disappeared" or so
continue continue
colitems.append(colitem) colitems.append(colitem)
else: else:

View File

@ -49,6 +49,7 @@ class CallRecorder:
def finalize(self): def finalize(self):
for recorder in self._recorders.values(): for recorder in self._recorders.values():
self._pyplugins.unregister(recorder) self._pyplugins.unregister(recorder)
self._recorders.clear()
def recordsmethod(self, name): def recordsmethod(self, name):
for apiclass in self._recorders: for apiclass in self._recorders:

View File

@ -385,21 +385,20 @@ class EventRecorder(object):
def clear(self): def clear(self):
self.events[:] = [] self.events[:] = []
self.callrecorder.calls[:] = []
def unregister(self): def unregister(self):
self.pyplugins.unregister(self) self.pyplugins.unregister(self)
self.callrecorder.finalize()
@py.test.mark.xfail def test_eventrecorder(testdir):
def test_eventrecorder():
bus = py._com.PyPlugins() bus = py._com.PyPlugins()
recorder = EventRecorder(bus) recorder = testdir.geteventrecorder(bus)
bus.notify("anonymous")
assert recorder.events
assert not recorder.getfailures() assert not recorder.getfailures()
rep = runner.ItemTestReport(None, None) rep = runner.ItemTestReport(None, None)
rep.passed = False rep.passed = False
rep.failed = True rep.failed = True
bus.notify("pytest_itemtestreport", rep) bus.call_each("pytest_itemtestreport", rep=rep)
failures = recorder.getfailures() failures = recorder.getfailures()
assert failures == [rep] assert failures == [rep]
failures = recorder.getfailures() failures = recorder.getfailures()
@ -408,12 +407,12 @@ def test_eventrecorder():
rep = runner.ItemTestReport(None, None) rep = runner.ItemTestReport(None, None)
rep.passed = False rep.passed = False
rep.skipped = True rep.skipped = True
bus.notify("pytest_itemtestreport", rep) bus.call_each("pytest_itemtestreport", rep=rep)
rep = runner.CollectReport(None, None) rep = runner.CollectReport(None, None)
rep.passed = False rep.passed = False
rep.failed = True rep.failed = True
bus.notify("pytest_itemtestreport", rep) bus.call_each("pytest_itemtestreport", rep=rep)
passed, skipped, failed = recorder.listoutcomes() passed, skipped, failed = recorder.listoutcomes()
assert not passed and skipped and failed assert not passed and skipped and failed
@ -427,8 +426,7 @@ def test_eventrecorder():
recorder.clear() recorder.clear()
assert not recorder.events assert not recorder.events
assert not recorder.getfailures() assert not recorder.getfailures()
bus.notify(pytest_itemtestreport, rep) bus.call_each("pytest_itemtestreport", rep=rep)
assert not recorder.events
assert not recorder.getfailures() assert not recorder.getfailures()
class LineComp: class LineComp:

View File

@ -11,9 +11,9 @@ class RunnerPlugin:
def pytest_item_setup_and_runtest(self, item): def pytest_item_setup_and_runtest(self, item):
setupstate = item.config._setupstate setupstate = item.config._setupstate
call = item.config.guardedcall(lambda: setupstate.prepare(item)) call = item.config.guardedcall(lambda: setupstate.prepare(item))
rep = ItemSetupReport(item, call.excinfo, call.outerr)
if call.excinfo: if call.excinfo:
item.config.pytestplugins.notify(pytest_itemsetupreport, rep) rep = ItemSetupReport(item, call.excinfo, call.outerr)
item.config.api.pytest_itemsetupreport(rep=rep)
else: else:
call = item.config.guardedcall(lambda: item.runtest()) call = item.config.guardedcall(lambda: item.runtest())
item.config.api.pytest_item_runtest_finished( item.config.api.pytest_item_runtest_finished(

View File

@ -79,9 +79,6 @@ class PytestPlugins(object):
#print "plugins.call_each", args[0], args[1:], kwargs #print "plugins.call_each", args[0], args[1:], kwargs
return self.pyplugins.call_each(*args, **kwargs) return self.pyplugins.call_each(*args, **kwargs)
def notify(self, eventname, *args, **kwargs):
return self.pyplugins.notify(eventname, *args, **kwargs)
def notify_exception(self, excinfo=None): def notify_exception(self, excinfo=None):
if excinfo is None: if excinfo is None:
excinfo = py.code.ExceptionInfo() excinfo = py.code.ExceptionInfo()