https://github.com/httpie/cli/commit/3524ccf0baa9f2b3029368ab07ba5f64e62dcb1f https://github.com/httpie/cli/commit/db16bbee961ceb93b7831fe1ec44a72d56a33e38 From 3524ccf0baa9f2b3029368ab07ba5f64e62dcb1f Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 4 Mar 2024 16:27:52 +0100 Subject: [PATCH] Drop dependency on the abandoned python-lazy-fixture --- a/setup.py +++ b/setup.py @@ -11,7 +11,6 @@ tests_require = [ 'pytest', 'pytest-httpbin>=0.0.6', - 'pytest-lazy-fixture>=0.0.6', 'responses', 'pytest-mock', 'werkzeug<2.1.0' --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,14 +3,14 @@ import pytest from pytest_httpbin import certs -from .utils import ( # noqa +from .utils import ( # noqa HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, HTTPBIN_WITH_CHUNKED_SUPPORT, REMOTE_HTTPBIN_DOMAIN, IS_PYOPENSSL, mock_env ) -from .utils.plugins_cli import ( # noqa +from .utils.plugins_cli import ( # noqa broken_plugin, dummy_plugin, dummy_plugins, @@ -18,7 +18,9 @@ httpie_plugins_success, interface, ) -from .utils.http_server import http_server, localhost_http_server # noqa +from .utils.http_server import http_server, localhost_http_server # noqa +# noinspection PyUnresolvedReferences +from .fixtures import pytest_lazy_fixture @pytest.fixture(scope='function', autouse=True) --- /dev/null +++ b/tests/fixtures/pytest_lazy_fixture.py @@ -0,0 +1,99 @@ +""" +Replacement for the abandoned `pytest.lazy_fixture` + +Based on + +""" +import dataclasses +import typing + +import pytest + + +@dataclasses.dataclass +class LazyFixture: + """Lazy fixture dataclass.""" + + name: str + + +def lazy_fixture(name: str) -> LazyFixture: + """Mark a fixture as lazy.""" + return LazyFixture(name) + + +# NOTE: Mimic the original API +pytest.lazy_fixture = lazy_fixture + + +def is_lazy_fixture(value: object) -> bool: + """Check whether a value is a lazy fixture.""" + return isinstance(value, LazyFixture) + + +def pytest_make_parametrize_id( + config: pytest.Config, + val: object, + argname: str, +) -> str | None: + """Inject lazy fixture parametrized id. + + Reference: + - https://bit.ly/48Off6r + + Args: + config (pytest.Config): pytest configuration. + value (object): fixture value. + argname (str): automatic parameter name. + + Returns: + str: new parameter id. + """ + if is_lazy_fixture(val): + return typing.cast(LazyFixture, val).name + return None + + +@pytest.hookimpl(tryfirst=True) +def pytest_fixture_setup( + fixturedef: pytest.FixtureDef, + request: pytest.FixtureRequest, +) -> object | None: + """Lazy fixture setup hook. + + This hook will never take over a fixture setup but just simply will + try to resolve recursively any lazy fixture found in request.param. + + Reference: + - https://bit.ly/3SyvsXJ + + Args: + fixturedef (pytest.FixtureDef): fixture definition object. + request (pytest.FixtureRequest): fixture request object. + + Returns: + object | None: fixture value or None otherwise. + """ + if hasattr(request, "param") and request.param: + request.param = _resolve_lazy_fixture(request.param, request) + return None + + +def _resolve_lazy_fixture(__val: object, request: pytest.FixtureRequest) -> object: + """Lazy fixture resolver. + + Args: + __val (object): fixture value object. + request (pytest.FixtureRequest): pytest fixture request object. + + Returns: + object: resolved fixture value. + """ + if isinstance(__val, list | tuple): + return tuple(_resolve_lazy_fixture(v, request) for v in __val) + if isinstance(__val, typing.Mapping): + return {k: _resolve_lazy_fixture(v, request) for k, v in __val.items()} + if not is_lazy_fixture(__val): + return __val + lazy_obj = typing.cast(LazyFixture, __val) + return request.getfixturevalue(lazy_obj.name) From db16bbee961ceb93b7831fe1ec44a72d56a33e38 Mon Sep 17 00:00:00 2001 From: Jakub Roztocil Date: Mon, 4 Mar 2024 18:05:26 +0100 Subject: [PATCH] Drop dependency on the abandoned python-lazy-fixture II. --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ import pytest from pytest_httpbin import certs +from pytest_httpbin.serve import Server as PyTestHttpBinServer from .utils import ( # noqa HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, @@ -19,8 +20,10 @@ interface, ) from .utils.http_server import http_server, localhost_http_server # noqa -# noinspection PyUnresolvedReferences -from .fixtures import pytest_lazy_fixture + + +# Patch to support `url = str(server)` in addition to `url = server + '/foo'`. +PyTestHttpBinServer.__str__ = lambda self: self.url @pytest.fixture(scope='function', autouse=True) @@ -72,8 +75,15 @@ def _remote_httpbin_available(): @pytest.fixture def remote_httpbin(_remote_httpbin_available): + if _remote_httpbin_available: - return 'http://' + REMOTE_HTTPBIN_DOMAIN + class Server(str): + """Look like `pytest_httpbin.serve.Server` but only provide URL info.""" + @property + def url(self): + return self + + return Server('http://' + REMOTE_HTTPBIN_DOMAIN) pytest.skip(f'{REMOTE_HTTPBIN_DOMAIN} not resolvable') --- a/tests/fixtures/pytest_lazy_fixture.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -Replacement for the abandoned `pytest.lazy_fixture` - -Based on - -""" -import dataclasses -import typing - -import pytest - - -@dataclasses.dataclass -class LazyFixture: - """Lazy fixture dataclass.""" - - name: str - - -def lazy_fixture(name: str) -> LazyFixture: - """Mark a fixture as lazy.""" - return LazyFixture(name) - - -# NOTE: Mimic the original API -pytest.lazy_fixture = lazy_fixture - - -def is_lazy_fixture(value: object) -> bool: - """Check whether a value is a lazy fixture.""" - return isinstance(value, LazyFixture) - - -def pytest_make_parametrize_id( - config: pytest.Config, - val: object, - argname: str, -) -> str | None: - """Inject lazy fixture parametrized id. - - Reference: - - https://bit.ly/48Off6r - - Args: - config (pytest.Config): pytest configuration. - value (object): fixture value. - argname (str): automatic parameter name. - - Returns: - str: new parameter id. - """ - if is_lazy_fixture(val): - return typing.cast(LazyFixture, val).name - return None - - -@pytest.hookimpl(tryfirst=True) -def pytest_fixture_setup( - fixturedef: pytest.FixtureDef, - request: pytest.FixtureRequest, -) -> object | None: - """Lazy fixture setup hook. - - This hook will never take over a fixture setup but just simply will - try to resolve recursively any lazy fixture found in request.param. - - Reference: - - https://bit.ly/3SyvsXJ - - Args: - fixturedef (pytest.FixtureDef): fixture definition object. - request (pytest.FixtureRequest): fixture request object. - - Returns: - object | None: fixture value or None otherwise. - """ - if hasattr(request, "param") and request.param: - request.param = _resolve_lazy_fixture(request.param, request) - return None - - -def _resolve_lazy_fixture(__val: object, request: pytest.FixtureRequest) -> object: - """Lazy fixture resolver. - - Args: - __val (object): fixture value object. - request (pytest.FixtureRequest): pytest fixture request object. - - Returns: - object: resolved fixture value. - """ - if isinstance(__val, list | tuple): - return tuple(_resolve_lazy_fixture(v, request) for v in __val) - if isinstance(__val, typing.Mapping): - return {k: _resolve_lazy_fixture(v, request) for k, v in __val.items()} - if not is_lazy_fixture(__val): - return __val - lazy_obj = typing.cast(LazyFixture, __val) - return request.getfixturevalue(lazy_obj.name) --- a/tests/test_cookie_on_redirects.py +++ b/tests/test_cookie_on_redirects.py @@ -2,54 +2,47 @@ from .utils import http -def _stringify(fixture): - return fixture + '' - - -@pytest.mark.parametrize('instance', [ - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), +@pytest.mark.parametrize('target_httpbin', [ + 'httpbin', + 'remote_httpbin', ]) -def test_explicit_user_set_cookie(httpbin, instance): - # User set cookies ARE NOT persisted within redirects - # when there is no session, even on the same domain. - +def test_explicit_user_set_cookie(httpbin, target_httpbin, request): + """User set cookies ARE NOT persisted within redirects when there is no session, even on the same domain.""" + target_httpbin = request.getfixturevalue(target_httpbin) r = http( '--follow', httpbin + '/redirect-to', - f'url=={_stringify(instance)}/cookies', + f'url=={target_httpbin.url}/cookies', 'Cookie:a=b' ) assert r.json == {'cookies': {}} -@pytest.mark.parametrize('instance', [ - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), +@pytest.mark.parametrize('target_httpbin', [ + 'httpbin', + 'remote_httpbin', ]) -def test_explicit_user_set_cookie_in_session(tmp_path, httpbin, instance): - # User set cookies ARE persisted within redirects - # when there is A session, even on the same domain. - +def test_explicit_user_set_cookie_in_session(tmp_path, httpbin, target_httpbin, request): + """User set cookies ARE persisted within redirects when there is A session, even on the same domain.""" + target_httpbin = request.getfixturevalue(target_httpbin) r = http( '--follow', '--session', str(tmp_path / 'session.json'), httpbin + '/redirect-to', - f'url=={_stringify(instance)}/cookies', + f'url=={target_httpbin}/cookies', 'Cookie:a=b' ) assert r.json == {'cookies': {'a': 'b'}} -@pytest.mark.parametrize('instance', [ - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), +@pytest.mark.parametrize('target_httpbin', [ + 'httpbin', + 'remote_httpbin', ]) -def test_saved_user_set_cookie_in_session(tmp_path, httpbin, instance): - # User set cookies ARE persisted within redirects - # when there is A session, even on the same domain. - +def test_saved_user_set_cookie_in_session(tmp_path, httpbin, target_httpbin, request): + """User set cookies ARE persisted within redirects when there is A session, even on the same domain.""" + target_httpbin = request.getfixturevalue(target_httpbin) http( '--follow', '--session', @@ -62,32 +55,33 @@ def test_saved_user_set_cookie_in_session(tmp_path, httpbin, instance): '--session', str(tmp_path / 'session.json'), httpbin + '/redirect-to', - f'url=={_stringify(instance)}/cookies', + f'url=={target_httpbin}/cookies', ) assert r.json == {'cookies': {'a': 'b'}} -@pytest.mark.parametrize('instance', [ - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), +@pytest.mark.parametrize('target_httpbin', [ + 'httpbin', + 'remote_httpbin', ]) @pytest.mark.parametrize('session', [True, False]) -def test_explicit_user_set_headers(httpbin, tmp_path, instance, session): - # User set headers ARE persisted within redirects - # even on different domains domain with or without - # an active session. +def test_explicit_user_set_headers(httpbin, tmp_path, target_httpbin, session, request): + """ + User set headers ARE persisted within redirects even on different domains domain with or without an active session. + + """ + target_httpbin = request.getfixturevalue(target_httpbin) session_args = [] if session: session_args.extend([ '--session', str(tmp_path / 'session.json') ]) - r = http( '--follow', *session_args, httpbin + '/redirect-to', - f'url=={_stringify(instance)}/get', + f'url=={target_httpbin}/get', 'X-Custom-Header:value' ) assert 'X-Custom-Header' in r.json['headers'] @@ -95,16 +89,13 @@ def test_explicit_user_set_headers(httpbin, tmp_path, instance, session): @pytest.mark.parametrize('session', [True, False]) def test_server_set_cookie_on_redirect_same_domain(tmp_path, httpbin, session): - # Server set cookies ARE persisted on the same domain - # when they are forwarded. - + """Server set cookies ARE persisted on the same domain when they are forwarded.""" session_args = [] if session: session_args.extend([ '--session', str(tmp_path / 'session.json') ]) - r = http( '--follow', *session_args, @@ -136,8 +127,7 @@ def test_server_set_cookie_on_redirect_different_domain(tmp_path, http_server, h def test_saved_session_cookies_on_same_domain(tmp_path, httpbin): - # Saved session cookies ARE persisted when making a new - # request to the same domain. + """Saved session cookies ARE persisted when making a new request to the same domain.""" http( '--session', str(tmp_path / 'session.json'), @@ -152,8 +142,7 @@ def test_saved_session_cookies_on_same_domain(tmp_path, httpbin): def test_saved_session_cookies_on_different_domain(tmp_path, httpbin, remote_httpbin): - # Saved session cookies ARE persisted when making a new - # request to a different domain. + """Saved session cookies ARE persisted when making a new request to a different domain.""" http( '--session', str(tmp_path / 'session.json'), @@ -167,45 +156,49 @@ def test_saved_session_cookies_on_different_domain(tmp_path, httpbin, remote_htt assert r.json == {'cookies': {}} -@pytest.mark.parametrize('initial_domain, first_request_domain, second_request_domain, expect_cookies', [ +@pytest.mark.parametrize(['initial_domain', 'first_request_domain', 'second_request_domain', 'expect_cookies'], [ ( # Cookies are set by Domain A # Initial domain is Domain A # Redirected domain is Domain A - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('httpbin'), + 'httpbin', + 'httpbin', + 'httpbin', True, ), ( # Cookies are set by Domain A # Initial domain is Domain B # Redirected domain is Domain B - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), - pytest.lazy_fixture('remote_httpbin'), + 'httpbin', + 'remote_httpbin', + 'remote_httpbin', False, ), ( # Cookies are set by Domain A # Initial domain is Domain A # Redirected domain is Domain B - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), + 'httpbin', + 'httpbin', + 'remote_httpbin', False, ), ( # Cookies are set by Domain A # Initial domain is Domain B # Redirected domain is Domain A - pytest.lazy_fixture('httpbin'), - pytest.lazy_fixture('remote_httpbin'), - pytest.lazy_fixture('httpbin'), + 'httpbin', + 'remote_httpbin', + 'httpbin', True, ), ]) -def test_saved_session_cookies_on_redirect(tmp_path, initial_domain, first_request_domain, second_request_domain, expect_cookies): +def test_saved_session_cookies_on_redirect( + tmp_path, initial_domain, first_request_domain, second_request_domain, expect_cookies, request): + initial_domain = request.getfixturevalue(initial_domain) + first_request_domain = request.getfixturevalue(first_request_domain) + second_request_domain = request.getfixturevalue(second_request_domain) http( '--session', str(tmp_path / 'session.json'), @@ -216,7 +209,7 @@ def test_saved_session_cookies_on_redirect(tmp_path, initial_domain, first_reque str(tmp_path / 'session.json'), '--follow', first_request_domain + '/redirect-to', - f'url=={_stringify(second_request_domain)}/cookies' + f'url=={second_request_domain}/cookies' ) if expect_cookies: expected_data = {'cookies': {'a': 'b'}} --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -821,16 +821,17 @@ def test_session_multiple_headers_with_same_name(basic_session, httpbin): 'server, expected_cookies', [ ( - pytest.lazy_fixture('localhost_http_server'), + 'localhost_http_server', {'secure_cookie': 'foo', 'insecure_cookie': 'bar'} ), ( - pytest.lazy_fixture('remote_httpbin'), + 'remote_httpbin', {'insecure_cookie': 'bar'} ) ] ) -def test_secure_cookies_on_localhost(mock_env, tmp_path, server, expected_cookies): +def test_secure_cookies_on_localhost(mock_env, tmp_path, server, expected_cookies, request): + server = request.getfixturevalue(server) session_path = tmp_path / 'session.json' http( '--session', str(session_path), --- a/tests/test_update_warnings.py +++ b/tests/test_update_warnings.py @@ -132,10 +132,10 @@ def test_check_updates_first_invocation( @pytest.mark.parametrize( - 'should_issue_warning, build_channel', + ['should_issue_warning', 'build_channel'], [ - (False, pytest.lazy_fixture('lower_build_channel')), - (True, pytest.lazy_fixture('higher_build_channel')), + (False, 'lower_build_channel'), + (True, 'higher_build_channel'), ], ) def test_check_updates_first_time_after_data_fetch( @@ -145,7 +145,9 @@ def test_check_updates_first_time_after_data_fetch( static_fetch_data, should_issue_warning, build_channel, + request, ): + request.getfixturevalue(build_channel) http('fetch_updates', '--daemon', env=with_warnings) r = http(httpbin + '/get', env=with_warnings) @@ -176,14 +178,15 @@ def test_cli_check_updates( @pytest.mark.parametrize( - "build_channel", [ - pytest.lazy_fixture("lower_build_channel"), - pytest.lazy_fixture("unknown_build_channel") + 'build_channel', [ + 'lower_build_channel', + 'unknown_build_channel', ] ) def test_cli_check_updates_not_shown( - static_fetch_data, build_channel + static_fetch_data, build_channel, request ): + request.getfixturevalue(build_channel) r = httpie('cli', 'check-updates') assert r.exit_status == ExitStatus.SUCCESS assert not check_update_warnings(r)