{"id":3783,"library":"pyupgrade","title":"pyupgrade","description":"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.","status":"active","version":"3.21.2","language":"en","source_language":"en","source_url":"https://github.com/asottile/pyupgrade","tags":["code-quality","linter","refactoring","tool","syntax-upgrade","pre-commit"],"install":[{"cmd":"pip install pyupgrade","lang":"bash","label":"Install via pip"}],"dependencies":[{"reason":"pyupgrade itself requires Python >=3.10 to run, although it can transform code for earlier target Python versions.","package":"Python","optional":false}],"imports":[],"quickstart":{"code":"# my_module.py\nimport os\nfrom typing import List\n\ndef old_function(name):\n    print(\"Hello, %s!\" % name)\n\nclass OldClass(object):\n    def __init__(self, value):\n        self.value = value\n\ndef process_items(items: List[int]) -> List[int]:\n    return [x * 2 for x in items]\n\n# Run pyupgrade from the command line:\n# pyupgrade --py38-plus my_module.py\n# This will update the file in place to, for example, use f-strings and remove object inheritance.","lang":"python","description":"To quickly upgrade a Python file, first save your code, then run `pyupgrade` from your terminal, specifying the target Python version using a `--pyN-plus` flag. This example updates `my_module.py` to Python 3.8+ syntax, converting old string formatting, removing redundant `(object)` inheritance, and updating type hints."},"warnings":[{"fix":"Use `find . -name '*.py' -exec pyupgrade --py3N-plus {} +` for recursive application, or integrate it as a `pre-commit` hook (e.g., `pre-commit run pyupgrade --all-files`).","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Add `--exit-zero-even-if-changed` to your pyupgrade command or pre-commit hook configuration.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always explicitly provide the `--pyN-plus` flag corresponding to the minimum Python version you intend to support (e.g., `--py38-plus` for Python 3.8 and newer).","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Review your `ruff` configuration (e.g., in `pyproject.toml`) for `select = ['UP']` to avoid duplicate tooling. `ruff --fix` often handles these upgrades.","message":"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.","severity":"gotcha","affected_versions":"All versions where Ruff is used with UP rules"},{"fix":"If you encounter issues with type checkers, use the `--keep-runtime-typing` flag to prevent these specific typing rewrites. Ensure `typing.Type` is always used with a type argument (e.g., `Type[int]`) if that's the intended meaning.","message":"`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.","severity":"gotcha","affected_versions":"All versions (especially with Python >=3.9, PEP 585/604)"},{"fix":"Always run your test suite and a linter (e.g., `ruff`, `flake8`) after applying `pyupgrade` to catch any regressions or new issues.","message":"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.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}