eukaryote / pytest-tornasync Goto Github PK
View Code? Open in Web Editor NEWA pytest plugin for testing Tornado (version 5.0 or newer) apps using plain (undecoratored) native coroutine tests.
License: MIT License
A pytest plugin for testing Tornado (version 5.0 or newer) apps using plain (undecoratored) native coroutine tests.
License: MIT License
According to https://pypi.org/project/pytest-tornasync/ latest version is 0.6.0.post2.
However looks like some changes not been commited here (of git repo not pushed) an there is no version git tags.
Is it possible to add missing bots to git repo?
Thx.
Hi,
thank you for this great package!
Is there a way to parametrize the creation of the app, depending on the test? I might have something like
@pytest.fixture
def app(database):
import yourapp
return yourapp.make_app(database) # a tornado.web.Application
def test_app_with_mock_db(http_server_client): # how to inject database here?
resp = await http_server_client.fetch('/')
assert resp.code == 200
Currently there are no github tags for releases. Would it be possible to add them?
Tags have the advantage over sdists that they include all files from the git repo, not just those chosen for the sdist. In this case, where the test files are not included in sdists (see #8), having the tags makes it feasible for downstream packagers to download a complete version of the sources.
Hello,
The last version is available only on wheels, would it be possible to upload sdist
files as well?
Packagers (like conda) need the sdist file to generate their packages.
Here's the output I'm getting when running the test suite:
.../pytest-tornasync $ pytest-3
============================= test session starts ==============================
platform linux -- Python 3.9.1+, pytest-6.0.2, py-1.10.0, pluggy-0.13.0
PyQt5 5.15.2 -- Qt runtime 5.15.2 -- Qt compiled 5.15.2
rootdir: /home/jdg/debian/spyder-packages/pytest-tornasync/build-area/pytest-tornasync-0.6.0+git20190716.9f1bdee, configfile: pytest.ini, testpaths: test
plugins: lazy-fixture-0.5.1, hypothesis-5.43.3, qt-3.2.2, anyio-0.0.0, mock-1.10.4, timeout-1.4.1, cov-2.10.1, xvfb-1.2.0, flaky-3.7.0
collected 10 items
test/test_plugin.py ..EEExsE
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File "/usr/lib/python3/dist-packages/_pytest/main.py", line 240, in wrap_session
INTERNALERROR> session.exitstatus = doit(config, session) or 0
INTERNALERROR> File "/usr/lib/python3/dist-packages/_pytest/main.py", line 296, in _main
INTERNALERROR> config.hook.pytest_runtestloop(session=session)
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR> return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/manager.py", line 92, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/manager.py", line 83, in <lambda>
INTERNALERROR> self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File "/usr/lib/python3/dist-packages/_pytest/main.py", line 321, in pytest_runtestloop
INTERNALERROR> item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR> return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/manager.py", line 92, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/manager.py", line 83, in <lambda>
INTERNALERROR> self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "/usr/lib/python3/dist-packages/pluggy/callers.py", line 182, in _multicall
INTERNALERROR> next(gen) # first yield
INTERNALERROR> File "/usr/lib/python3/dist-packages/pytest_timeout.py", line 102, in pytest_runtest_protocol
INTERNALERROR> func_only = get_func_only_setting(item)
INTERNALERROR> File "/usr/lib/python3/dist-packages/pytest_timeout.py", line 264, in get_func_only_setting
INTERNALERROR> settings = get_params(item, marker=marker)
INTERNALERROR> File "/usr/lib/python3/dist-packages/pytest_timeout.py", line 279, in get_params
INTERNALERROR> settings = _parse_marker(item.get_closest_marker(name="timeout"))
INTERNALERROR> File "/usr/lib/python3/dist-packages/pytest_timeout.py", line 309, in _parse_marker
INTERNALERROR> raise TypeError("Invalid keyword argument for timeout marker: %s" % kw)
INTERNALERROR> TypeError: Invalid keyword argument for timeout marker: seconds
======== 2 passed, 1 skipped, 1 xfailed, 2 warnings, 4 errors in 0.04s =========
It looks as though it may be interpreting @pytest.mark.timeout(seconds=10)
using the pytest-timeout
plugin rather than your plugin. Any suggestions?
Thanks!
Hi,
Recently we've found out an issue in our tests. It works with 3.6.1, but it breaks using 3.6.2.
We've tried to distill a minimal example to reproduce the issue. Any ideas on how to fix it?
import asyncio
import functools
import pytest
from tornado.web import RequestHandler
class TimeoutClient:
def __init__(self, http_client):
self.http_client = http_client
async def request(self, *args, **kwargs):
async with self.http_client.request(*args, **kwargs) as response:
await response.text()
return response
@pytest.fixture(scope='function')
def timeoutclient(aiohttp_client):
return TimeoutClient(http_client=aiohttp_client)
def asyncio_compat(func):
"""
Compatibility decorator for using asyncio-based libraries inside Tornado.
More info: https://github.com/aio-libs/aiohttp/issues/1180#issuecomment-247701597
"""
@functools.wraps(func)
async def wrapper(*args, **kwargs):
return await asyncio.get_event_loop().create_task(func(*args, **kwargs))
return wrapper
class TestBaseClient:
@asyncio_compat
async def test_timeout_response(self, timeoutclient, app, test_base_url):
class TimeoutHandler(RequestHandler):
@asyncio_compat
async def get(self):
await asyncio.sleep(10)
app.add_handlers(r".*", [
("/timeout", TimeoutHandler),
])
with pytest.raises(asyncio.TimeoutError):
await timeoutclient.request('GET', f'{test_base_url}/timeout', timeout=0.1)
I wanted to test that a redirect was setup correctly, so I went for something like:
import pytest
import tornado.web
class RedirecterHandler(tornado.web.RequestHandler):
async def get(self):
self.redirect('/')
class MainHandler(tornado.web.RequestHandler):
async def get(self):
self.finish('Welcome!')
@pytest.fixture
def app():
return tornado.web.Application([
(r"/", MainHandler),
(r"/redirect_me", RedirecterHandler),
])
async def test_http_server_client(http_server_client):
resp = await http_server_client.fetch('/redirect_me')
assert resp.code == 302
But unfortunately the fetch call never returns. I suspect there is a deadlock somewhere.
For what it is worth, my workaround is to do something like:
resp = await http_server_client.fetch('/redirect_me', max_redirects=0, raise_error=False)
assert resp.code == 302
assert resp.headers['Location'] == "/"
When running tests in a project that doesn't have pytest-tornasync as a dependency, with pytest-asyncio 0.17.2 and asyncio_mode = auto
in pytest.ini
, I get failures after removing @pytest.mark.asyncio
decorators from my tests.
pyfuncitem = <Function test_something>
@pytest.mark.tryfirst
def pytest_pyfunc_call(pyfuncitem):
funcargs = pyfuncitem.funcargs
testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames}
if not iscoroutinefunction(pyfuncitem.obj):
pyfuncitem.obj(**testargs)
return True
try:
> loop = funcargs["io_loop"]
E KeyError: 'io_loop'
~/.conda/envs/myenv/lib/python3.9/site-packages/pytest_tornasync/plugin.py:49: KeyError
During handling of the above exception, another exception occurred:
pyfuncitem = <Function test_something>
@pytest.mark.tryfirst
def pytest_pyfunc_call(pyfuncitem):
funcargs = pyfuncitem.funcargs
testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames}
if not iscoroutinefunction(pyfuncitem.obj):
pyfuncitem.obj(**testargs)
return True
try:
loop = funcargs["io_loop"]
except KeyError:
> loop = tornado.ioloop.IOLoop.current()
~/.conda/envs/myenv/lib/python3.9/site-packages/pytest_tornasync/plugin.py:51:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
~/.conda/envs/myenv/lib/python3.9/site-packages/tornado/ioloop.py:263: in current
loop = asyncio.get_event_loop()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <asyncio.unix_events._UnixDefaultEventLoopPolicy object at 0x7fcc51c39760>
def get_event_loop(self):
"""Get the event loop for the current context.
Returns an instance of EventLoop or raises an exception.
"""
if (self._local._loop is None and
not self._local._set_called and
threading.current_thread() is threading.main_thread()):
self.set_event_loop(self.new_event_loop())
if self._local._loop is None:
> raise RuntimeError('There is no current event loop in thread %r.'
% threading.current_thread().name)
E RuntimeError: There is no current event loop in thread 'MainThread'.
~/.conda/envs/myenv/lib/python3.9/asyncio/events.py:642: RuntimeError
=========================================================================================== ERRORS ===========================================================================================
____________________________________________________________________________ ERROR collecting test/test_plugin.py ____________________________________________________________________________
ImportError while importing test module '/disk-samsung/freebsd-ports/devel/py-pytest-tornasync/work-py39/pytest-tornasync-0.6.0.post2/test/test_plugin.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/local/lib/python3.9/importlib/__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
test/test_plugin.py:9: in <module>
from test import MESSAGE, PAUSE_TIME
E ImportError: cannot import name 'MESSAGE' from 'test' (/usr/local/lib/python3.9/test/__init__.py)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
====================================================================================== 1 error in 0.45s ======================================================================================
*** Error code 2
Version: 0.6.0.post2
Python-3.9
FreeBSD 13.1 STABLE
The last version tar.gz does not contain the LICENSE, would it be possible to upload together on tar.gz?
Packagers (like conda) need the LICENSE file to generate their packages.
With tornado version 6.2
there are some warnings on the terminal when running the tests:
/Users/user/.pyenv/versions/3.9.6/envs/cara/lib/python3.9/site-packages/pytest_tornasync/plugin.py:67: DeprecationWarning: clear_current is deprecated
loop.clear_current()
My guess is that this warning is coming from
.I need to shutdown something after test, like aioredis
, currently I can do
@pytest.fixture(scope='function')
def app(io_loop) -> Application:
app_ = tornado_app.make_app()
yield app_
app_.settings['redis'].close()
io_loop.run_sync(app_.settings['auth'].wait_closed)
but I want to use only one app across my tests, how can I do something like
@pytest.fixture(scope='session')
def app(global_loop) -> Application:
app_ = tornado_app.make_app()
yield app_
app_.settings['auth'].close()
global_loop.run_sync(app_.settings['auth'].wait_closed)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.