Skip to content

Commit ca7778e

Browse files
authored
Merge pull request #1 from vtitor/master
Extract init reactor methods
2 parents 7e6cd18 + eda6c44 commit ca7778e

File tree

3 files changed

+81
-96
lines changed

3 files changed

+81
-96
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ __pycache__/
2020
/dist/
2121
/.tox/
2222
/README.html
23+
.idea/

pytest_twisted.py

Lines changed: 78 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,27 @@
88
from twisted.internet.threads import blockingCallFromThread
99
from twisted.python import failure
1010

11-
gr_twisted = None
12-
reactor = None
11+
12+
class _instances:
13+
gr_twisted = None
14+
reactor = None
15+
16+
17+
def pytest_namespace():
18+
return dict(inlineCallbacks=inlineCallbacks, blockon=blockon)
1319

1420

1521
def blockon(d):
16-
if reactor.running:
22+
if _instances.reactor.running:
1723
return block_from_thread(d)
1824

1925
return blockon_default(d)
2026

2127

2228
def blockon_default(d):
2329
current = greenlet.getcurrent()
24-
assert current is not gr_twisted, \
25-
"blockon cannot be called from the twisted greenlet"
30+
assert current is not _instances.gr_twisted, \
31+
'blockon cannot be called from the twisted greenlet'
2632
result = []
2733

2834
def cb(r):
@@ -32,8 +38,8 @@ def cb(r):
3238

3339
d.addCallbacks(cb, cb)
3440
if not result:
35-
_result = gr_twisted.switch()
36-
assert _result is result, "illegal switch in blockon"
41+
_result = _instances.gr_twisted.switch()
42+
assert _result is result, 'illegal switch in blockon'
3743

3844
if isinstance(result[0], failure.Failure):
3945
result[0].raiseException()
@@ -42,96 +48,28 @@ def cb(r):
4248

4349

4450
def block_from_thread(d):
45-
return blockingCallFromThread(reactor, lambda x: x, d)
51+
return blockingCallFromThread(_instances.reactor, lambda x: x, d)
4652

4753

4854
@decorator.decorator
4955
def inlineCallbacks(fun, *args, **kw):
5056
return defer.inlineCallbacks(fun)(*args, **kw)
5157

5258

53-
def pytest_namespace():
54-
return dict(inlineCallbacks=inlineCallbacks,
55-
blockon=blockon)
56-
57-
58-
def stop_twisted_greenlet():
59-
if gr_twisted:
60-
reactor.stop()
61-
gr_twisted.switch()
62-
63-
64-
def create_twisted_greenlet():
65-
global gr_twisted
66-
if reactor is None:
59+
def init_twisted_greenlet():
60+
if _instances.reactor is None:
6761
return
6862

69-
if not gr_twisted and not reactor.running:
70-
gr_twisted = greenlet.greenlet(reactor.run)
63+
if not _instances.gr_twisted and not _instances.reactor.running:
64+
_instances.gr_twisted = greenlet.greenlet(_instances.reactor.run)
7165
# give me better tracebacks:
7266
failure.Failure.cleanFailure = lambda self: None
7367

7468

75-
def pytest_addhooks(pluginmanager):
76-
create_twisted_greenlet()
77-
78-
79-
def pytest_addoption(parser):
80-
group = parser.getgroup('twisted')
81-
group.addoption('--qt5reactor', dest='qt5reactor', action='store_true',
82-
help='prepare for use with qt5reactor')
83-
84-
85-
def pytest_configure(config):
86-
# TODO: why is the parameter needed?
87-
def default_reactor():
88-
global reactor
89-
import twisted.internet.reactor
90-
reactor = twisted.internet.reactor
91-
create_twisted_greenlet()
92-
93-
def qt5_reactor(qapp):
94-
global gr_twisted
95-
global reactor
96-
import qt5reactor
97-
98-
reinstalled = False
99-
100-
try:
101-
qt5reactor.install()
102-
except error.ReactorAlreadyInstalledError:
103-
if not isinstance(reactor, qt5reactor.QtReactor):
104-
stop_twisted_greenlet()
105-
gr_twisted = None
106-
del sys.modules['twisted.internet.reactor']
107-
qt5reactor.install()
108-
reinstalled = True
109-
else:
110-
reinstalled = True
111-
112-
if reinstalled:
113-
import twisted.internet.reactor
114-
reactor = twisted.internet.reactor
115-
116-
create_twisted_greenlet()
117-
118-
if config.getoption('qt5reactor'):
119-
reactor_fixture = qt5_reactor
120-
else:
121-
reactor_fixture = default_reactor
122-
123-
class ReactorPlugin(object):
124-
reactor = staticmethod(
125-
pytest.fixture(scope='session', autouse=True)(reactor_fixture)
126-
)
127-
128-
config.pluginmanager.register(ReactorPlugin())
129-
130-
131-
@pytest.fixture(scope="session", autouse=True)
132-
def twisted_greenlet(request, reactor):
133-
request.addfinalizer(stop_twisted_greenlet)
134-
return gr_twisted
69+
def stop_twisted_greenlet():
70+
if _instances.gr_twisted:
71+
_instances.reactor.stop()
72+
_instances.gr_twisted.switch()
13573

