Skip to content

Support pytest_plugins Variable for Fixture Discovery #77

@benediktziegler

Description

@benediktziegler

Summary

Implement automatic resolution and loading of fixtures declared via the pytest_plugins variable at module level.

Background

Pytest supports a pytest_plugins variable that allows users to declare fixture modules that should be loaded. This is commonly used in conftest.py files to import fixtures from external modules or packages without explicit imports.

# conftest.py
pytest_plugins = ["myapp.fixtures", "other.fixtures"]

Currently, the language server does not resolve these declarations, meaning fixtures from pytest_plugins modules are not discoverable for go-to-definition, completions, or other LSP features.

Requirements

Supported Syntax

All valid pytest_plugins syntax forms should be supported:

  • Single string: pytest_plugins = "myapp.fixtures"
  • List: pytest_plugins = ["module1", "module2"]
  • Tuple: pytest_plugins = ("module1", "module2")

Supported Locations

The pytest_plugins variable should be parsed in:

  1. conftest.py - Plugin registration for all tests in the directory tree
  2. Test files (test_*.py, *_test.py) - File-specific plugins
  3. Plugin entry point modules - Transitive plugin loading

Resolution Logic

  1. Parse pytest_plugins assignments during file analysis
  2. Extract only static string literals (expressions/variables should be skipped since they can't be resolved statically)
  3. Resolve module paths to actual files using the same logic as imports
  4. Recursively analyze plugin modules for fixtures
  5. Recursively process any pytest_plugins declarations in those modules (transitive loading)

Limitations

  • Dynamic values not supported: If pytest_plugins is assigned a variable, function call, or any non-literal expression, it will be skipped
  • Conditional declarations not supported: pytest_plugins inside if blocks will not be detected (consistent with other fixture limitations)

Expected Outcome

# conftest.py
pytest_plugins = ["myapp.fixtures", "other.fixtures"]

# test_example.py
def test_something(fixture_from_myapp):
    # Go-to-definition on fixture_from_myapp should work
    # Completions should suggest fixtures from myapp.fixtures
    pass

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions