Giter Club home page Giter Club logo

pytest-lazy-fixture's Introduction

pytest-lazy-fixture travis-ci appveyor pypi

Use your fixtures in @pytest.mark.parametrize.

Installation

pip install pytest-lazy-fixture

Usage

pytest-lazy-fixture lets you use a fixture as one of the values passed in @pytest.mark.parametrize:

import pytest
from pytest_lazyfixture import lazy_fixture

@pytest.fixture
def one():
    return 1

@pytest.mark.parametrize('arg1,arg2', [
    ('val1', lazy_fixture('one')),
])
def test_func(arg1, arg2):
    assert arg2 == 1

This can be even more useful when the fixture is itself parametrized:

import pytest
from pytest_lazyfixture import lazy_fixture

@pytest.fixture(params=[1, 2])
def one(request):
    return request.param

@pytest.mark.parametrize('arg1,arg2', [
    ('val1', lazy_fixture('one')),
])
def test_func(arg1, arg2):
    assert arg2 in [1, 2]

Also you can use it as a parameter in @pytest.fixture:

import pytest
from pytest_lazyfixture import lazy_fixture

@pytest.fixture(params=[
    lazy_fixture('one'),
    lazy_fixture('two')
])
def some(request):
    return request.param

@pytest.fixture
def one():
    return 1

@pytest.fixture
def two():
    return 2

def test_func(some):
    assert some in [1, 2]

Please see tests for more examples.

Contributing

Contributions are very welcome. Tests can be run with tox.

License

Distributed under the terms of the MIT license, pytest-lazy-fixture is free and open source software

Issues

If you encounter any problems, please file an issue along with a detailed description.

pytest-lazy-fixture's People

Contributors

akuli avatar ewjoachim avatar jayvdb avatar lefterisnik avatar mgeier avatar nicoddemus avatar patrick91 avatar tvorog avatar yannickjadoul avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pytest-lazy-fixture's Issues

Lazy fixtures not working at all

I had a few lazy fixtures loaded in some of my tests like this:

@pytest.mark.parametrize('user_group', [
        pytest.lazy_fixture('user_group_national_manager'),
        pytest.lazy_fixture('user_group_regional_manager'),	
        pytest.lazy_fixture('user_group_lwi_staff')	
    ])

Now, when the tests are being loaded it fails collecting them with:

/usr/local/lib/python3.6/dist-packages/pluggy/hooks.py:258: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
/usr/local/lib/python3.6/dist-packages/pluggy/manager.py:67: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
/usr/local/lib/python3.6/dist-packages/pluggy/manager.py:61: in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
/usr/local/lib/python3.6/dist-packages/_pytest/python.py:242: in pytest_pycollect_makeitem
    res = list(collector._genfunctions(name, obj))
/usr/local/lib/python3.6/dist-packages/_pytest/python.py:432: in _genfunctions
    self.ihook.pytest_generate_tests(metafunc=metafunc)
/usr/local/lib/python3.6/dist-packages/pluggy/hooks.py:258: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
/usr/local/lib/python3.6/dist-packages/pluggy/manager.py:67: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
/usr/local/lib/python3.6/dist-packages/pluggy/manager.py:61: in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
/usr/local/lib/python3.6/dist-packages/pytest_lazyfixture.py:70: in pytest_generate_tests
    normalize_metafunc_calls(metafunc, 'funcargs')
/usr/local/lib/python3.6/dist-packages/pytest_lazyfixture.py:77: in normalize_metafunc_calls
    calls = normalize_call(callspec, metafunc, valtype, used_keys)
/usr/local/lib/python3.6/dist-packages/pytest_lazyfixture.py:101: in normalize_call
    _, fixturenames_closure, arg2fixturedefs = fm.getfixtureclosure([val.name], metafunc.definition.parent)
E   ValueError: not enough values to unpack (expected 3, got 2)

If I changed the code to use tuples or arrays, the tests run but the lazy fixture is not loaded making the tests fail:

@pytest.mark.parametrize('user_group', [
        (pytest.lazy_fixture('user_group_national_manager'),),
        (pytest.lazy_fixture('user_group_regional_manager'),),
        (pytest.lazy_fixture('user_group_lwi_staff'),)
    ])
    assert response.status_code == 200
E   assert 403 == 200
E    +  where 403 = <HttpResponseForbidden status_code=403, "text/html">.status_code

This was working properly before the upgrade to 0.5.0

I tried to use the format specified in the README with no luck. I had to remove the lazy fixture and use a different approach in the meantime.

Any idea of what's broken?

FYI, each fixture just creates a Group and adds the user to the created group. I assert the groups the user belongs to and it belongs to none so the fixture is not loaded when the test runs.

Fixture with numpy array as value fails on 0.6.0

This seems related to pytest-dev/pytest#5946 (which is already fixed on pytest master), but it is still failing with the latest lazy-fixtures (pinning to 0.5.2 fixes it).

Test script (variation of the one in pytest-dev/pytest#5946):

import numpy as np
import pytest


@pytest.mark.parametrize(
    'value',
    [
        np.arange(10, dtype=np.int64),
        np.arange(10, dtype=np.int32),
    ]
)
def test_bug(value):
    assert isinstance(value, np.ndarray)

and this fails with:

$ pytest test_pytest_bug.py -v
==================================================================== test session starts =====================================================================
platform linux -- Python 3.7.3, pytest-5.2.2.dev23+ga20880cca, py-1.8.0, pluggy-0.12.0 -- /home/joris/miniconda3/envs/arrow-dev/bin/python
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/joris/scipy/.hypothesis/examples')
rootdir: /home/joris/scipy
plugins: hypothesis-4.24.2, lazy-fixture-0.6.0
collected 2 items                                                                                                                                            

test_pytest_bug.py::test_bug[value0] ERROR                                                                                                             [ 50%]
test_pytest_bug.py::test_bug[value1] ERROR                                                                                                             [100%]

=========================================================================== ERRORS ===========================================================================
_____________________________________________________________ ERROR at setup of test_bug[value0] _____________________________________________________________

request = <FixtureRequest for <Function test_bug[value0]>>

    def fill(request):
        item = request._pyfuncitem
        fixturenames = getattr(item, "fixturenames", None)
        if fixturenames is None:
            fixturenames = request.fixturenames
    
        if hasattr(item, 'callspec'):
>           for param, val in sorted_by_dependency(item.callspec.params, fixturenames):

../miniconda3/envs/arrow-dev/lib/python3.7/site-packages/pytest_lazyfixture.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

params = {'value': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])}, fixturenames = ['value']

    def sorted_by_dependency(params, fixturenames):
        free_fm = []
        non_free_fm = defaultdict(list)
    
        for key in _sorted_argnames(params, fixturenames):
            val = params.get(key)
    
>           if not val or not is_lazy_fixture(val) or val.name not in params:
E           ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

../miniconda3/envs/arrow-dev/lib/python3.7/site-packages/pytest_lazyfixture.py:130: ValueError
_____________________________________________________________ ERROR at setup of test_bug[value1] _____________________________________________________________

request = <FixtureRequest for <Function test_bug[value1]>>

    def fill(request):
        item = request._pyfuncitem
        fixturenames = getattr(item, "fixturenames", None)
        if fixturenames is None:
            fixturenames = request.fixturenames
    
        if hasattr(item, 'callspec'):
>           for param, val in sorted_by_dependency(item.callspec.params, fixturenames):

../miniconda3/envs/arrow-dev/lib/python3.7/site-packages/pytest_lazyfixture.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

params = {'value': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)}, fixturenames = ['value']

    def sorted_by_dependency(params, fixturenames):
        free_fm = []
        non_free_fm = defaultdict(list)
    
        for key in _sorted_argnames(params, fixturenames):
            val = params.get(key)
    
>           if not val or not is_lazy_fixture(val) or val.name not in params:
E           ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

../miniconda3/envs/arrow-dev/lib/python3.7/site-packages/pytest_lazyfixture.py:130: ValueError
====================================================================== 2 error in 0.09s ======================================================================

cannot use a lazy fixture - copy() takes 1 positional argument but 2 were given

import pytest

@pytest.fixture(params=[1,2])
def one(request):
    return request.param

@pytest.mark.parametrize('arg1,arg2', [
    ('val1', pytest.lazy_fixture('one')),
    ('val1', 'val2')
])
def test_func(arg1, arg2):
    pass
