Giter Club home page Giter Club logo

Comments (12)

Dreamsorcerer avatar Dreamsorcerer commented on May 24, 2024
aiohttp.web_exceptions.NotAppKeyWarning: It is recommended to use web.AppKey instances for keys.
https://docs.aiohttp.org/en/stable/web_advanced.html#application-s-config

Trivially fixable if you'd like to make a contribution. Though I'd also like to know why this isn't reproducing in our CI. The test appears to be passing: https://github.com/aio-libs/aiohttp/actions/runs/8210202661/job/22457206363#step:11:1653

from aiohttp.

ncopa avatar ncopa commented on May 24, 2024

Trivially fixable if you'd like to make a contribution.

I actually tried. Spent half an hour on it or so, without great success. It was somewhat complicated due to it is a nested test, a pytest that tests another pytest.

Its not that I don't want to contribute, but I figured someone who are more familiar with the code would do it in significantly less time than me.

Though I'd also like to know why this isn't reproducing in our CI. The test appears to be passing: https://github.com/aio-libs/aiohttp/actions/runs/8210202661/job/22457206363#step:11:1653

Exactly! I noticed that too and found it weird. What version of pytest are you using? I have bumped in several cases where pytest-8 breaks things.

(I am in the process of updating python to 3.12 for Alpine Linux. 1375 python packages left to build. Today I was able to rebuild ~58. I calculated that it will take me 24 days with current speed if I am able to spend 100% of my time on this.)

from aiohttp.

webknjaz avatar webknjaz commented on May 24, 2024

What version of pytest are you using?

The linked CI log says it's 8.0.2:
https://github.com/aio-libs/aiohttp/actions/runs/8210202661/job/22457206363#step:11:19.

We don't touch that code often so it's unlike it'll be faster for us to fix.

Anyway, are you able to provide a minimum reproducer with an Alpine container or something like that? It may have clues to what's different. Like maybe you have a Pure-python build w/o C-extensions or something..

from aiohttp.

webknjaz avatar webknjaz commented on May 24, 2024

FWIW it's probably the filterwarnings setting or equivalent that is turning warnings to errors. Not sure why, though.

Also, don't we have 3.9.4 already?

from aiohttp.

Dreamsorcerer avatar Dreamsorcerer commented on May 24, 2024

I actually tried. Spent half an hour on it or so, without great success. It was somewhat complicated due to it is a nested test, a pytest that tests another pytest.

Huh, it should just be replacing the strings as per the documentation linked in the warning.

At a glance, it's just 'value' used in 2 places, which would need to be replaced with an AppKey:
value_key = web.AppKey("value_key", str)
So, just define that as a global and replace 'value' with value_key:

request.app['value'] = (await request.post())['value']
return web.Response(body=b'thanks for the data')
else:
v = request.app.get('value', 'unknown')

Only problem with me making the change is that I can't see the error in the first place to confirm it's fixed.

Also, don't we have 3.9.4 already?

Uh, no, I was partly waiting on another fix to merge and partly got caught up with other things. Will make the release next week.

from aiohttp.

ncopa avatar ncopa commented on May 24, 2024

I think problem is related pytest 8, which changes how warnings are handled.

As I read the test, it is checking that warnings are raised?

with pytest.warns(DeprecationWarning):

from aiohttp.

ncopa avatar ncopa commented on May 24, 2024
diff --git a/tests/test_pytest_plugin.py b/tests/test_pytest_plugin.py
index b25a553..5faa254 100644
--- a/tests/test_pytest_plugin.py
+++ b/tests/test_pytest_plugin.py
@@ -73,9 +73,10 @@ async def test_noop() -> None:
 
 
 async def previous(request):
+    value_key = web.AppKey("value", str)
     if request.method == 'POST':
         with pytest.deprecated_call():  # FIXME: this isn't actually called
-            request.app['value'] = (await request.post())['value']
+            request.app[value_key] = (await request.post())[value_key]
         return web.Response(body=b'thanks for the data')
     else:
         v = request.app.get('value', 'unknown')