13674

13775
def _pytest_pyfunc_call(pyfuncitem):
@@ -140,7 +78,7 @@ def _pytest_pyfunc_call(pyfuncitem):
14078
return testfunction(*pyfuncitem._args)
14179
else:
14280
funcargs = pyfuncitem.funcargs
143-
if hasattr(pyfuncitem, "_fixtureinfo"):
81+
if hasattr(pyfuncitem, '_fixtureinfo'):
14482
testargs = {}
14583
for arg in pyfuncitem._fixtureinfo.argnames:
14684
testargs[arg] = funcargs[arg]
@@ -150,18 +88,66 @@ def _pytest_pyfunc_call(pyfuncitem):
15088

15189

15290
def pytest_pyfunc_call(pyfuncitem):
153-
if gr_twisted is not None:
154-
if gr_twisted.dead:
155-
raise RuntimeError("twisted reactor has stopped")
91+
if _instances.gr_twisted is not None:
92+
if _instances.gr_twisted.dead:
93+
raise RuntimeError('twisted reactor has stopped')
15694

15795
def in_reactor(d, f, *args):
15896
return defer.maybeDeferred(f, *args).chainDeferred(d)
15997

16098
d = defer.Deferred()
161-
reactor.callLater(0.0, in_reactor, d, _pytest_pyfunc_call, pyfuncitem)
99+
_instances.reactor.callLater(
100+
0.0, in_reactor, d, _pytest_pyfunc_call, pyfuncitem
101+
)
162102
blockon_default(d)
163103
else:
164-
if not reactor.running:
165-
raise RuntimeError("twisted reactor is not running")
166-
blockingCallFromThread(reactor, _pytest_pyfunc_call, pyfuncitem)
104+
if not _instances.reactor.running:
105+
raise RuntimeError('twisted reactor is not running')
106+
blockingCallFromThread(
107+
_instances.reactor, _pytest_pyfunc_call, pyfuncitem
108+
)
167109
return True
110+
111+
112+
@pytest.fixture(scope="session", autouse=True)
113+
def twisted_greenlet(request, reactor):
114+
request.addfinalizer(stop_twisted_greenlet)
115+
return _instances.gr_twisted
116+
117+
118+
def init_reactor():
119+
import twisted.internet.reactor
120+
_instances.reactor = twisted.internet.reactor
121+
init_twisted_greenlet()
122+
123+
124+
def init_qt5_reactor(qapp):
125+
import qt5reactor
126+
try:
127+
qt5reactor.install()
128+
except error.ReactorAlreadyInstalledError:
129+
if not isinstance(_instances.reactor, qt5reactor.QtReactor):
130+
stop_twisted_greenlet()
131+
_instances.gr_twisted = None
132+
del sys.modules['twisted.internet.reactor']
133+
qt5reactor.install()
134+
init_reactor()
135+
136+
137+
def pytest_addoption(parser):
138+
group = parser.getgroup('twisted')
139+
group.addoption('--qt5reactor', dest='qt5reactor', action='store_true',
140+
help='prepare for use with qt5reactor')
141+
142+
143+
def pytest_configure(config):
144+
reactor_fixture = init_reactor
145+
if config.getoption('qt5reactor'):
146+
reactor_fixture = init_qt5_reactor
147+
148+
class ReactorPlugin(object):
149+
reactor = staticmethod(
150+
pytest.fixture(scope='session', autouse=True)(reactor_fixture)
151+
)
152+
153+
config.pluginmanager.register(ReactorPlugin())

testing/test_basic.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import sys
44

5-
import pytest
6-
75

86
def test_fail_later(testdir):
97
testdir.makepyfile("""
@@ -108,13 +106,13 @@ def test_MAIN():
108106
assert outcomes.get("passed") == 1
109107

110108

111-
@pytest.mark.skip
112-
def test_blocon_in_hook(testdir):
109+
def test_blockon_in_hook(testdir):
113110
testdir.makeconftest("""
114111
import pytest_twisted as pt
115112
from twisted.internet import reactor, defer
116113
117114
def pytest_configure(config):
115+
pt.init_reactor()
118116
d = defer.Deferred()
119117
reactor.callLater(0.01, d.callback, 1)
120118
pt.blockon(d)

0 commit comments

Comments
 (0)