Skip to content

several names for fixture #3655

Closed
Closed

Description

@ggens

@#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)

Activity

  1. pytestbot commented on Jul 3, 2018

    @pytestbot
    Contributor

    GitMate.io thinks possibly related issues are #2934 (capsysbinary fixture), #3377 (Rescope a fixture), #538 (Fixture scope documentation), #794 (fixture named "request" fails), and #484 (Order of class fixtures).

  2. added
    platform: macmac platform-specific problem
    type: enhancementnew feature or API change, should be merged into features branch
    on Jul 3, 2018
  3. added
    type: proposalproposal for a new feature, often to gather opinions or design the API around the new feature
    and removed
    platform: macmac platform-specific problem
    on Jul 4, 2018
  4. nicoddemus commented on Jul 4, 2018

    @nicoddemus
    Member

    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.

  5. RonnyPfannschmidt commented on Jul 4, 2018

    @RonnyPfannschmidt
    Member

    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

  6. added
    status: needs informationreporter needs to provide more information; can be closed after 2 or more weeks of inactivity
    on Jul 4, 2018
  7. ggens commented on Jul 4, 2018

    @ggens
    Author

    @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))
    
  8. RonnyPfannschmidt commented on Jul 4, 2018

    @RonnyPfannschmidt
    Member

    @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

  9. ggens commented on Jul 4, 2018

    @ggens
    Author

    I looked tmpdir factory pattern by my requirement is different of this usage by these points:

    • scope function for fixture_factory
    • many call of this fixture for one test
      ... I don't see how tmpdir factory pattern answer of these points. My requirement is not maybe the good "pytest-way" (or pythonic) but ... one fixture must be only specific behavior ?
  10. RonnyPfannschmidt commented on Jul 4, 2018

    @RonnyPfannschmidt
    Member

    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

  11. nicoddemus commented on Jul 5, 2018

    @nicoddemus
    Member

    @ggens perhaps some example code demonstrating what you want to do (even if it does not work) would help?

  12. ggens commented on Jul 5, 2018

    @ggens
    Author

    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))
    
  13. RonnyPfannschmidt commented on Jul 5, 2018

    @RonnyPfannschmidt
    Member

    @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

  14. nicoddemus commented on Jul 5, 2018

    @nicoddemus
    Member

    @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.

  15. ggens commented on Jul 6, 2018

    @ggens
    Author

    @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.

  16. RonnyPfannschmidt commented on Jul 6, 2018

    @RonnyPfannschmidt
    Member

    currently nobody is working on it, its not clear how to enable it yet

  17. nicoddemus commented on Jul 7, 2018

    @nicoddemus
    Member

    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)
  18. RonnyPfannschmidt commented on Jul 7, 2018

    @RonnyPfannschmidt
    Member

    If that was it they wouldnt add value, -1

  19. ggens commented on Jul 9, 2018

    @ggens
    Author

    @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)

  20. nicoddemus commented on Jul 10, 2018

    @nicoddemus
    Member

    @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).

  21. RonnyPfannschmidt commented on Jul 10, 2018

    @RonnyPfannschmidt
    Member

    @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 ^^

  22. nicoddemus commented on Jul 10, 2018

    @nicoddemus
    Member

    Oh that's a good point. I agree then that we should wait until a more compelling use case appears. 👍

  23. sp-ricard-valverde commented on Jul 28, 2020

    @sp-ricard-valverde

    Sorry to reopen this, but I might have actually found a use case for the multiple naming of a single fixture:

        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:

        @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.

  24. laike9m commented on Dec 5, 2020

    @laike9m

    Would love to see this. Return from another fixture doesn't work if using yield.

  25. The-Compiler commented on Dec 5, 2020

    @The-Compiler
    Member

    Return from another fixture doesn't work if using yield.

    yield from other_fixture probably would though, no?

  26. laike9m commented on Dec 6, 2020

    @laike9m

    Return from another fixture doesn't work if using yield.

    yield from other_fixture probably 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: needs informationreporter needs to provide more information; can be closed after 2 or more weeks of inactivitytype: enhancementnew feature or API change, should be merged into features branchtype: proposalproposal for a new feature, often to gather opinions or design the API around the new feature

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions