pytest-language-server 🔥
Shamelessly vibed into existence 🤖✨
This entire LSP implementation was built from scratch in a single AI-assisted coding session. No template. No boilerplate. Just pure vibes and Rust. That's right - a complete, working Language Server Protocol implementation for pytest, vibed into reality through the power of modern AI tooling. Even this message about vibing was vibed into existence.
A blazingly fast Language Server Protocol (LSP) implementation for pytest, built with Rust.
Features
🎯 Go to Definition
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
🔍 Find References
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
📚 Hover Documentation
View fixture information on hover:
- Fixture signature
- Source file location
- Docstring (with proper formatting and dedenting)
- Markdown support in docstrings
⚡️ Performance
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
Installation
Choose your preferred installation method:
📦 PyPI (Recommended)
The easiest way to install for Python projects:
# Using uv (recommended)
# Or with pip
# Or with pipx (isolated environment)
🍺 Homebrew (macOS/Linux)
Install via Homebrew for system-wide availability:
To add the tap first:
🦀 Cargo (Rust)
Install from crates.io if you have Rust installed:
📥 Pre-built Binaries
Download 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
🔨 From Source
Build from source for development or customization:
The binary will be at target/release/pytest-language-server.
Setup
Neovim (with nvim-lspconfig)
require..
Zed
Install the extension from the 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 will automatically detect pytest-language-server if it's in your PATH.
VS Code
Install the extension from the marketplace (coming soon) or configure manually:
Other Editors
Any editor with LSP support can use pytest-language-server. Configure it to run the pytest-language-server command.
Configuration
Logging
Control log verbosity with the RUST_LOG environment variable:
# Minimal logging (default)
RUST_LOG=warn
# Info level
RUST_LOG=info
# Debug level (verbose)
RUST_LOG=debug
# Trace level (very verbose)
RUST_LOG=trace
Logs are written to stderr, so they won't interfere with LSP communication.
Virtual Environment Detection
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
Supported Fixture Patterns
Decorator Style
"""Fixture docstring."""
return 42
Assignment Style (pytest-mock)
=
Async Fixtures
return await
Fixture Dependencies
return
# Go to definition works on fixture_a
return +
Fixture Priority Rules
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
Fixture Overriding
The LSP correctly handles complex fixture overriding scenarios:
# conftest.py (parent)
return
# tests/conftest.py (child)
# Overrides parent
return # Uses parent
# tests/test_example.py
# Uses child
pass
When 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
Supported Third-Party Fixtures
Automatically discovers fixtures from popular pytest plugins:
- pytest-mock:
mocker,class_mocker - pytest-asyncio:
event_loop - pytest-django: Database fixtures
- pytest-cov: Coverage fixtures
- And any other pytest plugin in your environment
Architecture
- Language: Rust 🦀
- LSP Framework: tower-lsp
- Parser: rustpython-parser
- Concurrency: tokio async runtime
- Data Structures: DashMap for lock-free concurrent access
Development
Prerequisites
- Rust 1.83+ (2021 edition)
- Python 3.10+ (for testing)
Building
Running Tests
Logging During Development
RUST_LOG=debug
Security
Security 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.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Development Setup
-
Install pre-commit hooks:
-
Run security checks locally:
License
MIT License - see LICENSE file for details.
Acknowledgments
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. Shamelessly vibed into existence. Blazingly fast. 🔥
When you need a pytest LSP and the vibes are just right. ✨