Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pyupgrade formatter plugin #755

Draft
wants to merge 45 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
05b06b1
feat: remove global Black imports
akaihola Oct 11, 2024
1026778
fix: pylint import outside toplevel
akaihola Oct 28, 2024
eed33f2
style: fix indentation
akaihola Oct 28, 2024
da17346
feat: move black dependency to darker[black] extras
akaihola Oct 28, 2024
9726953
feat: verbose error if Black not found
akaihola Oct 28, 2024
90ebf09
test: correct operation with Black missing
akaihola Oct 28, 2024
ee6f216
test: --formatter=none config parsing
akaihola Oct 28, 2024
7a46f08
TEMP: install darkgraylib from branch
akaihola Oct 28, 2024
0e831a5
test: --formatter=none with Black installed or not
akaihola Oct 28, 2024
25f3597
docs: Black not installed by default
akaihola Oct 29, 2024
b3a0b24
docs: update the change log [drop-black-dependency]
akaihola Oct 29, 2024
885597d
feat: add ruff code re-formatter plugin
akaihola Sep 16, 2024
02c62cb
docs: comment about tomllib/tomli and the Python version
akaihola Oct 9, 2024
6e970cf
refactor: replace magic number with length of prefix string
akaihola Oct 9, 2024
887961f
feat: store numeric Black target versions internally
akaihola Oct 8, 2024
57fa15f
feat: store numeric Ruff target versions internally
akaihola Oct 8, 2024
fb4faf2
refactor: more readable _get_supported_target_versions()
akaihola Oct 9, 2024
9a00196
test: unit tests for ruff formatter
akaihola Oct 9, 2024
2ec8e7f
feat: pass file path to formatter run() method
akaihola Oct 7, 2024
34c992d
feat: add formatter TOML config sections to make testing easier
akaihola Oct 6, 2024
b8efbfe
test: both Black and Ruff in same test when applicable
akaihola Oct 6, 2024
3c3ae54
test: add Ruff command line option tests
akaihola Oct 6, 2024
0474b40
test: add Ruff config file + CLI option test
akaihola Oct 6, 2024
7d7c12c
test: ruff tests in test_main.py
akaihola Oct 7, 2024
01b4927
test: exercise ruff formatter in three more test_main tests
akaihola Oct 7, 2024
d0fba6b
test: ruff in tests for format_edited_parts()
akaihola Oct 7, 2024
a48fd8c
test: ruff in tests for reformat_and_flynt_single_file()
akaihola Oct 7, 2024
ea51a60
test: ruff in tests for --stdin-filename
akaihola Oct 7, 2024
c11858b
test: migrate from tmpdir to tmp_path
akaihola Oct 9, 2024
2ee706a
test: Black compatible Flake8 configuration [ruff-plugin]
akaihola Oct 9, 2024
a3bcbf4
feat: extras option and test dependencies for pyupgrade
akaihola Jan 22, 2023
49367f8
test: ignore missing imports for pyupgrade in Mypy
akaihola Jan 22, 2023
eac543f
feat: pyupgrade formatter plugin
akaihola Oct 8, 2024
3a561f0
feat: remove global pyupgrade imports
akaihola Oct 11, 2024
35a7adf
feat: remove global Black imports
akaihola Oct 11, 2024
1157323
test: adjust patching for removed global Black imports
akaihola Oct 11, 2024
59135d8
chore: tweak ruff rules
akaihola Oct 11, 2024
da292e7
docs: add --formatter=pyupgrade to README
akaihola Oct 19, 2024
7bfe788
ci: convert existing CI job to run pyupgrade through Darker
akaihola Oct 19, 2024
58edb0f
fix: pyupgrade entire modified files, not only user-modified chunks
akaihola Oct 19, 2024
26cd269
test: add stubs for pyupgrade
akaihola Oct 20, 2024
b9968a3
fix: swallow SystemExit from pyupgrade --help argparse
akaihola Oct 20, 2024
a4beeb3
fix: parse pyupgrade --target-version into an int-tuple
akaihola Oct 20, 2024
87b5ea4
docs: update the change log
akaihola Oct 20, 2024
647aa1e
docs: --formatter explanations in README
akaihola Oct 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
pygments \
'pylint<=3.2.7' \
pytest>=6.2.0 \
pyupgrade>=2.31.0 \
regex \
requests \
requests-cache \
Expand Down
13 changes: 5 additions & 8 deletions .github/workflows/pyupgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install uv
uses: astral-sh/setup-uv@v3
- uses: actions/setup-python@v5
- name: Ensure modern Python style using pyupgrade
# This script is written in a Linux / macos / windows portable way
run: |
uvx --from pyupgrade python -c "
import sys
from pyupgrade._main import main
from glob import glob
files = glob('**/*.py', recursive=True)
sys.exit(main(files + ['--py38-plus']))
" || ( git diff ; false )
uvx \
--from '.[pyupgrade]' \
darker --formatter=pyupgrade --target-version=py38 --diff
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ Added
other formatters in the future. There's also a dummy ``none`` formatter plugin.
- ``--formatter=none`` now skips running Black. This is useful when you only want to run
Isort or Flynt.
- Black_ is no longer installed by default. Use ``pip install 'darker[black]'`` to get
Black support.
- pyupgrade_ is now supported as a formatter plugin. Note that changes from pyupgrade
are applied on a per-file basis, not only for modified lines as with Black_ and Ruff_.