============================= test session starts =============================
platform win32 -- Python 3.6.2, pytest-3.6.3, py-1.5.4, pluggy-0.6.0 -- 
cachedir: .pytest_cache
metadata: {'Python': '3.6.2', 'Platform': 'Windows-10-10.0.16299-SP0', 'Packages': {'pytest': '3.6.3', 'py': '1.5.4', 'pluggy': '0.6.0'}, 'Plugins': {'metadata': '1.7.0', 'lazy-fixture': '0.4.0', 'html': '1.19.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\JDK18~1.0_1'}
rootdir: xxxxxxxx inifile:
plugins: metadata-1.7.0, lazy-fixture-0.4.0, html-1.19.0
collected 0 items / 1 errors

=================================== ERRORS ====================================
_______________________ ERROR collecting test_dry_qa.py _______________________
manifest\lib\site-packages\pluggy\__init__.py:617: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
manifest\lib\site-packages\pluggy\__init__.py:222: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
manifest\lib\site-packages\pluggy\__init__.py:216: in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
manifest\lib\site-packages\_pytest\python.py:243: in pytest_pycollect_makeitem
    res = list(collector._genfunctions(name, obj))
manifest\lib\site-packages\_pytest\python.py:433: in _genfunctions
    self.ihook.pytest_generate_tests(metafunc=metafunc)
manifest\lib\site-packages\pluggy\__init__.py:617: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
manifest\lib\site-packages\pluggy\__init__.py:222: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
manifest\lib\site-packages\pluggy\__init__.py:216: in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
manifest\lib\site-packages\pytest_lazyfixture.py:57: in pytest_generate_tests
    normalize_metafunc_calls(metafunc, 'funcargs')
manifest\lib\site-packages\pytest_lazyfixture.py:64: in normalize_metafunc_calls
    calls = normalize_call(callspec, metafunc, valtype)
manifest\lib\site-packages\pytest_lazyfixture.py:85: in normalize_call
    newcallspec = callspec.copy(metafunc)
E   TypeError: copy() takes 1 positional argument but 2 were given
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.31 seconds ===========================

lazy-fixture-0.5.2: function fixture runs before module fixture

pytest-5.1.3
lazy-fixture-0.5.2

Example:

import pytest
from pytest_lazyfixture import lazy_fixture

@pytest.fixture(scope="module")
def module_fixture():
    print('using module fixture')

@pytest.fixture
def fixture1():
    print("using fixture1")

@pytest.fixture
def fixture2():
    print("using fixture2")

@pytest.mark.usefixtures("module_fixture")
@pytest.mark.parametrize("fixt", [lazy_fixture("fixture1"), lazy_fixture("fixture2")])
def test_test(fixt):
    pass

output

smoke/test_test.py::test_test[fixt0] using fixture1
using module fixture
PASSED
smoke/test_test.py::test_test[fixt1] using fixture2
PASSED

There is strange order - fixture1, module fixture, fixture2

Same example without using lazy_fixture:

@pytest.mark.usefixtures("module_fixture")
def test_test1(fixture1):
    pass


@pytest.mark.usefixtures("module_fixture")
def test_test2(fixture2):
    pass

output:

smoke/test_test.py::test_test1 using module fixture
using fixture1
PASSED
smoke/test_test.py::test_test2 using fixture2
PASSED

Executing order looks as designed - module fixture, fixture1, fixture2

Inquiry about the status of pytest-lazy-fixture and offering assistance

Hey @TvoroG,

I hope you're doing well. I really find pytest-lazy-fixture a great pytest plugin, but I noticed that it hasn't had a release since 2020, and there are some open issues and pull requests that seem to be unattended.

For this reason, I wonder if the project is abandoned, or if it's still supported.

Specifically, I think that #62 is really something worth considering and that would make the project even more useful. I use that approach in pytest-factoryboy, but this project is way more advanced in the way it handles the pytest internals for lazy fixtures.

As an active user and maintainer of pytest-bdd and pytest-factoryboy, I would be interested in contributing to the project's maintenance and further development, including reviewing PRs, keeping the CI up to date with the latest pytests and python versions, making releases, etc.

Would that be something you can consider?

Thanks for your time, and I'm looking forward to your response.

Best regards,
Alessio

Using fixture that returns a list of parameters, is it possible?

Here's my fixture:

@fixture
def devices(scope='module');
    with connect(get_all_devices()) as connected_devices:
        yield connected_devices

Here's how I want to use it:

@parametrize('device', devices)
def test_routine(device):
    device.do_something()
    assert device.is_ok()

What I'm doing instead:

def test_routine(subtests, devices):
    for index, device in enumerate(devices):
        with subtests.test(device, i=index):
            device.do_something()
            assert device.is_ok()

Is this possible with lazy fixture or any other method?

LazyFixture only resolved when used directly, but not in lists etc.

My use case requires preparing lists of things instead of just single things one by one, please see your example adapted accordingly below.

import pytest

@pytest.fixture(params=[
    [pytest.lazy_fixture('one')],
    [pytest.lazy_fixture('one'), pytest.lazy_fixture('two')],
])
def some_list(request):
    return request.param

@pytest.fixture
def one():
    return 1

@pytest.fixture
def two():
    return 2

def test_func(some_list):
    from pprint import pprint
    pprint(some_list)
    assert 1 in some_list

Inside test_func() the some_list will be something like [<LazyFixture "one">, <LazyFixture "two">] where I would have expected that this had been expanded/resolved to [1, 2].

Is there a way to always expand /resolve in a test context no matter how wrapped or nested the LazyFixture is?

Cheers

Nested lazy fixtures not respecting scope

Hi, I have a fairly complex set of fixtures to help with parameterization of polymorphic requests. Unfortunately it seems that some of the fixtures stop respecting their intended scope and are called multiple times.

Theoretically, let's say we are building a graph which has vertices & edges. Well, the vertices themselves can be polymorphic fixtures, some of their properties can be mutated, and the test cases are building edges between them.

In the following example, I have a series of network primitives, Ports & Cloud Ports, which may have multiple locations associated with them. At the end, I take two vertex fixtures and test them.

The test list looks fine, but the count of how many times a session scoped fixture is invoked seems incorrect. In all cases, I would have expected the counts to match how many dependent parameters there are, but in some cases I see 8, others I see 16. I use a wrapper here to collect invocation counts and dump them at the end of the tests.

It's as if the cache key is invalidated or doesn't match because of where the fixture is referenced in the hierarchy of fixtures.

test_lazy_fixture[port-cloud_attachment-cloud_port_c-location_a]
test_lazy_fixture[port-cloud_attachment-cloud_port_c-location_b]
test_lazy_fixture[port-cloud_attachment-cloud_port_d-location_a]
test_lazy_fixture[port-cloud_attachment-cloud_port_d-location_b]
test_lazy_fixture[port-port_attachment-location_c-location_a]
test_lazy_fixture[port-port_attachment-location_c-location_b]
test_lazy_fixture[port-port_attachment-location_d-location_a]
test_lazy_fixture[port-port_attachment-location_d-location_b]
test_lazy_fixture[port_group-cloud_attachment-cloud_port_c-location_a]
test_lazy_fixture[port_group-cloud_attachment-cloud_port_c-location_b]
test_lazy_fixture[port_group-cloud_attachment-cloud_port_d-location_a]
test_lazy_fixture[port_group-cloud_attachment-cloud_port_d-location_b]
test_lazy_fixture[port_group-port_attachment-location_c-location_a]
test_lazy_fixture[port_group-port_attachment-location_c-location_b]
test_lazy_fixture[port_group-port_attachment-location_d-location_a]
test_lazy_fixture[port_group-port_attachment-location_d-location_b]
{
  "attachment": 1,
  "cloud_attachment": 8,
  "cloud_port": 8,
  "cloud_port_c": 1,
  "cloud_port_d": 1,
  "link_port": 1,
  "location_a": 1,
  "location_b": 1,
  "location_c": 1,
  "location_d": 1,
  "port": 8,
  "port_attachment": 8,
  "port_group": 8,
  "primary_location": 16,
  "secondary_location": 8,
  "secondary_port": 8
}
import collections
import functools
import json

import pytest
from pytest_lazyfixture import lazy_fixture

_COUNTERS = collections.defaultdict(int)


def teardown_module(module):
    print(json.dumps(_COUNTERS, sort_keys=True, indent=2))


def counter(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        fn(*args, **kwargs)
        _COUNTERS[fn.__name__] += 1

    return wrapper


@pytest.fixture(scope='session')
@counter
def location_a() -> str:
    return 'location_a'


@pytest.fixture(scope='session')
@counter
def location_b() -> str:
    return 'location_b'


@pytest.fixture(params=lazy_fixture([
    'location_a',
    'location_b'
]), scope='session')
@counter
def primary_location(request: pytest.FixtureRequest) -> str:
    return request.param  # type: ignore


@pytest.fixture(scope='session')
@counter
def location_c() -> str:
    return 'location_c'


@pytest.fixture(scope='session')
@counter
def location_d() -> str:
    return 'location_d'


@pytest.fixture(params=lazy_fixture([
    'location_c',
    'location_d'
]), scope='session')
@counter
def secondary_location(request: pytest.FixtureRequest) -> str:
    return request.param  # type: ignore


@pytest.fixture(scope='session')
@counter
def cloud_port_c() -> str:
    return 'cloud_port_c'


@pytest.fixture(scope='session')
@counter
def cloud_port_d() -> str:
    return 'cloud_port_d'


@pytest.fixture(params=lazy_fixture([
    'cloud_port_c',
    'cloud_port_d'
]), scope='session')
@counter
def cloud_port(request: pytest.FixtureRequest) -> str:
    return request.param  # type: ignore


@pytest.fixture(scope='session')
@counter
def port(primary_location: str) -> str:
    return f'port-{primary_location}'


@pytest.fixture(scope='session')
@counter
def port_group(primary_location: str) -> str:
    return f'port_group-{primary_location}'


@pytest.fixture(params=lazy_fixture([
    'port',
    'port_group'
]), scope='session')
@counter
def link_port(request: pytest.FixtureRequest) -> str:
    return request.param  # type: ignore


@pytest.fixture(scope='session')
@counter
def secondary_port(secondary_location: str) -> str:
    return f'secondary_port-{secondary_location}'


@pytest.fixture(scope='session')
@counter
def port_attachment(secondary_port: str) -> str:
    return f'port_attachment-{secondary_port}'


@pytest.fixture(scope='session')
@counter
def cloud_attachment(cloud_port: str) -> str:
    return f'cloud_attachment-{cloud_port}'


@pytest.fixture(params=lazy_fixture([
    'port_attachment',
    'cloud_attachment'
]), scope='session')
@counter
def attachment(request: pytest.FixtureRequest) -> str:
    return request.param  # type: ignore


def test_lazy_fixture(link_port: str, attachment: str) -> None:
    print(f'{link_port}-{attachment}')

pytest-lazy-fixture doesn't work for deep nesting

pytest-lazy-fixture doesn't work for deep nesting

platform linux -- Python 3.5.2, pytest-3.10.1, py-1.7.0, pluggy-0.8.1
plugins: timeout-1.3.0, celery-4.2.1, repeat-0.7.0, reportportal-1.0.4, assume-1.2, lazy-fixture-0.5.1

Example:

import pytest

@pytest.fixture(scope='function')
def fixt1():
    return 111

@pytest.fixture(scope='function')
def fixt2():
    return pytest.lazy_fixture("fixt1")

@pytest.fixture(scope='function')
def fixt3():
    return pytest.lazy_fixture("fixt2")

def test(fixt3):
    print("Value in test: {}".format(fixt3))

Returns:

Value in test: <LazyFixture "fixt1">

Should be:

Value in test: 111

skipping one of parametrized tests with `lazy_fixture` fails

Hi all,

Each test are run once for all environment in our test suite by default.

conftest.py

from dataclasses import dataclass
from enum        import auto, Flag

import pytest
from pytest_lazyfixture import is_lazy_fixture

class Environment(Flag):
  SLOVAK = auto()
  CZECH  = auto()
  ALL    = SLOVAK | CZECH

@dataclass
class TestItem:
  SUPPORTED_ENVIRONMENT_MARK_NAME = 'supported_environments'

  @classmethod
  def only_environment(cls, env):
    return getattr(pytest.mark, cls.SUPPORTED_ENVIRONMENT_MARK_NAME)(env)

  item: pytest.Function

  @property
  def current_environment(self):
    try:               current_environment = self.item.callspec.getparam(for_all_envs.__name__)
    except ValueError: current_environment = None
    else:
      if is_lazy_fixture(current_environment):
        current_environment = self.item._request.getfixturevalue(current_environment.name)

    return current_environment

  @property
  def supported_environments(self):
    return mark.args[0] \
      if   (mark := next(self.item.iter_markers(self.SUPPORTED_ENVIRONMENT_MARK_NAME), None)) \
      else Environment.ALL


@pytest.fixture(
  autouse = True,
  params  = [Environment.CZECH, Environment.SLOVAK],
)
def for_all_envs(request):
  ...

def pytest_runtest_setup(item):
  test_item = TestItem(item = item)

  if test_item.current_environment not in test_item.supported_environments:
    pytest.skip(f'cannot run on environment `{test_item.current_environment}`')

and the usage below:

test.py

from tests.conftest import Environment, TestItem

@TestItem.only_environment(Environment.CZECH)
def test_tests_skipping():
    ...

For now everything works well (output below):

collected 2 items

tests/test_tests_skipping.py::test_tests_skipping[Environment.CZECH] PASSED
tests/test_tests_skipping.py::test_tests_skipping[Environment.SLOVAK] SKIPPED (cannot run on environment `Environment.SLOVAK`)

Each environment needs custom setup and that's where the pytest_lazyfixture comes. I added two fixtures and changed parameter values of for_all_envs fixture.

conftest.py

@pytest.fixture
def czech_environment():
  # NOTE: do some env specific setup here
  return Environment.CZECH

@pytest.fixture
def slovak_environment():
  # NOTE: do some env specific setup here
  return Environment.SLOVAK

@pytest.fixture(
  autouse = True,
  params  = [
    pytest.param(lazy_fixture(czech_environment.__name__),  id = 'CZ'),
    pytest.param(lazy_fixture(slovak_environment.__name__), id = 'SK'),
  ]
)
def for_all_envs(request):
  return request.param

and now the output is:

collected 2 items

tests/test_tests_skipping.py::test_tests_skipping[cz] PASSED
tests/test_tests_skipping.py::test_tests_skipping[sk] SKIPPED (cannot run on environment `Environment.SLOVAK`)
tests/test_tests_skipping.py::test_tests_skipping[sk] ERROR

=========================================================================== ERRORS =================================================================================
________________________________________________________ ERROR at teardown of test_tests_skipping[sk] ______________________________________________________________
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:311: in from_call
    result: Optional[TResult] = func()
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:255: in <lambda>
    lambda: ihook(item=item, **kwds), when=when, reraise=reraise
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/pluggy/_hooks.py:265: in __call__
    return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/pluggy/_manager.py:80: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:175: in pytest_runtest_teardown
    item.session._setupstate.teardown_exact(item, nextitem)
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:419: in teardown_exact
    self._teardown_towards(needed_collectors)
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:434: in _teardown_towards
    raise exc
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:427: in _teardown_towards
    self._pop_and_teardown()
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:387: in _pop_and_teardown
    self._teardown_with_finalization(colitem)
/home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:408: in _teardown_with_finalization
    assert colitem in self.stack
E   AssertionError

If the test is run for both env, everything is OK:

test.py

def test_tests_skipping():
    ...

output

collected 2 items

tests/test_tests_skipping.py::test_tests_skipping[cz] PASSED
tests/test_tests_skipping.py::test_tests_skipping[sk] PASSED

=========================================================================== 2 passed in 0.06s ===========================================================================

It seems there is missing colitem <Function test_tests_skipping[sk]> in the self.stack in /home/jcas/.pyenv/versions/3.9.6/envs/pytest_lazy_fixture_bug3.9.6/lib/python3.9/site-packages/_pytest/runner.py:408 (from the last frame).

I'm not sure what is wrong, because I don't know these pytest internals. Also I'm not sure if it is
related to pytest-lazy-fixture.

Can anybody help me with this please?

cannot use a lazy fixture if it directly returns a list

# -*- coding: utf-8 -*-

import string
import pytest


@pytest.fixture
def list_of_tuple_for_testing():
    yield [(ord(x), x) for x in string.ascii_uppercase]


@pytest.mark.parametrize(
    'chr_code, chr_object',
    pytest.lazy_fixture('list_of_tuple_for_testing')
)
def test_all_files(chr_code, chr_object):
    assert chr(chr_code) == chr_object
================================================================================ ERRORS ================================================================================
________________________________________________________________ ERROR collecting test_lazy_fixture.py _________________________________________________________________
/usr/lib/python3.6/site-packages/pluggy/__init__.py:617: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
/usr/lib/python3.6/site-packages/pluggy/__init__.py:222: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
/usr/lib/python3.6/site-packages/pluggy/__init__.py:216: in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
/usr/lib/python3.6/site-packages/_pytest/python.py:240: in pytest_pycollect_makeitem
    res = list(collector._genfunctions(name, obj))
/usr/lib/python3.6/site-packages/_pytest/python.py:432: in _genfunctions
    self.ihook.pytest_generate_tests(metafunc=metafunc)
/usr/lib/python3.6/site-packages/pluggy/__init__.py:617: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
/usr/lib/python3.6/site-packages/pluggy/__init__.py:222: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
/usr/lib/python3.6/site-packages/pluggy/__init__.py:216: in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
/usr/lib/python3.6/site-packages/_pytest/python.py:161: in pytest_generate_tests
    metafunc.parametrize(*marker.args, **marker.kwargs)
/usr/lib/python3.6/site-packages/_pytest/python.py:872: in parametrize
    argnames, argvalues, self.function, self.config
/usr/lib/python3.6/site-packages/_pytest/mark/structures.py:106: in _for_parametrize
    for x in argvalues
E   TypeError: 'LazyFixture' object is not iterable

mypy can't discover pytest.lazy_fixture under pytest 6

If you have a test suite that uses pytest.lazy_fixture, and you're using pytest 6.0.0+, and you run mypy over your test suite, mypy complains with the error:

test/test_something.py:42: error: Module has no attribute "lazy_fixture"

The test suite itself passes without any problems; it is only the type checking of mypy that fails.

This problem does not exist on pytest 5.4.3 or earlier.

I presume something has changed in the plugin registration process that prevents mypy from seeing the lazy_fixture attribute.

autouse=True of lazy_fixture breaks nose tests

Hi all,

We have some legacy nose-style tests in our test suite. They are also run nicely via pytest (https://docs.pytest.org/en/latest/nose.html).

Today I've tried to add a fixture with parametrization using lazy_fixture in combination with autouse=True and the tests are now ERRORing with:

_____ ERROR at setup of MyNoseTestClass.test_foo ________
test_foo does not support fixtures, maybe unittest.TestCase subclass?
Node id: path/test_foo.py::MyNoseTestClass::test_foo
Function type: TestCaseFunction

The indication is right and maybe some check would avoid this issue.

Not that some other fixtures with autouse=True but without lazy_fixture are not changing the test behaviour

Pytest discovery changes test names when using multiple lazy fixtures

I have some test cases in which I need more than one lazy fixture (one for each parameter).

The problem is that the pytest discovery is creating different test names in every run, which creates a problem in the interaction with tools like VScode. I don't know if it's a pytest issue or pytest-lazy-fixtures one.

Here's an example of a test that uses two lazy fixtures:

import pytest
from pytest import fixture
from pytest_lazyfixture import lazy_fixture


@fixture(params=[1, 2, 3])
def all_numbers(request):
    return request.param


@fixture(params=["a", "b", "c"])
def all_letters(request):
    return request.param


@pytest.mark.parametrize(
    "number,letter",
    [lazy_fixture(["all_numbers", "all_letters"])]
)
def test_multiple_lazy(number, letter):
    print(number, letter)

This is one pytest collect run:

 pytest --collect-only
=================================================================== test session starts ====================================================================
platform darwin -- Python 3.11.0, pytest-7.2.0, pluggy-0.13.1
rootdir: /Users/fraimondo/dev/scratch/pytest_order
plugins: typeguard-2.13.3, lazy-fixture-0.6.3
collected 9 items                                                                                                                                          

<Module test_multiple_lazy.py>
  <Function test_multiple_lazy[all_numbers-all_letters-a-1]>
  <Function test_multiple_lazy[all_numbers-all_letters-a-2]>
  <Function test_multiple_lazy[all_numbers-all_letters-a-3]>
  <Function test_multiple_lazy[all_numbers-all_letters-b-1]>
  <Function test_multiple_lazy[all_numbers-all_letters-b-2]>
  <Function test_multiple_lazy[all_numbers-all_letters-b-3]>
  <Function test_multiple_lazy[all_numbers-all_letters-c-1]>
  <Function test_multiple_lazy[all_numbers-all_letters-c-2]>
  <Function test_multiple_lazy[all_numbers-all_letters-c-3]>

This is another one:

pytest --collect-only
=================================================================== test session starts ====================================================================
platform darwin -- Python 3.11.0, pytest-7.2.0, pluggy-0.13.1
rootdir: /Users/fraimondo/dev/scratch/pytest_order
plugins: typeguard-2.13.3, lazy-fixture-0.6.3
collected 9 items                                                                                                                                          

<Module test_multiple_lazy.py>
  <Function test_multiple_lazy[all_numbers-all_letters-1-a]>
  <Function test_multiple_lazy[all_numbers-all_letters-1-b]>
  <Function test_multiple_lazy[all_numbers-all_letters-1-c]>
  <Function test_multiple_lazy[all_numbers-all_letters-2-a]>
  <Function test_multiple_lazy[all_numbers-all_letters-2-b]>
  <Function test_multiple_lazy[all_numbers-all_letters-2-c]>
  <Function test_multiple_lazy[all_numbers-all_letters-3-a]>
  <Function test_multiple_lazy[all_numbers-all_letters-3-b]>
  <Function test_multiple_lazy[all_numbers-all_letters-3-c]>

pytest-lazy-fixture breaks with Traits in factoryboy 3.2.0: 'Maybe' object has no attribute 'call'

After updating factoryboy to 3.2.0 my tests using lazy_fixture with fixtures that use Trait (in result using Maybe) raise AttributeError: 'Maybe' object has no attribute 'call'.

python_version = "3.8"
django = "~=3.0"
factory-boy = "~=3.2.0"
pytest = "~=5.4.3"
pytest-factoryboy = "~=2.1.0"
pytest-lazy-fixture = "~=0.6.3"

Attached is a full traceback from failed test case.

request = <FixtureRequest for <Function test_success>>

    def fill(request):
        item = request._pyfuncitem
        fixturenames = getattr(item, "fixturenames", None)
        if fixturenames is None:
            fixturenames = request.fixturenames
    
        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)
                elif param not in item.funcargs:
                    item.funcargs[param] = request.getfixturevalue(param)
    
>       _fillfixtures()

/home/django/venv/lib/python3.8/site-packages/pytest_lazyfixture.py:39: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/home/django/venv/lib/python3.8/site-packages/pytest_factoryboy/fixture.py:188: in model_fixture
    factoryboy_request.evaluate(request)
/home/django/venv/lib/python3.8/site-packages/pytest_factoryboy/plugin.py:83: in evaluate
    self.execute(request, function, deferred)
/home/django/venv/lib/python3.8/site-packages/pytest_factoryboy/plugin.py:65: in execute
    self.results[model][attr] = function(request)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <SubRequest 'user' for <Function test_success>>

    def deferred(request):
>       declaration.call(instance, step, context)
E       AttributeError: 'Maybe' object has no attribute 'call'

/home/django/venv/lib/python3.8/site-packages/pytest_factoryboy/fixture.py:294: AttributeError

Seems like it could be a problem in pytest_factoryboy itself but I've seen it raised only for tests using lazy_fixture.

Failed: Database access not allowed, use the "django_db" mark to enable it.

It does not work with Django when the referenced fixture needs access to the database.

    def pytest_runtest_setup(item):
        if hasattr(item, 'callspec'):
            for param, val in sorted_by_dependency(item.callspec.params):
                if is_lazy_fixture(val):
>                   item.callspec.params[param] = item._request.getfixturevalue(val.name)

/usr/local/lib/python3.5/site-packages/pytest_lazyfixture.py:22: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests/lexicon/conftest.py:9: in user
    username='user', password='password', email='[email protected]',
/usr/local/lib/python3.5/site-packages/django/contrib/auth/models.py:157: in create_user
    return self._create_user(username, email, password, **extra_fields)
/usr/local/lib/python3.5/site-packages/django/contrib/auth/models.py:151: in _create_user
    user.save(using=self._db)
/usr/local/lib/python3.5/site-packages/django/contrib/auth/base_user.py:80: in save
    super(AbstractBaseUser, self).save(*args, **kwargs)
/usr/local/lib/python3.5/site-packages/django/db/models/base.py:796: in save
    force_update=force_update, update_fields=update_fields)
/usr/local/lib/python3.5/site-packages/django/db/models/base.py:821: in save_base
    with transaction.atomic(using=using, savepoint=False):
/usr/local/lib/python3.5/site-packages/django/db/transaction.py:158: in __enter__
    if not connection.get_autocommit():
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <django.db.backends.postgresql.base.DatabaseWrapper object at 0x7f6b472b4da0>

    def get_autocommit(self):
        """
            Check the autocommit state.
            """
>       self.ensure_connection()
E       Failed: Database access not allowed, use the "django_db" mark to enable it.

/usr/local/lib/python3.5/site-packages/django/db/backends/base/base.py:365: Failed

lazy-fixture breaks all the fixtures with autouse=True

In my current project I have some fixtures which they use autouse=True. eg:

def setup(autouse=True):
     self.var = 15

After installing pytest-lazy-fixture, my tests can't find the self.var variable. If I remove the autouse=True and pass the fixture to my tests all work fine.

Any ideas?

Nested fixtures are not seen by pytest_lazyfixture unless autouse=True

Using modified example from the official Usage instructions:

@fixture(params=[0, 1], autouse=True)
def zero_one(request):
    return request.param

@fixture(params=[1])
def one(request, zero_one):
    return zero_one * request.param

@fixture(params=[0, 1], autouse=False)
def zero_two(request):
    return request.param

@fixture
def two(request, zero_two):
    return zero_two * request.param

@fixture(params=[
    lazy_fixture('one'),
])
def some_auto(request):
    return request.param

@fixture(params=[
    lazy_fixture('two')
])
def some(request):
    return request.param

def test_pytest_can_see_all_fixtures(zero_one, zero_two, one, two):
    for f in (zero_one, zero_two, one, two):
        assert isinstance(f, int)

def test_func_autouse(some_auto):
    assert some_auto in [0, 1]

def test_func_no_autouse(some):
    assert some in [0, 1]

The last test will fail unexpectedly with error:

C:\Anaconda\lib\site-packages\_pytest\python.py:680: ValueError

During handling of the above exception, another exception occurred:

request = <FixtureRequest for <Function 'test_func_no_autouse[0-some0]'>>

    def fill(request):
        item = request._pyfuncitem
        fixturenames = item.fixturenames
        argnames = item._fixtureinfo.argnames
    
        for fname in fixturenames:
            if fname not in item.funcargs and fname not in argnames:
                item.funcargs[fname] = request.getfixturevalue(fname)
    
        if hasattr(item, 'callspec'):
            for param, val in sorted_by_dependency(item.callspec.params, fixturenames):
                if is_lazy_fixture(val):
>                   item.callspec.params[param] = request.getfixturevalue(val.name)
E                   Failed: The requested fixture has no parameter defined for the current test.
E                   
E                   Requested fixture 'zero_two' defined in:
E                   some_package\tests\test_example.py:47
E                   
E                   Requested here:
E                   C:\Anaconda\lib\site-packages\_pytest\fixtures.py:523

C:\Anaconda\lib\site-packages\pytest_lazyfixture.py:40: Failed

For some reason pytest_lazyfixture doesn't see fixtures that depend on other fixtures that pytest can see unless autouse=True in the lowest level fixture.

support passing parameters to lazy fixtures

as far as i understood lazy fixtures currently look up only by name, and dont add parameterization

the idea i have in mind is to be able to pass parameter values and scopes to them so the lazy fixture can get passed parameters

if this impossible without introducing support in pytest-core please open corosponding issues on pytest

ValueError: duplicate 'name'

Example:

import pytest


@pytest.fixture(params=[1, 2, 3])
def one(request):
    return request.param


@pytest.fixture(params=[pytest.mark.fixture('one')])
def as_str(request):
    return str(request.getfixturevalue('one'))


@pytest.fixture(params=[pytest.mark.fixture('one')])
def as_hex(request):
    return hex(request.getfixturevalue('one'))


def test_as_str(as_str):
    assert as_str in {'1', '2', '3'}


def test_as_hex(as_hex):
    assert as_hex in {'0x1', '0x2', '0x3'}


# fails at setup time, with ValueError: duplicate 'one'
def test_as_hex_vs_as_str(as_str, as_hex):
    assert int(as_hex, 16) == int(as_str)

Possible to expand the fixture return value in parametrize?

I would like to parametrize a test with the return value of a fixture.

Example:

@pytest.fixture
def links(browser): // assume broser was a fixture
    return browser.find_by_tag('a')

@pytest.mark.parametrize("link", links) // here expand the links fixture return value
def test_func(link):
     // test that link here

Is this possible with pytest-lazy-fixture? (or maybe even pytest itself?) Or might it be a nice feature?

AttributeError: module 'pytest' has no attribute 'lazy_fixture'

I have installed pytest-lazy-fixture:

pip install pytest-lazy-fixture
Collecting pytest-lazy-fixture
  Downloading pytest-lazy-fixture-0.4.0.tar.gz
Collecting pytest>=2.9.2 (from pytest-lazy-fixture)
  Downloading pytest-3.4.0-py2.py3-none-any.whl (188kB)
    100% |โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 194kB 645kB/s 
Requirement already satisfied: setuptools in /home/overflow012/.virtualenvs/split_dataset/lib/python3.5/site-packages (from pytest>=2.9.2->pytest-lazy-fixture)
Collecting py>=1.5.0 (from pytest>=2.9.2->pytest-lazy-fixture)
  Downloading py-1.5.2-py2.py3-none-any.whl (88kB)
    100% |โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 92kB 1.0MB/s 
Collecting pluggy<0.7,>=0.5 (from pytest>=2.9.2->pytest-lazy-fixture)
  Downloading pluggy-0.6.0.tar.gz
Requirement already satisfied: six>=1.10.0 in /home/overflow012/.virtualenvs/split_dataset/lib/python3.5/site-packages (from pytest>=2.9.2->pytest-lazy-fixture)
Collecting attrs>=17.2.0 (from pytest>=2.9.2->pytest-lazy-fixture)
  Downloading attrs-17.4.0-py2.py3-none-any.whl
Building wheels for collected packages: pytest-lazy-fixture, pluggy
  Running setup.py bdist_wheel for pytest-lazy-fixture ... done
  Stored in directory: /home/overflow012/.cache/pip/wheels/85/9e/a0/45b3bca5fb2b27171cf4537a2b77a078db0140789c364431e3
  Running setup.py bdist_wheel for pluggy ... done
  Stored in directory: /home/overflow012/.cache/pip/wheels/df/44/8e/e136760ae525eac46b3e3db643ef58ff1753177b5a722b0c96
Successfully built pytest-lazy-fixture pluggy
Installing collected packages: py, pluggy, attrs, pytest, pytest-lazy-fixture
Successfully installed attrs-17.4.0 pluggy-0.6.0 py-1.5.2 pytest-3.4.0 pytest-lazy-fixture-0.4.0

When I run pytest I get error:

____________________________________________________ ERROR collecting test/test_split_dataset.py _____________________________________________________
test/test_split_dataset.py:28: in <module>
    "source": pytest.lazy_fixture("dataset_path")
E   AttributeError: module 'pytest' has no attribute 'lazy_fixture'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
============================================================== 1 error in 1.20 seconds ===============================================================

Tests:

@pytest.fixture(scope="module", autouse=True)
def dataset_path(tmpdir_factory):
    p = tmpdir_factory.mktemp("tmp").join("dataset.csv")
    df = pd.DataFrame({
        "a": [1, 2, 3, 4, 5, 6],
        "b": [1, 2, 3, 4, 5, 6],
        "c": [1, 2, 3, 4, 5, 6],
        "d": [1, 2, 3, 4, 5, 6],
    })
    df.to_csv(p, index=False)

    yield str(p)  # all code below it will be executed when session done
    os.remove(str(p))


@pytest.mark.parametrize("test_input,expected", [
    ({
        "input": {
            "format": "csv",
            "source": pytest.lazy_fixture("dataset_path")
        },
        "split": {
            "targets": "c",
            "seeds": [1, 5, 34],
            "params":{
                "train_size": 0.7,
                "random_state": 42
            }
        }
    }, 8)
])
def test_dataset(test_input, expected):
    print(test_input)
    assert False

lazy-fixture on fixture whose argument is a fixture

I am missing something very obvious: Below is my use case as seems best to explain with example:

  • a fixture to create a bunch of parameters
@pytest.fixture(name="hc_tags", params=[("Label", TR.LabelMixin)])
def _hc_tags(request):
    return request.param

  • create derived object from parameter
@pytest.fixture
def Type_HC_Passive_NoStub(hc_tags):
...
return obj
  • create a test parametrized with above fixture (using lazy_fixture):
@pytest.mark.parametrize("Type_HCBase_NoStub",
                         [(lazy_fixture('Type_HC_Passive_NoStub'))]
                         )
def test_lazy(Type_HCBase_NoStub):
    print (Type_HCBase_NoStub)
    assert True

The above results in error:

============================== ERRORS ===============================
_________ ERROR collecting tests_internal/test_internal.py __________
In test_lazy: function uses no fixture 'hc_tags'
====================== short test summary info ======================
ERROR test_internal.py
!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!
========================= 1 error in 1.94s ==========================

Isn't fixture recursive resolution not allowed with lazy fixtures? If so, what is the workaround.

Make LazyFixture iterable

This does work now:

@pytest.mark.parametrize('arg1', [
   pytest.lazy_fixture('needs_db')
])
@pytest.mark.django_db
def test_some(arg1):
    assert ...

But it's not quite what I need. The fixture needs_db returns a list and I'd like to parametrize test_some with that list:

@pytest.mark.parametrize('arg1', pytest.lazy_fixture('needs_db'))
@pytest.mark.django_db
def test_some(arg1):
    assert ...

This fails: TypeError: 'LazyFixture' object is not iterable

Is it possible to support this use case? I'm not familiar with pytest's internals. :/

TypeError: 'LazyFixture' object is not subscriptable

Hi there,

I was trying to do the following code which results in a Exception being thrown. I was wondering if someone has found a way to use the returned object from a lazy_fixture in the parametrize values

import pytest
from pytest_lazyfixture import lazy_fixture

@pytest.fixture
def one():
    return {
        "foo1": "bar",
        "foo2": "baz",
    }

@pytest.mark.parametrize(
    'attr1',
    [
        (lazy_fixture('one')["foo1"], ),
    ]
)
def test_func(attr1):
    assert attr1 == "bar"
============================================================================================================= test session starts =============================================================================================================
platform linux -- Python 3.10.5, pytest-7.1.3, pluggy-1.0.0
rootdir: /home/users/frank/workspace/pseudopiper, configfile: pytest.ini
plugins: xdist-2.5.0, cov-4.0.0, lazy-fixture-0.6.3, clarity-1.0.1, icdiff-0.6, forked-1.4.0
collected 0 items / 1 error

=================================================================================================================== ERRORS ====================================================================================================================
___________________________________________________________________________________________________ ERROR collecting tests/test_foobar2.py ____________________________________________________________________________________________________
tests/test_foobar2.py:14: in <module>
    (lazy_fixture('one')["foo1"], ),
E   TypeError: 'LazyFixture' object is not subscriptable
=========================================================================================================== short test summary info ===========================================================================================================
ERROR tests/test_foobar2.py - TypeError: 'LazyFixture' object is not subscriptable
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
============================================================================================================== 1 error in 0.21s ===============================================================================================================

Use fixture names to generate test ids?

First off, thank you for writing this plugin, it fixes problems that have been bugging me for years.

Given the following tests:

import pytest
from pytest_lazyfixture import lazy_fixture

@pytest.fixture()
def foo():
    return "foo"

@pytest.fixture(params=['spam', 'eggs'])
def bar(request):
    return f"bar-{request.param}"

@pytest.mark.parametrize("data", [lazy_fixture("foo"),
                                  lazy_fixture("bar")])
def test_the_thing(data):
    assert False    

Pytest generates the following test names:

> py.test test_lazy.py --collect-only
===================== test session starts =====================
platform darwin -- Python 3.7.6, pytest-5.3.2, py-1.8.1, pluggy-0.13.1
rootdir: /tmp
plugins: xdist-1.26.1, flask-0.14.0, lazy-fixture-0.6.2, forked-1.1.3
collected 3 items                                                                                                            
<Module test_lazy.py>
  <Function test_the_thing[data0]>
  <Function test_the_thing[data1-spam]>
  <Function test_the_thing[data1-eggs]>

Would it be possible to use the fixture name to generate these ids? It would be great to end up with these names instead:

test_the_thing[foo]
test_the_thing[bar-spam]
test_the_thing[bar-eggs]

Fixtures with pytest.mark.fixture() with parametrize in test functions

Currently the example below doesn't work. I'd expect to produce the equivalent of the last test function.
Probably the parametrize decorator should take precedence over the parametrized fixture, as the other parametrization is not explicit.
Hope to help in development soon.

import pytest


@pytest.fixture(params=[1, 2, 3])
def one(request):
    return request.param


@pytest.fixture(params=[pytest.mark.fixture('one')])
def as_str(request):
    return str(request.getfixturevalue('one'))



# doesn't work. Fixture 'a'/'b'/'c' not found
@pytest.mark.parametrize('val', ('a', 'b', 'c'))
def test_as_str(val, as_str):
    combined = ''.join((val, as_str))
    assert combined in {'a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3'}


# test_as_str expected
@pytest.mark.parametrize('val_2', ('1', '2', '3'))
@pytest.mark.parametrize('val_1', ('a', 'b', 'c'))
def test_parametrize(val_1, val_2):
    combined = ''.join((val_1, val_2))
    assert combined in {'a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3'}

error with pytest==5.3.0

Getting the following error after updating from pytest==5.2.4 to pytest==5.3.0. Using latest pytest-lazy-fixture.

../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pluggy/hooks.py:286: in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pluggy/manager.py:92: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pluggy/manager.py:83: in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/_pytest/python.py:208: in pytest_pycollect_makeitem
    res = outcome.get_result()
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/aiohttp/pytest_plugin.py:155: in pytest_pycollect_makeitem
    return list(collector._genfunctions(name, obj))
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/_pytest/python.py:404: in _genfunctions
    self.ihook.pytest_generate_tests.call_extra(methods, dict(metafunc=metafunc))
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pluggy/hooks.py:324: in call_extra
    return self(**kwargs)
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pluggy/hooks.py:286: in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pluggy/manager.py:92: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pluggy/manager.py:83: in <lambda>
    self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pytest_lazyfixture.py:69: in pytest_generate_tests
    normalize_metafunc_calls(metafunc, 'funcargs')
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pytest_lazyfixture.py:76: in normalize_metafunc_calls
    calls = normalize_call(callspec, metafunc, valtype, used_keys)
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pytest_lazyfixture.py:111: in normalize_call
    newmetafunc = copy_metafunc(metafunc)
../../.pyenv/versions/3.8.0/lib/python3.8/site-packages/pytest_lazyfixture.py:85: in copy_metafunc
    copied._ids = copy.copy(metafunc._ids)
E   AttributeError: 'Metafunc' object has no attribute '_ids'

Broken by pytest 5.3.3

I haven't had time to investigate why, but it seems that the pytest 5.3.3 release broke pytest-lazy-fixture:

Running the basic example from the README

import pytest

@pytest.fixture(params=[1, 2])
def one(request):
    return request.param

@pytest.mark.parametrize('arg1,arg2', [
    ('val1', pytest.lazy_fixture('one')),
])
def test_func(arg1, arg2):
    assert arg2 in [1, 2]

results in the following error:

$ pytest test_lazy_fixture.py 
============================= test session starts ==============================
platform linux -- Python 3.6.9, pytest-5.3.3, py-1.7.0, pluggy-0.12.0
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/yannick/.hypothesis/examples')
rootdir: /home/yannick
plugins: xonsh-0.9.6, lazy-fixture-0.6.2, hypothesis-4.34.0
collected 2 items                                                              

test_lazy_fixture.py EE                                                  [100%]

==================================== ERRORS ====================================
__________________ ERROR at setup of test_func[val1-arg20-1] ___________________
file /home/yannick/test_lazy_fixture.py, line 7
  @pytest.mark.parametrize('arg1,arg2', [
      ('val1', pytest.lazy_fixture('one')),
  ])
  def test_func(arg1, arg2):
file /home/yannick/test_lazy_fixture.py, line 3
  @pytest.fixture(params=[1, 2])
  def one(request):
file /home/yannick/.local/lib/python3.6/site-packages/_pytest/fixtures.py, line 297
  def get_direct_param_fixture_func(request):
E       recursive dependency involving fixture 'one' detected
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, one, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

/home/yannick/.local/lib/python3.6/site-packages/_pytest/fixtures.py:297
__________________ ERROR at setup of test_func[val1-arg20-2] ___________________
file /home/yannick/test_lazy_fixture.py, line 7
  @pytest.mark.parametrize('arg1,arg2', [
      ('val1', pytest.lazy_fixture('one')),
  ])
  def test_func(arg1, arg2):
file /home/yannick/test_lazy_fixture.py, line 3
  @pytest.fixture(params=[1, 2])
  def one(request):
file /home/yannick/.local/lib/python3.6/site-packages/_pytest/fixtures.py, line 297
  def get_direct_param_fixture_func(request):
E       recursive dependency involving fixture 'one' detected
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, one, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

/home/yannick/.local/lib/python3.6/site-packages/_pytest/fixtures.py:297
============================== 2 errors in 0.02s ===============================

If I have time, I'll have a closer look and report back on my findings.

0.5.2 problem with pytest-asyncio

I made a PR to upgrade pytest-lazy-fixture 0.4.2 to 0.5.2.

It worked with 0.4.2 but doesn't work with 0.5.2 anymore. Any idea?

The errors are refering about event loop

E       RuntimeError: Task <Task pending coro=<test_complicated_key() running at /Users/youknowone/Projects/ring/tests/_test_func_asyncio.py:183> cb=[_run_until_complete_cb() at ~/.pyenv/versions/3.7.0/lib/python3.7/asyncio/base_events.py:150]> got Future <Future pending cb=[BaseSelectorEventLoop._sock_connect_done(22)()]> attached to a different loop

Because upgrading pytest-lazy-fixture triggers the problem regardless of pytest-asyncio version, I guessed this may be a regression in pytest-lazy-fixture. Please let me know if the change in pytest-lazy-fixture is not a problem. Then I should change my code to fit in new version.

mark.xfail doesn't seem to work

import pytest
def division(a, b):
    return a / b


@pytest.fixture(params=[0])
def zero(request):
    return request.param


@pytest.mark.parametrize(('a', 'b'), [(1, pytest.lazy_fixture('zero'))])
def test_division(a, b):
    with pytest.raises(ZeroDivisionError):
        division(a, b)

works as expected, but when I try

import pytest
def division(a, b):
    return a / b


@pytest.fixture(params=[0])
def zero(request):
    return request.param


@pytest.mark.parametrize(('a', 'b'), [
    pytest.mark.xfail((1, pytest.lazy_fixture('zero')), reason=ZeroDivisionError)
])
def test_division(a, b):
    division(a, b)

it raises TypeError, traceback

==================================== ERRORS ====================================
_____________________ ERROR collecting tests/test_name.py ______________________
/usr/local/lib/python3.5/dist-packages/_pytest/runner.py:163: in __init__
    self.result = func()
/usr/local/lib/python3.5/dist-packages/_pytest/main.py:464: in _memocollect
    return self._memoizedcall('_collected', lambda: list(self.collect()))
/usr/local/lib/python3.5/dist-packages/_pytest/main.py:335: in _memoizedcall
    res = function()
/usr/local/lib/python3.5/dist-packages/_pytest/main.py:464: in <lambda>
    return self._memoizedcall('_collected', lambda: list(self.collect()))
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:412: in collect
    return super(Module, self).collect()
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:326: in collect
    res = self.makeitem(name, obj)
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:338: in makeitem
    collector=self, name=name, obj=obj)
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:745: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:339: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:334: in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:613: in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:250: in _wrapped_call
    wrap_controller.send(call_outcome)
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:197: in pytest_pycollect_makeitem
    res = list(collector._genfunctions(name, obj))
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:358: in _genfunctions
    self.ihook.pytest_generate_tests(metafunc=metafunc)
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:745: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:339: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:334: in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:613: in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:254: in _wrapped_call
    return call_outcome.get_result()
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:279: in get_result
    raise ex[1].with_traceback(ex[2])
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:265: in __init__
    self.result = func()
