A blazingly fast Language Server Protocol (LSP) implementation for pytest, built with Rust, with full support for fixture discovery, go to definition, code completion, find references, hover documentation, diagnostics, and more!
- Features
- Installation
- Setup
- Configuration
- CLI Commands
- Supported Fixture Patterns
- Fixture Priority Rules
- Supported Third-Party Fixtures
- Architecture
- Development
- Security
- Contributing
- License
- Acknowledgments
Built with AI, maintained with care π€
This project was built with the help of AI coding agents, but carefully reviewed to ensure correctness, reliability, security and performance. If you find any issues, please open an issue or submit a pull request!
Jump directly to fixture definitions from anywhere they're used:
- Local fixtures in the same file
- Fixtures in
conftest.pyfiles - Third-party fixtures from pytest plugins (pytest-mock, pytest-asyncio, etc.)
- Respects pytest's fixture shadowing/priority rules
Smart auto-completion for pytest fixtures:
- Context-aware: Only triggers inside test functions and fixture functions
- Hierarchy-respecting: Suggests fixtures based on pytest's priority rules (same file > conftest.py > third-party)
- Rich information: Shows fixture source file and docstring
- No duplicates: Automatically filters out shadowed fixtures
- Works everywhere: Completions available in both function parameters and function bodies
- Supports both sync and async functions
Find all usages of a fixture across your entire test suite:
- Works from fixture definitions or usage sites
- Character-position aware (distinguishes between fixture name and parameters)
- Shows references in all test files
- Correctly handles fixture overriding and hierarchies
- LSP spec compliant: Always includes the current position in results
View fixture information on hover:
- Fixture signature
- Source file location
- Docstring (with proper formatting and dedenting)
- Markdown support in docstrings
One-click fixes for common pytest issues:
- Add missing fixture parameters: Automatically add undeclared fixtures to function signatures
- Smart insertion: Handles both empty and existing parameter lists
- Editor integration: Works with any LSP-compatible editor's quick fix menu
- LSP compliant: Full support for
CodeActionKind::QUICKFIX
Detect and fix common pytest fixture issues with intelligent code actions:
Undeclared Fixture Detection:
- Detects when fixtures are used in function bodies but not declared as parameters
- Line-aware scoping: Correctly handles local variables assigned later in the function
- Hierarchy-aware: Only reports fixtures that are actually available in the current file's scope
- Works in tests and fixtures: Detects undeclared usage in both test functions and fixture functions
- Excludes built-in names (
self,request) and actual local variables
One-Click Quick Fixes:
- Code actions to automatically add missing fixture parameters
- Intelligent parameter insertion (handles both empty and existing parameter lists)
- Works with both single-line and multi-line function signatures
- Triggered directly from diagnostic warnings
Example:
@pytest.fixture
def user_db():
return Database()
def test_user(user_db): # β
user_db properly declared
user = user_db.get_user(1)
assert user.name == "Alice"
def test_broken(): # β οΈ Warning: 'user_db' used but not declared
user = user_db.get_user(1) # π‘ Quick fix: Add 'user_db' fixture parameter
assert user.name == "Alice"How to use quick fixes:
- Place cursor on the warning squiggle
- Trigger code actions menu (usually Cmd+. or Ctrl+. in most editors)
- Select "Add 'fixture_name' fixture parameter"
- The parameter is automatically added to your function signature
Built with Rust for maximum performance:
- Fast workspace scanning with concurrent file processing
- Efficient AST parsing using rustpython-parser
- Lock-free data structures with DashMap
- Minimal memory footprint
Choose your preferred installation method:
The easiest way to install for Python projects:
# Using uv (recommended)
uv tool install pytest-language-server
# Or with pip
pip install pytest-language-server
# Or with pipx (isolated environment)
pipx install pytest-language-serverInstall via Homebrew for system-wide availability:
brew install bellini666/tap/pytest-language-serverTo add the tap first:
brew tap bellini666/tap https://github.com/bellini666/pytest-language-server
brew install pytest-language-serverInstall from crates.io if you have Rust installed:
cargo install pytest-language-serverDownload pre-built binaries from the GitHub Releases page.
Available for:
- Linux: x86_64, aarch64, armv7 (glibc and musl)
- macOS: Intel and Apple Silicon
- Windows: x64 and x86
Build from source for development or customization:
git clone https://github.com/bellini666/pytest-language-server
cd pytest-language-server
cargo build --releaseThe binary will be at target/release/pytest-language-server.
Add this to your config:
vim.lsp.config('pytest_lsp', {
cmd = { 'pytest-language-server' },
filetypes = { 'python' },
root_markers = { 'pyproject.toml', 'setup.py', 'setup.cfg', 'pytest.ini', '.git' },
})
vim.lsp.enable('pytest_lsp')Install from the Zed Extensions Marketplace:
- Open Zed
- Open the command palette (Cmd+Shift+P / Ctrl+Shift+P)
- Search for "zed: extensions"
- Search for "pytest Language Server"
- Click "Install"
The extension downloads platform-specific binaries from GitHub Releases. If you prefer to use your own installation (via pip, cargo, or brew), place pytest-language-server in your PATH.
The extension includes pre-built binaries - no separate installation required!
Install from the Visual Studio Marketplace:
- Open VS Code
- Go to Extensions (Cmd+Shift+X / Ctrl+Shift+X)
- Search for "pytest Language Server"
- Click "Install"
Works out of the box with zero configuration!
The plugin includes pre-built binaries - no separate installation required!
Install from the JetBrains Marketplace:
- Open PyCharm or IntelliJ IDEA
- Go to Settings/Preferences β Plugins
- Search for "pytest Language Server"
- Click "Install"
Requires PyCharm 2024.2+ or IntelliJ IDEA 2024.2+ with Python plugin.
Any editor with LSP support can use pytest-language-server. Configure it to run the pytest-language-server command.
Control log verbosity with the RUST_LOG environment variable:
# Minimal logging (default)
RUST_LOG=warn pytest-language-server
# Info level
RUST_LOG=info pytest-language-server
# Debug level (verbose)
RUST_LOG=debug pytest-language-server
# Trace level (very verbose)
RUST_LOG=trace pytest-language-serverLogs are written to stderr, so they won't interfere with LSP communication.
The server automatically detects your Python virtual environment:
- Checks for
.venv/,venv/, orenv/in your project root - Falls back to
$VIRTUAL_ENVenvironment variable - Scans third-party pytest plugins for fixtures
Code actions are automatically available on diagnostic warnings. If code actions don't appear in your editor:
- Check LSP capabilities: Ensure your editor supports code actions (most modern editors do)
- Enable debug logging: Use
RUST_LOG=infoto see if actions are being created - Verify diagnostics: Code actions only appear where there are warnings
- Trigger manually: Use your editor's code action keybinding (Cmd+. / Ctrl+.)
In addition to the LSP server mode, pytest-language-server provides useful command-line tools:
View all fixtures in your test suite with a hierarchical tree view:
# List all fixtures
pytest-language-server fixtures list tests/
# Skip unused fixtures
pytest-language-server fixtures list tests/ --skip-unused
# Show only unused fixtures
pytest-language-server fixtures list tests/ --only-unusedThe output includes:
- Color-coded display: Files in cyan, directories in blue, used fixtures in green, unused in gray
- Usage statistics: Shows how many times each fixture is used
- Smart filtering: Hides files and directories with no matching fixtures
- Hierarchical structure: Visualizes fixture organization across conftest.py files
Example output:
Fixtures tree for: /path/to/tests
conftest.py (7 fixtures)
βββ another_fixture (used 2 times)
βββ cli_runner (used 7 times)
βββ database (used 6 times)
βββ generator_fixture (used 1 time)
βββ iterator_fixture (unused)
βββ sample_fixture (used 7 times)
βββ shared_resource (used 5 times)
subdir/
βββ conftest.py (4 fixtures)
βββ cli_runner (used 7 times)
βββ database (used 6 times)
βββ local_fixture (used 4 times)
βββ sample_fixture (used 7 times)
This command is useful for:
- Auditing fixture usage across your test suite
- Finding unused fixtures that can be removed
- Understanding fixture organization and hierarchy
- Documentation - visualizing available fixtures for developers
@pytest.fixture
def my_fixture():
"""Fixture docstring."""
return 42mocker = pytest.fixture()(_mocker)@pytest.fixture
async def async_fixture():
return await some_async_operation()@pytest.fixture
def fixture_a():
return "a"
@pytest.fixture
def fixture_b(fixture_a): # Go to definition works on fixture_a
return fixture_a + "b"pytest-language-server correctly implements pytest's fixture shadowing rules:
- Same file: Fixtures defined in the same file have highest priority
- Closest conftest.py: Searches parent directories for conftest.py files
- Virtual environment: Third-party plugin fixtures
The LSP correctly handles complex fixture overriding scenarios:
# conftest.py (parent)
@pytest.fixture
def cli_runner():
return "parent runner"
# tests/conftest.py (child)
@pytest.fixture
def cli_runner(cli_runner): # Overrides parent
return cli_runner # Uses parent
# tests/test_example.py
def test_example(cli_runner): # Uses child
passWhen using find-references:
- Clicking on the function name
def cli_runner(...)shows references to the child fixture - Clicking on the parameter
cli_runner(cli_runner)shows references to the parent fixture - Character-position aware to distinguish between the two
Automatically discovers fixtures from 50+ popular pytest plugins, including:
- Testing frameworks: pytest-mock, pytest-asyncio, pytest-bdd, pytest-cases
- Web frameworks: pytest-flask, pytest-django, pytest-aiohttp, pytest-tornado, pytest-sanic, pytest-fastapi
- HTTP clients: pytest-httpx
- Databases: pytest-postgresql, pytest-mongodb, pytest-redis, pytest-mysql, pytest-elasticsearch
- Infrastructure: pytest-docker, pytest-kubernetes, pytest-rabbitmq, pytest-celery
- Browser testing: pytest-selenium, pytest-playwright, pytest-splinter
- Performance: pytest-benchmark, pytest-timeout
- Test data: pytest-factoryboy, pytest-freezegun, pytest-mimesis
- And many more...
The server automatically scans your virtual environment for any pytest plugin and makes their fixtures available.
- Language: Rust π¦
- LSP Framework: tower-lsp
- Parser: rustpython-parser
- Concurrency: tokio async runtime
- Data Structures: DashMap for lock-free concurrent access
- Rust 1.83+ (2021 edition)
- Python 3.10+ (for testing)
cargo build --releasecargo testRUST_LOG=debug cargo runSecurity is a priority. This project includes:
- Automated dependency vulnerability scanning (cargo-audit)
- License compliance checking (cargo-deny)
- Daily security audits in CI/CD
- Dependency review on pull requests
- Pre-commit security hooks
See SECURITY.md for our security policy and how to report vulnerabilities.
Contributions are welcome! Please feel free to submit a Pull Request.
-
Install pre-commit hooks:
pre-commit install
-
Run security checks locally:
cargo audit cargo clippy cargo test
MIT License - see LICENSE file for details.
Built with:
- tower-lsp - LSP framework
- rustpython-parser - Python AST parsing
- tokio - Async runtime
Special thanks to the pytest team for creating such an amazing testing framework.
Made with β€οΈ and Rust. Blazingly fast π₯
Built with AI assistance, maintained with care.