The result is:

$ PYTHONPATH="$(echo 
build/lib.*)" pytest --no-cov --ignore tests/autobahn/test_autobahn.py --ignore tests/test_proxy_fun
ctional.py -k "test_aiohttp_plugin" -vvv
======================================= test session starts ========================================
platform linux -- Python 3.11.8, pytest-8.0.2, pluggy-1.4.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ncopa/aports/community/py3-aiohttp/src/aiohttp-3.9.3
configfile: setup.cfg
testpaths: tests/
plugins: cov-4.1.0, xdist-3.5.0, mock-3.10.0, requests-mock-1.11.0
collected 3079 items / 3076 deselected / 3 selected                                                

tests/test_pytest_plugin.py::test_aiohttp_plugin FAILED                                      [ 33%]
tests/test_pytest_plugin.py::test_aiohttp_plugin_async_fixture PASSED                        [ 66%]
tests/test_pytest_plugin.py::test_aiohttp_plugin_async_gen_fixture PASSED                    [100%]

============================================= FAILURES =============================================
_______________________________________ test_aiohttp_plugin ________________________________________

testdir = <Testdir local('/tmp/pytest-of-ncopa/pytest-43/test_aiohttp_plugin0')>

    def test_aiohttp_plugin(testdir) -> None:
        testdir.makepyfile(
            """\
    import pytest
    from unittest import mock
    
    from aiohttp import web
    
    
    async def hello(request):
        return web.Response(body=b'Hello, world')
    
    
    def create_app(loop=None):
        app = web.Application()
        app.router.add_route('GET', '/', hello)
        return app
    
    
    async def test_hello(aiohttp_client) -> None:
        client = await aiohttp_client(create_app)
        resp = await client.get('/')
        assert resp.status == 200
        text = await resp.text()
        assert 'Hello, world' in text
    
    
    async def test_hello_from_app(aiohttp_client, loop) -> None:
        app = web.Application()
        app.router.add_get('/', hello)
        client = await aiohttp_client(app)
        resp = await client.get('/')
        assert resp.status == 200
        text = await resp.text()
        assert 'Hello, world' in text
    
    
    async def test_hello_with_loop(aiohttp_client, loop) -> None:
        client = await aiohttp_client(create_app)
        resp = await client.get('/')
        assert resp.status == 200
        text = await resp.text()
        assert 'Hello, world' in text
    
    
    async def test_set_args(aiohttp_client, loop) -> None:
        with pytest.raises(AssertionError):
            app = web.Application()
            await aiohttp_client(app, 1, 2, 3)
    
    
    async def test_set_keyword_args(aiohttp_client, loop) -> None:
        app = web.Application()
        with pytest.raises(TypeError):
            await aiohttp_client(app, param=1)
    
    
    async def test_noop() -> None:
        pass
    
    
    async def previous(request):
        value_key = web.AppKey("value", str)
        if request.method == 'POST':
            with pytest.deprecated_call():  # FIXME: this isn't actually called
                request.app[value_key] = (await request.post())[value_key]
            return web.Response(body=b'thanks for the data')
        else:
            v = request.app.get('value', 'unknown')
            return web.Response(body='value: {}'.format(v).encode())
    
    
    def create_stateful_app(loop):
        app = web.Application()
        app.router.add_route('*', '/', previous)
        return app
    
    
    @pytest.fixture
    def cli(loop, aiohttp_client):
        return loop.run_until_complete(aiohttp_client(create_stateful_app))
    
    
    async def test_set_value(cli) -> None:
        resp = await cli.post('/', data={'value': 'foo'})
        assert resp.status == 200
        text = await resp.text()
        assert text == 'thanks for the data'
        assert cli.server.app['value'] == 'foo'
    
    
    async def test_get_value(cli) -> None:
        resp = await cli.get('/')
        assert resp.status == 200
        text = await resp.text()
        assert text == 'value: unknown'
        with pytest.warns(DeprecationWarning):
            cli.server.app['value'] = 'bar'
        resp = await cli.get('/')
        assert resp.status == 200
        text = await resp.text()
        assert text == 'value: bar'
    
    
    def test_noncoro() -> None:
        assert True
    
    
    async def test_failed_to_create_client(aiohttp_client) -> None:
    
        def make_app(loop):
            raise RuntimeError()
    
        with pytest.raises(RuntimeError):
            await aiohttp_client(make_app)
    
    
    async def test_custom_port_aiohttp_client(aiohttp_client, aiohttp_unused_port):
        port = aiohttp_unused_port()
        client = await aiohttp_client(create_app, server_kwargs={'port': port})
        assert client.port == port
        resp = await client.get('/')
        assert resp.status == 200
        text = await resp.text()
        assert 'Hello, world' in text
    
    
    async def test_custom_port_test_server(aiohttp_server, aiohttp_unused_port):
        app = create_app()
        port = aiohttp_unused_port()
        server = await aiohttp_server(app, port=port)
        assert server.port == port
    
    """
        )
        testdir.makeconftest(CONFTEST)
        result = testdir.runpytest("-p", "no:sugar", "--aiohttp-loop=pyloop")
