Skip to content

Commit 935804a

Browse files
committed
Merge branch 'master' into 35-altendky-tidy_async_await_fixtures
2 parents bac0f90 + 34473e6 commit 935804a

File tree

8 files changed

+137
-77
lines changed

8 files changed

+137
-77
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ language: python
33
matrix:
44
include:
55
- python: 2.7
6-
- python: 3.4
76
- python: 3.5
87
- python: 3.6
98
- python: 3.7

CONTRIBUTING.rst

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,26 @@ What it takes to add a new reactor:
88

99
* In ``testing/test_basic.py``
1010

11-
* Add ``test_blockon_in_hook_with_foo()`` decorated by ``@skip_if_reactor_not('foo')``
12-
* Add ``test_wrong_reactor_with_foo()`` decorated by ``@skip_if_reactor_not('foo')``
11+
* Add ``test_blockon_in_hook_with_foo()`` with ``skip_if_reactor_not('foo')`` as the first line
12+
* Add ``test_wrong_reactor_with_foo()`` with ``skip_if_reactor_not('foo')`` as the first line
1313

1414
* In ``tox.ini``
1515

1616
* Adjust ``envlist`` to include the ``fooreactor`` factor for the appropriate versions of Python
1717
* Add conditional ``deps`` for the new reactor such as ``foo: foobar`` to the appropriate test environments
18-
* Add the conditional assignment ``foo: reactor_option=foo`` to ``setenv`` in the appropriate test environments
18+
* Add ``fooreactor: pytest --reactor=foo`` to the commands list
1919

2020
* In ``.travis.yml``
2121

2222
* Consider any extra system packages which may be required
23+
24+
* In ``appveyor.yml``
25+
26+
* Add the new reactor environment to the ``TOXENV`` for each relevant Python
27+
28+
Reference reactor additions:
29+
* `asyncio`_
30+
* `qt5reactor`_
31+
32+
.. _`asyncio`: https://github.com/pytest-dev/pytest-twisted/pull/63
33+
.. _`qt5reactor`: https://github.com/pytest-dev/pytest-twisted/pull/16

README.rst

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ pytest-twisted - test twisted code with pytest
77
|PyPI| |Pythons| |Travis| |AppVeyor| |Black|
88

99
:Authors: Ralf Schmitt, Kyle Altendorf, Victor Titor
10-
:Version: 1.8
11-
:Date: 2018-05-01
10+
:Version: 1.11
11+
:Date: 2019-08-20
1212
:Download: https://pypi.python.org/pypi/pytest-twisted#downloads
1313
:Code: https://github.com/pytest-dev/pytest-twisted
1414

@@ -33,11 +33,9 @@ The plugin is available after installation and can be disabled using
3333
By default ``twisted.internet.default`` is used to install the reactor.
3434
This creates the same reactor that ``import twisted.internet.reactor``
3535
would. Alternative reactors can be specified using the ``--reactor``
36-
option.
37-
38-
Presently only ``qt5reactor`` is supported for use with ``pyqt5``
39-
and ``pytest-qt``. This `guide`_ describes how to add support for
40-
a new reactor.
36+
option. This presently supports ``qt5reactor`` for use with ``pyqt5``
37+
and ``pytest-qt`` as well as ``asyncio``. This `guide`_ describes how to add
38+
support for a new reactor.
4139

4240
The reactor is automatically created prior to the first test but can
4341
be explicitly installed earlier by calling
@@ -53,7 +51,7 @@ is to ``import pytest_twisted as pt``.
5351
inlineCallbacks
5452
===============
5553
Using ``twisted.internet.defer.inlineCallbacks`` as a decorator for test
56-
functions, which take funcargs, does not work. Please use
54+
functions, which use fixtures, does not work. Please use
5755
``pytest_twisted.inlineCallbacks`` instead::
5856

5957
@pytest_twisted.inlineCallbacks
@@ -65,7 +63,7 @@ functions, which take funcargs, does not work. Please use
6563
ensureDeferred
6664
==============
6765
Using ``twisted.internet.defer.ensureDeferred`` as a decorator for test
68-
functions, which take funcargs, does not work. Please use
66+
functions, which use fixtures, does not work. Please use
6967
``pytest_twisted.ensureDeferred`` instead::
7068

7169
@pytest_twisted.ensureDeferred
@@ -105,7 +103,7 @@ The twisted greenlet
105103
====================
106104
Some libraries (e.g. corotwine) need to know the greenlet, which is
107105
running the twisted reactor. It's available from the
108-
``twisted_greenlet`` funcarg. The following code can be used to make
106+
``twisted_greenlet`` fixture. The following code can be used to make
109107
corotwine work with pytest-twisted::
110108

111109
@pytest.fixture(scope="session", autouse=True)
@@ -116,10 +114,14 @@ corotwine work with pytest-twisted::
116114

117115
That's (almost) all.
118116

119-
============
117+
120118
Deprecations
121119
============
122120

121+
----
122+
v1.9
123+
----
124+
123125
``pytest.blockon``
124126
Use ``pytest_twisted.blockon``
125127
``pytest.inlineCallbacks``

