| name | python-pyupgrade-syntax-modernizer |
| description | Use pyupgrade to automatically upgrade Python syntax to newer versions. Activate when: (1) Migrating code from Python 2 to 3, (2) Removing deprecated syntax like 'class Foo(object)', (3) Converting old-style string formatting to f-strings, (4) Updating type hints to modern union syntax (X | Y), (5) Removing obsolete __future__ imports, or (6) Upgrading to a newer Python minimum version. Use when this capability is needed. |
Python Pyupgrade Syntax Modernizer
Overview
Pyupgrade is a tool (and pre-commit hook) that automatically upgrades Python syntax for newer versions of the language. It scans your code and applies modern syntax patterns appropriate for your target Python version.
Key benefit: Pyupgrade automates tedious manual refactoring when upgrading Python versions, ensuring consistent modern syntax across your codebase.
Key Capabilities
- Version-targeted upgrades: Specify minimum Python version (3.6+ through 3.14+)
- Safe transformations: Conservative approach that won't break working code
- Pre-commit integration: Seamlessly integrates into CI/CD workflows
- Comprehensive coverage: Handles strings, types, imports, classes, and more
Quick Reference
Basic Commands
pyupgrade file.py
pyupgrade --py311-plus file.py
find . -name "*.py" -exec pyupgrade --py311-plus {} +
pyupgrade --py311-plus file.py && git diff
pyupgrade --keep-percent-format file.py
pyupgrade --keep-mock file.py
Version Flags
| Flag | Minimum Python | Key Features Enabled |
|---|
--py36-plus | 3.6 | f-strings, variable annotations |
--py37-plus | 3.7 | async/await improvements |
--py38-plus | 3.8 | Walrus operator, positional-only params |
--py39-plus | 3.9 | dict | dict, list[int] generics |
--py310-plus | 3.10 | X | Y union types, match statements |
--py311-plus | 3.11 | Exception groups, tomllib |
--py312-plus | 3.12 | Type parameter syntax |
--py313-plus | 3.13 | Latest syntax features |
--py314-plus | 3.14 | Bleeding edge features |
Transformations
Set Literals
set([1, 2, 3])
set((1, 2, 3))
{1, 2, 3}
Dictionary Comprehensions
dict((a, b) for a, b in items)
{a: b for a, b in items}
String Formatting (f-strings)
"Hello, {}".format(name)
"Hello, %s" % name
"Value: {value}".format(value=x)
f"Hello, {name}"
f"Hello, {name}"
f"Value: {x}"
Class Definitions
class MyClass(object):
__metaclass__ = ABCMeta
class MyClass:
pass
Super Calls
class Child(Parent):
def method(self):
super(Child, self).method()
class Child(Parent):
def method(self):
super().method()
Type Hints (--py310-plus)
from typing import Optional, Union, List, Dict
def func(x: Optional[int]) -> Union[str, int]:
items: List[Dict[str, int]] = []
def func(x: int | None) -> str | int:
items: list[dict[str, int]] = []
future Imports
from __future__ import annotations, division, print_function
from __future__ import annotations
Collections Imports
from collections import Mapping, MutableMapping
from collections.abc import Mapping, MutableMapping
Mock Imports
from mock import Mock, patch
from unittest.mock import Mock, patch
Invalid Escape Sequences
regex = "\d+\s+"
regex = r"\d+\s+"
Six Library Removal
import six
if six.PY2:
text_type = unicode
else:
text_type = str
text_type = str
Exception Handling
OSError
IOError
EnvironmentError
OSError
OSError
OSError
Comparison Operators
if x is 1:
pass
if x == 1:
pass
Configuration
Pre-commit Integration
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.21.2
hooks:
- id: pyupgrade
args: [--py311-plus]
Combining with Other Tools
With Ruff: If using Ruff, you can use its UP rules instead:
[tool.ruff.lint]
select = ["UP"]
target-version = "py311"
With Black: Run pyupgrade before Black for consistent formatting:
pyupgrade --py311-plus file.py
black file.py
Common Workflows
Upgrade Entire Codebase
find . -name "*.py" -not -path "./.venv/*" -exec pyupgrade --py311-plus {} +
find . -name "*.py" -not -path "./.venv/*" | xargs -P 4 pyupgrade --py311-plus
Check Before Commit
git add -A
git diff --cached --name-only --diff-filter=ACMR | \
grep "\.py$" | \
xargs -r pyupgrade --py311-plus
Gradual Migration
pyupgrade --py38-plus file.py
pyupgrade --py39-plus file.py
pyupgrade --py310-plus file.py
pyupgrade --py311-plus file.py
Best Practices
- Use version control: Always commit before running pyupgrade
- Run tests after: Verify functionality after transformations
- Match your target: Use the flag matching your minimum Python version
- Review changes: Some transformations may need manual adjustment
- Combine with formatters: Run Black/Ruff format after pyupgrade
Caveats
- F-string complexity: Won't create f-strings if they would be longer or harder to read
- Timid approach: Intentionally conservative to avoid breaking code
- Manual review: Some edge cases may need manual attention
Detailed Reference
For complete transformation examples, see references/pyupgrade-transforms.md.
External Links
Converted and distributed by TomeVault — claim your Tome and manage your conversions.