/usr/local/lib/python3.5/dist-packages/_pytest/vendored_packages/pluggy.py:614: in execute
    res = hook_impl.function(*args)
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:110: in pytest_generate_tests
    metafunc.parametrize(*marker.args, **marker.kwargs)
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:851: in parametrize
    ids = idmaker(argnames, argvalues, idfn, ids, self.config)
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:962: in idmaker
    for valindex, valset in enumerate(argvalues)]
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:962: in <listcomp>
    for valindex, valset in enumerate(argvalues)]
/usr/local/lib/python3.5/dist-packages/_pytest/python.py:955: in _idvalset
    for val, argname in zip(valset, argnames)]
E   TypeError: zip argument #1 must support iteration
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.65 seconds ============================

Reason to have this feature: to make one test suite for multiple exceptions types, because at the moment I am forced to write a test for each of them.

TypeError: 'LazyFixture' object is not iterable

Hi there,

I am running into issues with using a fixture, that loads a list of parameters that I want to use to parametrize tests. I am not sure, whether that is something, that can be done with your package and I just can't figure it out, or whether that would be a new feature.

Here is a example on what I want to achieve:

import pytest

@pytest.fixture()
def one(tmp_path):
    return list(str(tmp_path))

@pytest.mark.parametrize("char", pytest.lazy_fixture('one'))
def test_func(char):
    assert char.isascii()

Do you have an idea on how to get my code running?

Thanks a lot!

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.