appveyor.yml

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,22 @@ environment:
88
- TOXENV: py27-defaultreactor
99
PYTHON: "C:\\Python27-x64"
1010

11-
- TOXENV: py34-defaultreactor
12-
PYTHON: "C:\\Python34"
13-
14-
- TOXENV: py34-defaultreactor
15-
PYTHON: "C:\\Python34-x64"
16-
17-
- TOXENV: py35-defaultreactor, win-py35-qt5reactor
11+
- TOXENV: py35-defaultreactor, win-py35-qt5reactor, py35-asyncioreactor
1812
PYTHON: "C:\\Python35"
1913

20-
- TOXENV: py35-defaultreactor, win-py35-qt5reactor
14+
- TOXENV: py35-defaultreactor, win-py35-qt5reactor, py35-asyncioreactor
2115
PYTHON: "C:\\Python35-x64"
2216

23-
- TOXENV: py36-defaultreactor, win-py36-qt5reactor
17+
- TOXENV: py36-defaultreactor, win-py36-qt5reactor, py36-asyncioreactor
2418
PYTHON: "C:\\Python36"
2519

26-
- TOXENV: py36-defaultreactor, win-py36-qt5reactor
20+
- TOXENV: py36-defaultreactor, win-py36-qt5reactor, py36-asyncioreactor
2721
PYTHON: "C:\\Python36-x64"
2822

29-
- TOXENV: py37-defaultreactor, win-py37-qt5reactor
23+
- TOXENV: py37-defaultreactor, win-py37-qt5reactor, py37-asyncioreactor
3024
PYTHON: "C:\\Python37"
3125

32-
- TOXENV: py37-defaultreactor, win-py37-qt5reactor
26+
- TOXENV: py37-defaultreactor, win-py37-qt5reactor, py37-asyncioreactor
3327
PYTHON: "C:\\Python37-x64"
3428

3529
install:

pytest_twisted.py

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -174,53 +174,50 @@ def decorator(f):
174174
def _pytest_pyfunc_call(pyfuncitem):
175175
testfunction = pyfuncitem.obj
176176
async_generators = []
177-
if pyfuncitem._isyieldedfunction():
178-
defer.returnValue(testfunction(*pyfuncitem._args))
179-
else:
180-
funcargs = pyfuncitem.funcargs
181-
if hasattr(pyfuncitem, "_fixtureinfo"):
182-
testargs = {}
183-
for arg in pyfuncitem._fixtureinfo.argnames:
184-
if isinstance(funcargs[arg], _CoroutineWrapper):
185-
wrapper = funcargs[arg]
186-
187-
if wrapper.mark == 'async_fixture':
188-
arg_value = yield defer.ensureDeferred(
189-
wrapper.coroutine
190-
)
191-
elif wrapper.mark == 'async_yield_fixture':
192-
async_generators.append((arg, wrapper))
193-
arg_value = yield defer.ensureDeferred(
194-
wrapper.coroutine.__anext__(),
195-
)
196-
else:
197-
raise UnrecognizedCoroutineMarkError.from_mark(
198-
mark=wrapper.mark,
199-
)
177+
funcargs = pyfuncitem.funcargs
178+
if hasattr(pyfuncitem, "_fixtureinfo"):
179+
testargs = {}
180+
for arg in pyfuncitem._fixtureinfo.argnames:
181+
if isinstance(funcargs[arg], _CoroutineWrapper):
182+
wrapper = funcargs[arg]
183+
184+
if wrapper.mark == 'async_fixture':
185+
arg_value = yield defer.ensureDeferred(
186+
wrapper.coroutine
187+
)
188+
elif wrapper.mark == 'async_yield_fixture':
189+
async_generators.append((arg, wrapper))
190+
arg_value = yield defer.ensureDeferred(
191+
wrapper.coroutine.__anext__(),
192+
)
200193
else:
201-
arg_value = funcargs[arg]
194+
raise UnrecognizedCoroutineMarkError.from_mark(
195+
mark=wrapper.mark,
196+
)
197+
else:
198+
arg_value = funcargs[arg]
199+
200+
testargs[arg] = arg_value
201+
else:
202+
testargs = funcargs
203+
result = yield testfunction(**testargs)
202204

203-
testargs[arg] = arg_value
205+
async_generator_deferreds = [
206+
(arg, defer.ensureDeferred(g.coroutine.__anext__()))
207+
for arg, g in reversed(async_generators)
208+
]
209+
210+
for arg, d in async_generator_deferreds:
211+
try:
212+
yield d
213+
except StopAsyncIteration:
214+
continue
204215
else:
205-
testargs = funcargs
206-
result = yield testfunction(**testargs)
207-
208-
async_generator_deferreds = [
209-
(arg, defer.ensureDeferred(g.coroutine.__anext__()))
210-
for arg, g in reversed(async_generators)
211-
]
212-
213-
for arg, d in async_generator_deferreds:
214-
try:
215-
yield d
216-
except StopAsyncIteration:
217-
continue
218-
else:
219-
raise AsyncGeneratorFixtureDidNotStopError.from_generator(
220-
generator=arg,
221-
)
216+
raise AsyncGeneratorFixtureDidNotStopError.from_generator(
217+
generator=arg,
218+
)
222219

