Basic Series 3 - Python Code Formatting with Black and isort
This guide shows you how to automatically format your Python code using Black and isort, so your project stays clean, consistent, and easy to read (even at 3 a.m. after too much coffee).
What Are Black and isort?
- Black: An opinionated Python code formatter that auto-formats your code to follow PEP 8 style (so you can stop arguing about whitespace with your teammates).
- isort: Automatically sorts and organizes your imports into neat, logical sections.
⚠️ Heads up: Black and isort can sometimes fight over formatting. To avoid this, always configure isort to use Black’s style.
Installing Black and isort
# Install both tools
pip install black isort
# Or add them as dev dependencies with uv
uv add black isort --dev
How to Use Black and isort
Using Black
# Format a single file
black your_file.py
# Format an entire directory
black your_directory/
# Format specific files
black file1.py file2.py
# Check what would be changed (without modifying)
black --check your_file.py
# Format all Python files in the current directory
black .
Using isort
# Sort imports in a single file
isort your_file.py
# Sort imports in an entire directory
isort your_directory/
# Sort imports in specific files
isort file1.py file2.py
# Check for changes without actually changing files
isort --check-only your_file.py
Configuring Black and isort
Black
Create a pyproject.toml
in your project root (if you’re using uv
, it may already exist):
[tool.black]
line-length = 88
target-version = ['py38']
include = '\.pyi?$'
exclude = '''
/(
\.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
'''
isort
Add this to the same pyproject.toml
:
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 88
Setting
profile = "black"
makes sure isort and Black play nicely together.
IDE Integration
VS Code
{
"[python]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"editor.defaultFormatter": "black"
}
}
PyCharm
- Install the BlackConnect plugin.
- Install the isort plugin.
- Configure both under Settings → Tools.
Before and After Example
Before
from datetime import datetime
import os
import sys
from typing import List,Dict
def my_function( x: int,y: int )->int:
return x+y
After Black and isort
import os
import sys
from datetime import datetime
from typing import Dict, List
def my_function(x: int, y: int) -> int:
return x + y
Best Practices
- Use the same config across your team: Avoid “it works on my machine” chaos.
- Set up pre-commit hooks: Auto-format code before you even push.
- Add checks to CI/CD: Stop bad formatting from sneaking in.
- Document your rules: Put them in the README so everyone stays on the same page.
Troubleshooting
Common Issues
-
Black and isort fighting?
- Use
profile = "black"
in isort. - Run isort first, then Black.
- Use
-
Line length conflicts?
- Set the same
line-length
in both tools.
- Set the same
-
Imports not sorting right?
- Use
--profile black
with isort. - Double-check your config sections.
- Use
Advanced Usage with Ruff
Ruff is a lightning-fast linter and formatter (written in Rust) that can replace Black, isort, and other tools — all in one go.
Why Use Ruff?
- Super fast: Like, really fast.
- All-in-one: Formatting and linting together.
- Compatible with Black style: No fighting.
- Tons of rules: Supports over 800 lint rules.
- Modern and reliable: Built for speed and correctness.
Installing Ruff
# Install with pip
pip install ruff
# Or with uv
uv add ruff --dev
Using Ruff
# Lint code
ruff check .
# Format code
ruff format .
# Auto-fix issues
ruff check --fix .
# Fix and format in one go
ruff check --fix . && ruff format .
Ruff Configuration
Add to pyproject.toml
:
[tool.ruff]
line-length = 88
select = ["ALL"]
ignore = ["E501", "D203", "D212"]
target-version = "py38"
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
VS Code Integration
- Install the Ruff extension.
- Add to your
settings.json
:
{
"[python]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
"editor.defaultFormatter": "charliermarsh.ruff"
}
}
Before and After with Ruff
- Before
from datetime import datetime
import os
import sys
from typing import List,Dict
def my_function( x: int,y: int )->int:
return x+y
- After
import os
import sys
from datetime import datetime
from typing import Dict, List
def my_function(x: int, y: int) -> int:
return x + y
Conclusion
Whether you stick with Black and isort or switch to Ruff for an all-in-one approach, keeping your code consistently formatted will make your life (and your teammates’ lives) so much easier. No more nitpicking over spaces or import orders — just clean, readable code every time.
Now go make your code beautiful and keep those diffs clean!