>       result.assert_outcomes(passed=12)
E       AssertionError: assert {'passed': 10, 'skipped': 0, 'failed': 2, 'errors': 0, 'xpassed': 0, 'xfailed': 0} == {'passed': 12, 'skipped': 0, 'failed': 0, 'errors': 0, 'xpassed': 0, 'xfailed': 0}
E         
E         Common items:
E         {'errors': 0, 'skipped': 0, 'xfailed': 0, 'xpassed': 0}
E         Differing items:
E         {'failed': 2} != {'failed': 0}
E         {'passed': 10} != {'passed': 12}
E         
E         Full diff:
E           {
E               'errors': 0,
E         -     'failed': 0,
E         ?               ^
E         +     'failed': 2,
E         ?               ^
E         -     'passed': 12,
E         ?                ^
E         +     'passed': 10,
E         ?                ^
E               'skipped': 0,
E               'xfailed': 0,
E               'xpassed': 0,
E           }

result     = <RunResult ret=1 len(stdout.lines)=55 len(stderr.lines)=0 duration=0.17s>
testdir    = <Testdir local('/tmp/pytest-of-ncopa/pytest-43/test_aiohttp_plugin0')>

/home/ncopa/aports/community/py3-aiohttp/src/aiohttp-3.9.3/tests/test_pytest_plugin.py:151: AssertionError
--------------------------------------- Captured stdout call ---------------------------------------
============================= test session starts ==============================
platform linux -- Python 3.11.8, pytest-8.0.2, pluggy-1.4.0
rootdir: /tmp/pytest-of-ncopa/pytest-43/test_aiohttp_plugin0
plugins: cov-4.1.0, xdist-3.5.0, mock-3.10.0, requests-mock-1.11.0
collected 12 items

test_aiohttp_plugin.py ......FF....                                      [100%]

=================================== FAILURES ===================================
____________________________ test_set_value[pyloop] ____________________________

cli = <aiohttp.test_utils.TestClient object at 0x7f86b1afc3d0>

    async def test_set_value(cli) -> None:
>       resp = await cli.post('/', data={'value': 'foo'})

test_aiohttp_plugin.py:82: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/home/ncopa/aports/community/py3-aiohttp/src/aiohttp-3.9.3/build/lib.linux-x86_64-cpython-311/aiohttp/test_utils.py:322: in _request
    resp = await self._session.request(method, self.make_url(path), **kwargs)
/home/ncopa/aports/community/py3-aiohttp/src/aiohttp-3.9.3/build/lib.linux-x86_64-cpython-311/aiohttp/client.py:605: in _request
    await resp.start(conn)
/home/ncopa/aports/community/py3-aiohttp/src/aiohttp-3.9.3/build/lib.linux-x86_64-cpython-311/aiohttp/client_reqrep.py:966: in start
    message, payload = await protocol.read()  # type: ignore[union-attr]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <aiohttp.client_proto.ResponseHandler object at 0x7f86b1a55080>

    async def read(self) -> _T:
        if not self._buffer and not self._eof:
            assert not self._waiter
            self._waiter = self._loop.create_future()
            try:
