From ce108317bc4f623e74bc2dbc59a9508253cb489a Mon Sep 17 00:00:00 2001 From: Alessio Bogon <778703+youtux@users.noreply.github.com> Date: Fri, 21 Jul 2023 16:08:51 +0000 Subject: [PATCH 1/3] Add support for callables --- pytest_lazyfixture.py | 28 +++++++++++++++++---- tests/test_lazyfixture.py | 52 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/pytest_lazyfixture.py b/pytest_lazyfixture.py index abf5db5..f75d68d 100644 --- a/pytest_lazyfixture.py +++ b/pytest_lazyfixture.py @@ -3,6 +3,7 @@ import sys import types from collections import defaultdict +from inspect import signature import pytest @@ -32,7 +33,7 @@ def fill(request): if hasattr(item, 'callspec'): for param, val in sorted_by_dependency(item.callspec.params, fixturenames): if val is not None and is_lazy_fixture(val): - item.callspec.params[param] = request.getfixturevalue(val.name) + item.callspec.params[param] = val.evaluate(request) elif param not in item.funcargs: item.funcargs[param] = request.getfixturevalue(param) @@ -44,14 +45,14 @@ def fill(request): def pytest_fixture_setup(fixturedef, request): val = getattr(request, 'param', None) if is_lazy_fixture(val): - request.param = request.getfixturevalue(val.name) + request.param = val.evaluate(request) def pytest_runtest_call(item): if hasattr(item, 'funcargs'): for arg, val in item.funcargs.items(): if is_lazy_fixture(val): - item.funcargs[arg] = item._request.getfixturevalue(val.name) + item.funcargs[arg] = val.evaluate(item._request) @pytest.hookimpl(hookwrapper=True) @@ -176,7 +177,7 @@ def _tree_to_list(trees, leave): def lazy_fixture(names): - if isinstance(names, string_type): + if isinstance(names, string_type) or callable(names): return LazyFixture(names) else: return [LazyFixture(name) for name in names] @@ -188,7 +189,24 @@ def is_lazy_fixture(val): class LazyFixture(object): def __init__(self, name): - self.name = name + if isinstance(name, str): + self.name = name + self.fn = None + self.args = [name] + elif callable(name): + self.fn = name + params = signature(self.fn).parameters.values() + self.args = [param.name for param in params if param.kind == param.POSITIONAL_OR_KEYWORD] + self.name = "<" + name.__name__ + ":" + "-".join(self.args) + ">" + else: + raise TypeError(f"Unsupported parameter: {name!r}") + + def evaluate(self, request): + if self.fn is not None: + kwargs = {arg: request.getfixturevalue(arg) for arg in self.args} + return self.fn(**kwargs) + else: + return request.getfixturevalue(self.name) def __repr__(self): return '<{} "{}">'.format(self.__class__.__name__, self.name) diff --git a/tests/test_lazyfixture.py b/tests/test_lazyfixture.py index ba234b6..2bf308e 100644 --- a/tests/test_lazyfixture.py +++ b/tests/test_lazyfixture.py @@ -936,3 +936,55 @@ def test_eq(): assert lazy_fixture("Lol") == lazy_fixture("Lol") assert lazy_fixture("Lol") != lazy_fixture("Wut") assert lazy_fixture("Lol") != 123 + +def test_lambda_function(testdir): + testdir.makepyfile(""" + import pytest + from pytest_lazyfixture import lazy_fixture + + @pytest.fixture + def foo(): + return 1 + + @pytest.fixture + def bar(): + return 2 + + @pytest.mark.parametrize( + "data", + [ + lazy_fixture(lambda foo, bar: [foo, bar]) + ] + ) + def test_the_thing(data): + assert data == [1, 2] + """) + reprec = testdir.inline_run('-vvv') + reprec.assertoutcome(passed=1) + + +def test_lambda_function_item_names(testdir): + items = testdir.getitems(""" + import pytest + from pytest_lazyfixture import lazy_fixture + + @pytest.fixture + def foo(): + return 1 + + @pytest.fixture + def bar(): + return 2 + + @pytest.mark.parametrize( + "data", + [ + lazy_fixture(lambda foo, bar: [foo, bar]) + ] + ) + def test_the_thing(data): + assert data == [1, 2] + assert baz == 3 + """) + [item] = items + assert item.name == "test_the_thing[<:foo-bar>]" \ No newline at end of file From e60c0f4af9ffe97b641f4739026e2edca220d1f1 Mon Sep 17 00:00:00 2001 From: Alessio Bogon <778703+youtux@users.noreply.github.com> Date: Fri, 21 Jul 2023 16:11:02 +0000 Subject: [PATCH 2/3] Add readme description of callable lazy fixtures --- README.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.rst b/README.rst index 2639502..4c2c79d 100644 --- a/README.rst +++ b/README.rst @@ -30,6 +30,14 @@ in ``@pytest.mark.parametrize``: ]) def test_func(arg1, arg2): assert arg2 == 1 + + + # Callables are accepted too: + @pytest.mark.parametrize('arg', [ + lazy_fixture(lambda one: one + 9)), + ]) + def test_func(arg): + assert arg == 10 This can be even more useful when the fixture is itself parametrized: From 197679085d3cbc0f65563ffd3338a9b6666ee54b Mon Sep 17 00:00:00 2001 From: Alessio Bogon <778703+youtux@users.noreply.github.com> Date: Fri, 21 Jul 2023 18:19:53 +0200 Subject: [PATCH 3/3] Add missing newline at the end of file --- tests/test_lazyfixture.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_lazyfixture.py b/tests/test_lazyfixture.py index 2bf308e..05f30c0 100644 --- a/tests/test_lazyfixture.py +++ b/tests/test_lazyfixture.py @@ -987,4 +987,4 @@ def test_the_thing(data): assert baz == 3 """) [item] = items - assert item.name == "test_the_thing[<:foo-bar>]" \ No newline at end of file + assert item.name == "test_the_thing[<:foo-bar>]"