pyupgrade
pyupgrade is an active Python tool (version 3.21.2) designed to automatically upgrade code syntax for newer language versions. It streamlines the process of adopting modern Python features, improving code readability and efficiency. It's primarily used as a command-line utility or integrated into development workflows via pre-commit hooks, with new versions released continuously to support the latest Python syntax.
Warnings
- gotcha pyupgrade does not natively process directories recursively. Users commonly combine it with `find` or use `pre-commit` to apply it across an entire codebase. Alternatively, `pyupgrade-directories` is a separate tool available for this purpose.
- gotcha By default, `pyupgrade` exits with a non-zero status code (1) if it makes any changes. This can cause CI pipelines to fail. Use the `--exit-zero-even-if-changed` flag to ensure a successful exit code even when changes are applied.
- gotcha The `--pyN-plus` flag (e.g., `--py38-plus`, `--py311-plus`) is crucial to specify the minimum Python version whose syntax rules should be applied. Failing to specify it, or choosing a version too low, might prevent desired modernizations or apply changes unsuitable for your actual target runtime environment. `pyupgrade` defaults to generic Python 3 if no specific version is provided.
- gotcha If you are already using `ruff` with the `UP` (pyupgrade) rules enabled, a separate `pyupgrade` pre-commit hook or standalone run might be redundant, as `ruff` can perform many of the same modernizations.
- gotcha `pyupgrade` may convert `typing.Type` to `builtins.type`. While often interchangeable, in strict type-checking contexts (e.g., with Pyright), these are distinct and can lead to type errors if `typing.Type` was intended as a generic type. This can be problematic if `Type` is used without a type argument.
- gotcha pyupgrade focuses solely on syntax upgrades. It does not perform semantic or logical checks. After running `pyupgrade`, manual inspection, testing, and linting are still crucial to ensure the upgraded code remains logically correct and compatible with third-party libraries.
Install
-
pip install pyupgrade
Quickstart
# my_module.py
import os
from typing import List
def old_function(name):
print("Hello, %s!" % name)
class OldClass(object):
def __init__(self, value):
self.value = value
def process_items(items: List[int]) -> List[int]:
return [x * 2 for x in items]
# Run pyupgrade from the command line:
# pyupgrade --py38-plus my_module.py
# This will update the file in place to, for example, use f-strings and remove object inheritance.