>               await self._waiter
E               aiohttp.client_exceptions.ServerDisconnectedError: Server disconnected

/home/ncopa/aports/community/py3-aiohttp/src/aiohttp-3.9.3/build/lib.linux-x86_64-cpython-311/aiohttp/streams.py:622: ServerDisconnectedError
____________________________ test_get_value[pyloop] ____________________________

cli = <aiohttp.test_utils.TestClient object at 0x7f86b16fc7d0>

    async def test_get_value(cli) -> None:
        resp = await cli.get('/')
        assert resp.status == 200
        text = await resp.text()
        assert text == 'value: unknown'
>       with pytest.warns(DeprecationWarning):
E       aiohttp.web_exceptions.NotAppKeyWarning: It is recommended to use web.AppKey instances for keys.
E       https://docs.aiohttp.org/en/stable/web_advanced.html#application-s-config

test_aiohttp_plugin.py:94: NotAppKeyWarning
=========================== short test summary info ============================
FAILED test_aiohttp_plugin.py::test_set_value[pyloop] - aiohttp.client_except...
FAILED test_aiohttp_plugin.py::test_get_value[pyloop] - aiohttp.web_exception...
========================= 2 failed, 10 passed in 0.16s =========================
======================================= slowest 10 durations =======================================
0.17s call     tests/test_pytest_plugin.py::test_aiohttp_plugin
0.06s call     tests/test_pytest_plugin.py::test_aiohttp_plugin_async_fixture
0.03s call     tests/test_pytest_plugin.py::test_aiohttp_plugin_async_gen_fixture
0.00s setup    tests/test_pytest_plugin.py::test_aiohttp_plugin
0.00s setup    tests/test_pytest_plugin.py::test_aiohttp_plugin_async_fixture
0.00s setup    tests/test_pytest_plugin.py::test_aiohttp_plugin_async_gen_fixture
0.00s teardown tests/test_pytest_plugin.py::test_aiohttp_plugin
0.00s teardown tests/test_pytest_plugin.py::test_aiohttp_plugin_async_gen_fixture
0.00s teardown tests/test_pytest_plugin.py::test_aiohttp_plugin_async_fixture
===================================== short test summary info ======================================
FAILED tests/test_pytest_plugin.py::test_aiohttp_plugin - AssertionError: assert {'passed': 10, 'skipped': 0, 'failed': 2, 'errors': 0, 'xpassed': 0, 'xf...
=========================== 1 failed, 2 passed, 3076 deselected in 0.56s ===========================

from aiohttp.

Dreamsorcerer avatar Dreamsorcerer commented on May 24, 2024

I think problem is related pytest 8, which changes how warnings are handled.

Right, not clear what's changed, but this is reproducing in the Dependabot PR: #8223
So, that gives us somewhere to reproduce.

As I read the test, it is checking that warnings are raised?

No, that line long predates AppKey: https://github.com/aio-libs/aiohttp/blame/77f5633ce02da71c6879d3b25b5fbe8b240647c6/tests/test_pytest_plugin.py#L107
The AppKey warning is also not a DeprecationWarning, so it should never have caught it before.
I suspect the runpytest() thing that these tests are using never errored on warnings with previous versions of pytest.

from aiohttp.

Dreamsorcerer avatar Dreamsorcerer commented on May 24, 2024

Oh, also, the tests are passing in current pytest on master. So, there must be some difference with 3.x.

from aiohttp.

ncopa avatar ncopa commented on May 24, 2024

I don't see any test_get_value or test_set_value in master branch.

from aiohttp.

Dreamsorcerer avatar Dreamsorcerer commented on May 24, 2024

OK, will take a look next week, I'm away for the next few days.

from aiohttp.

ncopa avatar ncopa commented on May 24, 2024

Thank you! Enjoy!

from aiohttp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.