Removed
-------
Expand Down Expand Up @@ -682,3 +686,4 @@ Added
.. _Ruff: https://astral.sh/ruff
.. _Black: https://black.readthedocs.io/
.. _NixOS: https://nixos.org/
.. _pyupgrade: https://pypi.org/project/pyupgrade/
31 changes: 23 additions & 8 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,11 @@ How?

To install or upgrade, use::

pip install --upgrade darker~=2.1.1
pip install --upgrade darker[black]~=2.1.1

Or, if you're using Conda_ for package management::

conda install -c conda-forge darker~=2.1.1 isort
conda install -c conda-forge darker~=2.1.1 black isort
conda update -c conda-forge darker

..
Expand All @@ -146,6 +146,8 @@ Or, if you're using Conda_ for package management::
specifier for Darker. See `Guarding against Black compatibility breakage`_ for more
information.

*New in version 3.0.0:* Black is no longer installed by default.

The ``darker <myfile.py>`` or ``darker <directory>`` command
reads the original file(s),
formats them using Black_,
Expand All @@ -165,6 +167,9 @@ You can enable additional features with command line options:
- ``-f`` / ``--flynt``: Also convert string formatting to use f-strings using the
``flynt`` package

If you only want to run those tools without reformatting with Black,
use the ``--formatter=none`` option.

*New in version 1.1.0:* The ``-L`` / ``--lint`` option.

*New in version 1.2.2:* Package available in conda-forge_.
Expand All @@ -174,6 +179,8 @@ You can enable additional features with command line options:
*New in version 3.0.0:* Removed the ``-L`` / ``--lint`` functionality and moved it into
the Graylint_ package.

*New in version 3.0.0:* The ``--formatter`` option.

.. _Conda: https://conda.io/
.. _conda-forge: https://conda-forge.org/

Expand Down Expand Up @@ -371,7 +378,8 @@ The following `command line arguments`_ can also be used to modify the defaults:
versions that should be supported by Black's output. [default: per-file auto-
detection]
--formatter FORMATTER
[black\|none] Formatter to use for reformatting code. [default: black]
[black\|none\|pyupgrade\|ruff] Formatter to use for reformatting code. [default:
black]

To change default values for these options for a given project,
add a ``[tool.darker]`` section to ``pyproject.toml`` in the project's root directory,
Expand Down Expand Up @@ -478,7 +486,7 @@ PyCharm/IntelliJ IDEA

