@#hello everyone,
I've suggestion, Is it possible to add list string management for name parameter ?
@pytest.fixture(name=[ 'name_1', 'name_2])
def fixture_factory:
...
of course request.fixturename == 'name_1' or 'name_2' (depends fixture call by test)
GitMate.io thinks possibly related issues are https://github.com/pytest-dev/pytest/issues/2934 (capsysbinary fixture), https://github.com/pytest-dev/pytest/issues/3377 (Rescope a fixture), https://github.com/pytest-dev/pytest/issues/538 (Fixture scope documentation), https://github.com/pytest-dev/pytest/issues/794 (fixture named "request" fails), and https://github.com/pytest-dev/pytest/issues/484 (Order of class fixtures).
Hi @ggens, thanks for writing.
The current workaround for that is:
@pytest.fixture(name='name_1')
def fixture_factory_1():
...
@pytest.fixture(name='name_2')
def fixture_factory_2(name_1):
return name_1
But I'm curious, what use cases do you have in mind?
One that I can think of is deprecating one fixture name over the another (for example), but even in that case I would still want to raise a deprecation warning on the deprecated fixture.
the main issue that op didnt explain what he/she wants to actually do
without the use-case we have no idea whats actually meant
@RonnyPfannschmidt , I would like collect request.fixturename to pass into class factory.
```
class abstract_factory(object):
def __new__(cls, fixturename):
if fixturename == "fixture_1":
return str(cls)
if fixturename == "fixture_2":
return bool(cls)
@pytest.fixture(name=[ 'fixture_1', 'fixture_2'])
def fixture_factory(request):
return abstract_factory(request.fixturename)
def test_fixture_factory(fixture_1,fixture_2):
assert not isinstance(fixture_1,type(fixture_2))
```
@ggens based on your examples its a much better pattern to just declare a factory fixture and use it from other fixtures like pytests own tmpdir factory for example
I looked tmpdir factory pattern by my requirement is different of this usage by these points:
one thing is certain, you are not describing your actual use-case as long as you dont, there is nothing we can do to help you, im not going to participate in this as longer as its just a X-Y problem
@ggens perhaps some example code demonstrating what you want to do (even if it does not work) would help?
my actual case seems :
class abstract_factory(object):
def __new__(cls, fixturename):
if fixturename == "fixture_1":
return str(cls)
if fixturename == "fixture_2":
return bool(cls)
@pytest.fixture
def fixture_1(request):
return abstract_factory("fixture_1")
@pytest.fixture
def fixture_2(request):
return abstract_factory("fixture_2")
def test_fixture_factory(fixture_1,fixture_2):
assert not isinstance(fixture_1,type(fixture_2))
```
... and i would like just this
class abstract_factory(object):
def __new__(cls, fixturename):
if fixturename == "fixture_1":
return str(cls)
if fixturename == "fixture_2":
return bool(cls)
@pytest.fixture(name=[ 'fixture_1', 'fixture_2'])
def fixture_factory(request):
return abstract_factory(request.fixturename)
def test_fixture_factory(fixture_1,fixture_2):
assert not isinstance(fixture_1,type(fixture_2))
```
@ggens that is a specific example if a implementation that is trimmed down so much that tis no longer a use-case, but rather a disconnected code example of no value
@ggens thanks for posting, but as @RonnyPfannschmidt said, your examples doesn't convey why the 1st example is much superior to the second, besides being just a little shorter (17 vs 13 lines).
Can you post real world scenarios where this would be useful? I can see it being used whenever someone has a factory and a fixed set of instantiations, but this seems like a rare use case.
@RonnyPfannschmidt @nicoddemus afterthought , I'm agree with you. It's too specific case which does not bring anything.
Well, I think new design for my case but should need class fixture
May you talk me about this ? is it planned ? just an idea? people work on this feature ? ( i'm really interested to participate)
thanks a lot again.
currently nobody is working on it, its not clear how to enable it yet
Thanks @ggens,
FWIW, this is how I imagine class fixtures would work:
@pytest.fixture(scope='module')
class MyFixture:
def __init__(self, tmpdir):
...
Would be the equivalent of:
@pytest.fixture(scope='module')
def my_fixture(tmpdir):
class MyFixture:
def __init__(self, tmpdir):
...
return MyFixture(tmpdir)
If that was it they wouldnt add value, -1
@RonnyPfannschmidt I'm not agree with you, example of @nicoddemus show an add value with the first case: Avoiding to encapsulate class in function for potentially an other usage (and it's join my issue in my current work)
@RonnyPfannschmidt I don't see much value either, but I think if this can be implemented cleanly and non-intrusively I wouldn't mind adding it (unless we can already foresee problems with the approach).
@nicoddemus i am very strictly opposed to burning class level fixtures as just a new way to spell functions when we could get real and actual interaction out of it ^^
Oh that's a good point. I agree then that we should wait until a more compelling use case appears. 馃憤
Sorry to reopen this, but I might have actually found a use case for the multiple naming of a single fixture:
````python
def path_glob(...):
# some function to be tested
@pytest.fixture
def match_files(request):
files = request.param
return {f.replace('/', os.sep) for f in files}
@pytest.fixture
def unmatch_files(request):
files = request.param
return {f.replace('/', os.sep) for f in files}
@pytest.mark.parametrize('mkfiles, match_files, path, expr', [
({'file_a.txt', 'file_b.txt'}, {'file_a.txt', 'file_b.txt'}, '.', '*.txt'),
({'file_a.txt', 'dir/file_b.txt'}, {'file_a.txt'}, '.', '*.txt'),
({'file_a.txt', 'dir/file_b.txt'}, {'file_a.txt', 'dir/file_b.txt'}, '.', '**/*.txt'),
({'file_a.txt', 'dir/file_b.txt'}, {'dir/file_b.txt'}, 'dir', '*.txt'),
({'file_A.txt'}, {'file_A.txt'}, '.', '*.txt'),
({'.file_a.txt'}, {'.file_a.txt'}, '.', '*.txt')
], indirect=['mkfiles', 'match_files'])
def test_path_glob_ok(self, chdir_tmp, mkfiles, match_files, path, expr):
found_files = path_glob(Path(path), expr)
found_files_set = {str(f) for f in found_files}
assert found_files_set == match_files
@pytest.mark.parametrize('mkfiles, unmatch_files, path, expr', [
({'file_a.txt', 'file_b.png'}, {'file_b.png'}, '.', '*.txt'),
({'file_a.txt', 'file_b.txt', 'dir/file_c.txt'}, {'dir/file_c.txt'}, '.', '*.txt')
], indirect=['mkfiles', 'unmatch_files'])
def test_path_glob_ok_unmatch(self, chdir_tmp, mkfiles, unmatch_files, path, expr):
found_files = path_glob(Path(path), expr)
found_files_set = {str(f) for f in found_files}
assert not (found_files_set & unmatch_files)
````
In this case match_files and unmatch_files could easily be the same fixture with different appropriate names, but the alternate solution:
````python
@pytest.fixture
def match_files(request):
files = request.param
return {f.replace('/', os.sep) for f in files}
@pytest.fixture
def unmatch_files(match_files):
return match_files
````
Won't work as the request context is lost and cannot be passed from unmatch_files to match_files.
Would love to see this. Return from another fixture doesn't work if using yield.
Return from another fixture doesn't work if using
yield.
yield from other_fixture probably would though, no?
Return from another fixture doesn't work if using
yield.
yield from other_fixtureprobably would though, no?
Which gives the error "Fixtures are not meant to be called directly"
I have not found a good way to reuse a fixture without defining a non-fixture function and call it in both fixtures.
Most helpful comment
Thanks @ggens,
FWIW, this is how I imagine class fixtures would work:
Would be the equivalent of: