python · sanjeed5 — Cursor rule: what it does, how to install
This Cursor rule sets conventions for Python files, from formatting and imports to typing, packaging, and tests. Use it when a project needs one consistent code style.
.cursor/rules/python.mdcWhat python does
The rule targets **/*.py files and builds its guidance on PEP 8. It defines four-space indentation, an 88-character line limit, spacing between declarations, and naming patterns for modules, classes, functions, variables, and constants. Black or Ruff can enforce formatting, while isort keeps imports grouped and ordered.
Public modules, classes, and functions should carry reStructuredText-style docstrings. Function signatures receive type annotations, with mypy available for static checks. The suggested package layout uses src/, pyproject.toml, README.md, LICENSE, and tests/.
The rule requires Poetry or Pipenv for dependency management and isolated environments. Tests use pytest, with pytest-cov for coverage and unittest.mock or pytest-mock for isolation. A project using neither Poetry nor Pipenv conflicts with this rule’s environment requirement.
What it helps with
- format Python code around PEP 8
- sort imports into clear groups
- standardize names across a codebase
- add docstrings and type annotations
- organize tests with
pytest
Example prompts for the agent
- Apply the Python rules to
app.pywithout changing its behavior. - Review every file under
src/for imports, naming, and type annotations. - Suggest a package layout with
src/,pyproject.toml, andtests/.
How to install python
Manually: put the files in place
.cursor/rules/python.mdcFrontmatter: description, globs, alwaysApply
Manually: put the files in place
.claude/rules/python.mdThe paths frontmatter field limits the files: move globs from the source into paths
AGENTS.md
Codex reads AGENTS.md: paste the rule text there
Manually: put the files in place
.github/instructions/python.instructions.mdThe applyTo field sets which files it applies to: move globs from the source into applyTo
Manually: put the files in place
.devin/rules/python.mdManually: put the files in place
.clinerules/python.mdStep by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules
Questions about python
How do I install python in Cursor?
Add the rule file at .cursor/rules/python.mdc inside the Cursor project.
What does the python rule do?
It guides formatting, imports, naming, documentation, type hints, project layout, environment management, and Python tests.
Which tools does the rule expect?
It points to Black or Ruff, isort, mypy, Poetry or Pipenv, plus pytest and pytest-cov.
Source text
python.mdc · CC0-1.0
---
description: This guide defines the definitive Python best practices for our team, focusing on readability, maintainability, and modern development standards. Adhere to these rules for consistent, high-quality Python code.
globs: **/*.py
---
# python Best Practices
This document outlines the definitive Python best practices for our team. Adherence ensures consistent, readable, and maintainable code across all projects. We prioritize **PEP 8** as the foundation, augmented with modern tooling and patterns.
## 1. Code Layout & Formatting
Always adhere to PEP 8. Use an auto-formatter like `Black` or `Ruff` to enforce consistency.
* **Indentation**: Use 4 spaces. Never tabs.
* **Line Length**: Limit lines to 88 characters. Docstrings and comments should ideally wrap at 72 characters.
* **Blank Lines**:
* Two blank lines between top-level functions and classes.
* One blank line between methods within a class.
* One blank line to separate logical sections within functions/methods.
❌ BAD:
```python
def my_func():
x = 1
y = 2
return x + y
class MyClass:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, {self.name}!")
```
✅ GOOD:
```python
def my_function():
x = 1
y = 2
# Separate logical steps
result = x + y
return result
class MyClass:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, {self.name}!")
```
## 2. Imports
Organize imports for clarity and to prevent circular dependencies. Use `isort` to automate this.
* **Grouping**:
1. Standard library imports.
2. Third-party library imports.
3. Local application/project-specific imports.
* **Alphabetical Order**: Sort imports alphabetically within each group.
* **Absolute Imports**: Prefer absolute imports over relative imports.
❌ BAD:
```python
import os, sys
from my_package.sub_module import some_function
import requests
from .another_module import another_function
```
✅ GOOD:
```python
import os
import sys
import requests
from my_package.sub_module import some_function
from my_package.another_module import another_function
```
## 3. Naming Conventions
Follow PEP 8 naming conventions strictly.
* **Modules**: `lowercase_with_underscores`
* **Packages**: `lowercase_with_underscores`
* **Classes**: `CamelCase`
* **Functions/Methods**: `lowercase_with_underscores`
* **Variables**: `lowercase_with_underscores`
* **Constants**: `UPPERCASE_WITH_UNDERSCORES`
* **Protected Members**: `_single_leading_underscore` (internal use)
* **Private Members**: `__double_leading_underscore` (name mangling, avoid unless necessary for mixins)
❌ BAD:
```python
class myClass: # Class name not CamelCase
def Get_Data(self): # Method name not lowercase_with_underscores
MY_VAR = 10 # Variable name not lowercase_with_underscores
return MY_VAR
```
✅ GOOD:
```python
class MyClass:
def get_data(self):
my_var = 10
return my_var
GLOBAL_CONSTANT = 100
```
## 4. Docstrings & Comments
Document all public modules, classes, and functions using PEP 257 docstring conventions. Use reStructuredText format for Sphinx compatibility.
* **Module Docstrings**: Top of the file, after `__future__` imports.
* **Class Docstrings**: First line after the class definition.
* **Function/Method Docstrings**: First line after the `def` statement.
* **Comments**: Use sparingly for *why* code exists, not *what* it does.
❌ BAD:
```python
def calculate_sum(a, b): # This function adds two numbers
return a + b
```
✅ GOOD:
```python
def calculate_sum(a: int, b: int) -> int:
"""Calculate the sum of two integers.
:param a: The first integer.
:param b: The second integer.
:return: The sum of a and b.
:raises TypeError: If a or b are not integers.
"""
if not isinstance(a, int) or not isinstance(b, int):
raise TypeError("Inputs must be integers.")
return a + b
```
## 5. Type Hints
**Always use type hints.** They improve readability, enable static analysis with `mypy`, and catch errors early.
* **All Function Signatures**: Annotate parameters and return types.
* **Variables**: Annotate complex or ambiguous variable types.
* **`typing` module**: Use `List`, `Dict`, `Optional`, `Union`, `Callable`, `Any`, etc.
* **`TypeAlias`**: For complex type signatures.
❌ BAD:
```python
def process_data(data):
# ...
return len(data)
def get_user(user_id):
# ...
return {"id": user_id, "name": "Test"}
```
✅ GOOD:
```python
from typing import Dict, Any, List, Optional, Union, TypeAlias
UserId: TypeAlias = Union[int, str]
def process_data(data: List[str]) -> int:
"""Processes a list of strings and returns its length."""
return len(data)
def get_user(user_id: UserId) -> Optional[Dict[str, Any]]:
"""Retrieves user data by ID."""
if user_id == 1:
return {"id": 1, "name": "Alice"}
return None
```
## 6. Virtual Environments
**Mandatory for all projects.** Use `Poetry` or `Pipenv` for dependency management and environment isolation.
* **Poetry**: Recommended for new projects due to superior dependency resolution and packaging features.
* **Pipenv**: Acceptable for existing projects already using it.
* **Never commit `venv/` directories.**
❌ BAD:
```bash
# Installing directly into global Python environment
pip install requests black
```
✅ GOOD:
```bash
# Using Poetry
poetry new my_project
cd my_project
poetry add requests black --group dev
poetry run python my_script.py
# Using Pipenv
mkdir my_project && cd my_project
pipenv install requests
pipenv install black --dev
pipenv run python my_script.py
```
## 7. Packaging
Structure projects for easy distribution and installation.
* **`src/` Layout**: Place all package code inside a `src/` directory.
* **`pyproject.toml`**: Use this for project metadata and build configuration (PEP 621).
* **`README.md`**: Comprehensive project description.
* **`LICENSE`**: Clearly state the project's license.
❌ BAD:
```
my_project/
├── my_module.py
├── setup.py # Old style
└── requirements.txt
```
✅ GOOD:
```
my_project/
├── src/
│ └── my_package/
│ ├── __init__.py
│ └── main.py
├── pyproject.toml
├── README.md
├── LICENSE
└── tests/
└── test_main.py
```
## 8. Testing Approaches
**Automated testing is non-negotiable.** Use `pytest` for all tests.
* **`pytest`**: The standard test runner.
* **Coverage**: Integrate `pytest-cov` to ensure adequate test coverage. Aim for >90%.
* **Fixtures**: Use `pytest` fixtures for setup and teardown.
* **Parametrization**: Use `pytest.mark.parametrize` for testing multiple inputs.
* **Mocks**: Use `unittest.mock` (or `pytest-mock`) for isolating units under test.
* **Test-Driven Development (TDD)**: Strongly encouraged. Write tests before code.
❌ BAD:
```python
# No tests, or using unittest.TestCase directly without pytest
def add(a, b):
return a + b
# Manual testing
print(add(1, 2))
```
✅ GOOD:
```python
# src/my_package/math.py
def add(a: int, b: int) -> int:
return a + b
# tests/test_math.py
import pytest
from src.my_package.math import add
@pytest.mark.parametrize("a, b, expected", [
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
])
def test_add(a: int, b: int, expected: int):
assert add(a, b) == expected
def test_add_raises_type_error():
with pytest.raises(TypeError):
add("1", 2) # type: ignore
```
## 9. Common Patterns & Anti-patterns
* **Context Managers**: Use `with` statements for resource management.
❌ BAD:
```python
f = open("file.txt", "r")
data = f.read()
f.close() # Easy to forget or miss on error
```
✅ GOOD:
```python
with open("file.txt", "r") as f:
data = f.read()
# File is automatically closed
```
* **List Comprehensions/Generator Expressions**: For concise data transformations.
❌ BAD:
```python
squares = []
for i in range(10):
squares.append(i * i)
```
✅ GOOD:
```python
squares = [i * i for i in range(10)]
```
* **F-strings**: Prefer `f-strings` for string formatting.
❌ BAD:
```python
name = "Alice"
age = 30
print("Hello, %s. You are %d years old." % (name, age))
print("Hello, {}. You are {} years old.".format(name, age))
```
✅ GOOD:
```python
name = "Alice"
age = 30
print(f"Hello, {name}. You are {age} years old.")
```
* **Caveat**: Avoid complex expressions or function calls inside f-strings. Assign to a variable first.
* **Enums**: Use `enum.Enum` for symbolic constants.
❌ BAD:
```python
STATUS_PENDING = "pending"
STATUS_COMPLETED = "completed"
```
✅ GOOD:
```python
from enum import Enum
class Status(Enum):
PENDING = "pending"
COMPLETED = "completed"
current_status = Status.PENDING
```
* **Avoid Mutable Default Arguments**: This is a common pitfall.
❌ BAD:
```python
def add_item(item, item_list=[]): # item_list is created once
item_list.append(item)
return item_list
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] - unexpected!
```
✅ GOOD:
```python
from typing import List, Optional
def add_item(item: Any, item_list: Optional[List[Any]] = None) -> List[Any]:
if item_list is None:
item_list = []
item_list.append(item)
return item_list
print(add_item(1)) # [1]
print(add_item(2)) # [2]
```
* **Catch Specific Exceptions**: Never use bare `except:`.
❌ BAD:
```python
try:
# risky operation
except: # Catches ALL exceptions, including SystemExit, KeyboardInterrupt
print("An error occurred.")
```
✅ GOOD:
```python
try:
result = 1 / 0
except ZeroDivisionError:
print("Cannot divide by zero.")
except Exception as e: # Catching a broader base for unexpected errors
print(f"An unexpected error occurred: {e}")
```
© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc
Similar IDE rules
All IDE rules for Programming languages →python by other authors comes first.