1. Install ``darker``::

$ pip install darker
$ pip install 'darker[black]'

2. Locate your ``darker`` installation folder.

Expand Down Expand Up @@ -540,7 +548,7 @@ Visual Studio Code

1. Install ``darker``::

$ pip install darker
$ pip install 'darker[black]'

2. Locate your ``darker`` installation folder.

Expand Down Expand Up @@ -683,16 +691,20 @@ other reformatter tools you use to known compatible versions, for example:
Using arguments
---------------

You can provide arguments, such as enabling isort, by specifying ``args``.
Note the inclusion of the isort Python package under ``additional_dependencies``:
You can provide arguments, such as disabling Darker or enabling isort,
by specifying ``args``.
Note the absence of Black and the inclusion of the isort Python package
under ``additional_dependencies``:

.. code-block:: yaml

- repo: https://github.com/akaihola/darker
rev: v2.1.1
hooks:
- id: darker
args: [--isort]
args:
- --formatter=none
- --isort
additional_dependencies:
- isort~=5.9

Expand Down Expand Up @@ -779,6 +791,9 @@ The ``lint:`` option.
Removed the ``lint:`` option and moved it into the GitHub action
of the Graylint_ package.

*New in version 3.0.0:*
Black is now explicitly installed when running the action.


Syntax highlighting
===================
Expand Down
2 changes: 1 addition & 1 deletion action/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

run([sys.executable, "-m", "venv", str(ENV_PATH)], check=True) # nosec

req = ["darker[color,isort]"]
req = ["darker[black,color,isort]"]
if VERSION:
if VERSION.startswith("@"):
req[0] = f"git+https://github.com/akaihola/darker{VERSION}#egg={req[0]}"
Expand Down
16 changes: 9 additions & 7 deletions action/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,25 @@ def test_creates_virtualenv(tmp_path, main_patch):


@pytest.mark.kwparametrize(
dict(run_main_env={}, expect=["darker[color,isort]"]),
dict(run_main_env={}, expect=["darker[black,color,isort]"]),
dict(
run_main_env={"INPUT_VERSION": "1.5.0"}, expect=["darker[color,isort]==1.5.0"]
run_main_env={"INPUT_VERSION": "1.5.0"},
expect=["darker[black,color,isort]==1.5.0"],
),
dict(
run_main_env={"INPUT_VERSION": "@master"},
expect=[
"git+https://github.com/akaihola/darker@master#egg=darker[color,isort]"
"git+https://github.com/akaihola/darker"
"@master#egg=darker[black,color,isort]"
],
),
dict(
run_main_env={"INPUT_LINT": "dummy"},
expect=["darker[color,isort]"],
expect=["darker[black,color,isort]"],
),
dict(
run_main_env={"INPUT_LINT": "dummy,foobar"},
expect=["darker[color,isort]"],
expect=["darker[black,color,isort]"],
),
)
def test_installs_packages(tmp_path, main_patch, run_main_env, expect):
Expand Down Expand Up @@ -208,15 +210,15 @@ def test_error_if_pip_fails(tmp_path, capsys):
run_module("main")

assert main_patch.subprocess.run.call_args_list[-1] == call(
[ANY, "-m", "pip", "install", "darker[color,isort]"],
[ANY, "-m", "pip", "install", "darker[black,color,isort]"],
check=False,
stdout=PIPE,
stderr=STDOUT,
encoding="utf-8",
)
assert (
capsys.readouterr().out.splitlines()[-1]
== "::error::Failed to install darker[color,isort]."
== "::error::Failed to install darker[black,color,isort]."
)
main_patch.sys.exit.assert_called_once_with(42)