223-
defer.returnValue(result)
220+
defer.returnValue(result)
224221

225222

226223
def pytest_pyfunc_call(pyfuncitem):
@@ -274,9 +271,19 @@ def init_qt5_reactor():
274271
)
275272

276273

274+
def init_asyncio_reactor():
275+
from twisted.internet import asyncioreactor
276+
277+
_install_reactor(
278+
reactor_installer=asyncioreactor.install,
279+
reactor_type=asyncioreactor.AsyncioSelectorReactor,
280+
)
281+
282+
277283
reactor_installers = {
278284
"default": init_default_reactor,
279285
"qt5reactor": init_qt5_reactor,
286+
"asyncio": init_asyncio_reactor,
280287
}
281288

282289

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55

66
setup(
77
name="pytest-twisted",
8-
version="1.8",
8+
version="1.11",
99
description="A twisted plugin for py.test.",
1010
long_description=long_description,
11+
long_description_content_type="text/x-rst",
1112
author="Ralf Schmitt, Kyle Altendorf, Victor Titor",
1213
author_email="[email protected]",
1314
url="https://github.com/pytest-dev/pytest-twisted",
@@ -24,7 +25,6 @@
2425
"Programming Language :: Python :: 2",
2526
"Programming Language :: Python :: 2.7",
2627
"Programming Language :: Python :: 3",
27-
"Programming Language :: Python :: 3.4",
2828
"Programming Language :: Python :: 3.5",
2929
"Programming Language :: Python :: 3.6",
3030
"Programming Language :: Python :: 3.7",

testing/test_basic.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
import pytest
55

6-
import pytest_twisted
7-
86

97
# https://docs.python.org/3/whatsnew/3.5.html#pep-492-coroutines-with-async-and-await-syntax
108
ASYNC_AWAIT = sys.version_info >= (3, 5)
@@ -41,7 +39,9 @@ def format_run_result_output_for_assert(run_result):
4139
def skip_if_reactor_not(request, expected_reactor):
4240
actual_reactor = request.config.getoption("reactor", "default")
4341
if actual_reactor != expected_reactor:
44-
pytest.skip("reactor is {} not {}".format(actual_reactor, expected_reactor))
42+
pytest.skip(
43+
"reactor is {} not {}".format(actual_reactor, expected_reactor),
44+
)
4545

4646

4747
def skip_if_no_async_await():
@@ -609,3 +609,49 @@ def main():
609609
assert_outcomes(rr, {"passed": 1, "failed": 1})
610610
# test embedded mode:
611611
assert testdir.run(sys.executable, "runner.py").ret == 0
612+
613+
614+
def test_blockon_in_hook_with_asyncio(testdir, cmd_opts, request):
615+
skip_if_reactor_not(request, "asyncio")
616+
conftest_file = """
617+
import pytest_twisted as pt
618+
from twisted.internet import defer
619+
620+
def pytest_configure(config):
621+
pt.init_asyncio_reactor()
622+
d = defer.Deferred()
623+
624+
from twisted.internet import reactor
625+
626+
reactor.callLater(0.01, d.callback, 1)
627+
pt.blockon(d)
628+
"""
629+
testdir.makeconftest(conftest_file)
630+
test_file = """
631+
from twisted.internet import reactor, defer
632+
633+
def test_succeed():
634+
d = defer.Deferred()
635+
reactor.callLater(0.01, d.callback, 1)
636+
return d
637+
"""
638+
testdir.makepyfile(test_file)
639+
rr = testdir.run(sys.executable, "-m", "pytest", "-v", *cmd_opts)
640+
assert_outcomes(rr, {"passed": 1})
641+
642+
643+
def test_wrong_reactor_with_asyncio(testdir, cmd_opts, request):
644+
skip_if_reactor_not(request, "asyncio")
645+
conftest_file = """
646+
def pytest_addhooks():
647+
import twisted.internet.default
648+
twisted.internet.default.install()
649+
"""
650+
testdir.makeconftest(conftest_file)
651+
test_file = """
652+
def test_succeed():
653+
pass
654+
"""
655+
testdir.makepyfile(test_file)
656+
rr = testdir.run(sys.executable, "-m", "pytest", "-v", *cmd_opts)
657+
assert "WrongReactorAlreadyInstalledError" in rr.stderr.str()

tox.ini

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[tox]
22
envlist=
3-
py{27,34}-defaultreactor
4-
py{35,36,37}-{default,qt5}reactor
3+
py{27,35}-defaultreactor
4+
py{35,36,37}-{default,qt5,asyncio}reactor
55
win-py{35,36,37}-qt5reactor
66
linting
77

@@ -18,6 +18,7 @@ deps=
1818
commands=
1919
defaultreactor: pytest --reactor=default
2020
qt5reactor: pytest --reactor=qt5reactor
21+
asyncioreactor: pytest --reactor=asyncio
2122
sitepackages=False
2223

2324
[testenv:linting]

0 commit comments

Comments
 (0)