tvorog / pytest-lazy-fixture Goto Github PK
View Code? Open in Web Editor NEWIt helps to use fixtures in pytest.mark.parametrize
License: MIT License
It helps to use fixtures in pytest.mark.parametrize
License: MIT License
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
For example:
class TestModels(TestCase):
def setUp(self):
....
def test_models(self):
....
Any ideas?
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. :/
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.
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
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
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
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!
For example:
class TestModels(object):
@pytest.mark.skip(reason='skip this')
def test_model(self):
....
....
Any ideas?
I am missing something very obvious: Below is my use case as seems best to explain with example:
@pytest.fixture(name="hc_tags", params=[("Label", TR.LabelMixin)])
def _hc_tags(request):
return request.param
@pytest.fixture
def Type_HC_Passive_NoStub(hc_tags):
...
return obj
@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.
in pytest we are in the process of deprecating the pytest_namespace hook, so this plugin would need a new location for its api that works when that hook is removed
Hi! pytest-lazy-fixture
doesn't work with pytest==8.0.0
AttributeError: 'CallSpec2' object has no attribute 'funcargs'
When I downgraded it to 0.4.1, the problem is fixed.
Examples
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.
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}')
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 ======================================================================
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.
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?
# -*- 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
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)
Here is a simple example:
@pytest.fixture(autouse=True)
def fixture(request):
yield
It will raise StopIteration
.
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'
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.
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?
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
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]>
Please include the tests in the source distribution. See https://build.opensuse.org/request/show/673508
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 ===========================
Sorry, I posted this issue in the wrong Repo! Please delete.
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?
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.
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]
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.
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
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?
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
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
.
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'}
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 ===============================================================================================================
Is there a release in pypi?
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.