Expand Down
3 changes: 2 additions & 1 deletion constraints-oldest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# interpreter and Python ependencies. Keep this up-to-date with minimum
# versions in `setup.cfg`.
black==22.3.0
darkgraylib==2.0.1
# TODO: upgrade to darkgraylib~=2.1.0 when released
darkgraylib @ git+https://github.com/akaihola/darkgraylib.git@module-scope-git-repo-fixture
defusedxml==0.7.1
flake8-2020==1.6.1
flake8-bugbear==22.1.11
Expand Down
2 changes: 2 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
[mypy]
mypy_path = stubs/

disallow_any_unimported = True
disallow_any_expr = False
disallow_any_decorated = True
Expand Down
9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[build-system]

Check failure on line 1 in pyproject.toml

View workflow job for this annotation

GitHub Actions / Pylint

pyproject.toml#L1

Unrecognized option found: per-file-ignores (unrecognized-option, E0015)
# Minimum requirements for the build system to execute.
requires = ["setuptools", "wheel"] # PEP 508 specifications.

Expand Down Expand Up @@ -31,10 +31,18 @@
revision = "origin/master..."
src = ["."]

[tool.pylint.MASTER]
load-plugins = [
"pylint_per_file_ignores",
]

[tool.pylint."messages control"]
# Check import order only with isort. Pylint doesn't support a custom list of first
# party packages. We want to consider "darkgraylib" and "graylint" as first party.
disable = ["wrong-import-order"]
per-file-ignores = [
"/stubs/:missing-class-docstring,missing-function-docstring,unused-argument",
]

[tool.ruff]
target-version = "py38"
Expand All @@ -48,6 +56,7 @@
"D203", # One blank line required before class docstring
"D213", # Multi-line docstring summary should start at the second line
"D400", # First line should end with a period (duplicates D415)
"ISC001", # Checks for implicitly concatenated strings on a single line

# Remove these when support for Python 3.8 is dropped:
"UP006", # Use `xyz` instead of `Xyz` for type annotation
Expand Down
18 changes: 16 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ package_dir =
packages = find:
install_requires =
# NOTE: remember to keep `constraints-oldest.txt` in sync with these
black>=22.3.0
darkgraylib~=2.0.1
# TODO: upgrade to darkgraylib~=2.1.0 when released
darkgraylib @ git+https://github.com/akaihola/darkgraylib.git@module-scope-git-repo-fixture
toml>=0.10.0
typing_extensions>=4.0.1
# NOTE: remember to keep `.github/workflows/python-package.yml` in sync
Expand All @@ -47,17 +47,23 @@ darker =
[options.entry_points]
darker.formatter =
black = darker.formatters.black_formatter:BlackFormatter
ruff = darker.formatters.ruff_formatter:RuffFormatter
pyupgrade = darker.formatters.pyupgrade_formatter:PyupgradeFormatter
none = darker.formatters.none_formatter:NoneFormatter
console_scripts =
darker = darker.__main__:main_with_error_handling

[options.extras_require]
black =
black>=22.3.0
flynt =
flynt>=0.76
isort =
isort>=5.0.1
color =
Pygments>=2.4.0
pyupgrade =
pyupgrade>=2.31.0
test =
# NOTE: remember to keep `constraints-oldest.txt` in sync with these
black>=22.3.0
Expand All @@ -70,8 +76,10 @@ test =
pydocstyle
pygments
pylint<=3.2.7 # pylint 3.3.0 dropped Python 3.8 support
pylint-per-file-ignores
pytest>=6.2.0
pytest-kwparametrize>=0.0.3
pyupgrade>=2.31.0
regex>=2021.4.4
requests_cache>=0.7
ruamel.yaml>=0.17.21
Expand All @@ -95,8 +103,14 @@ ignore =
D400
# D415 First line should end with a period, question mark, or exclamation point
D415
# E203 Whitespace before ':'
E203
# E231 missing whitespace after ','
E231
# E501 Line too long (82 > 79 characters)
E501
# E701 Multiple statements on one line (colon)
E701
# W503 line break before binary operator
W503
# Darglint options when run as a Flake8 plugin:
Expand Down
Loading
Loading