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

Add ruff to "format-file" command #123

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ Usage: ./cli.py format-file [OPTIONS] FILE_PATH
│ --remove-all-unused-imports Remove all unused imports (not just those from the │
│ standard library) via autoflake │
│ [default: True] │
│ --ruff-format Use Ruff "format" instead of the default tools │
│ --ruff-check-fix Use Ruff "check --fix" instead of the default tools │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
```
Expand Down Expand Up @@ -333,6 +335,7 @@ See also git tags: https://github.com/jedie/manageprojects/tags
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)

* [**dev**](https://github.com/jedie/manageprojects/compare/v0.17.1...main)
* 2024-01-26 - Add ruff to "format-file" command
* 2024-01-25 - Update requirements
* 2023-12-30 - Fix typos
* [v0.17.1](https://github.com/jedie/manageprojects/compare/v0.17.0...v0.17.1)
Expand Down
14 changes: 14 additions & 0 deletions manageprojects/cli/cli_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,16 @@ def wiggle(project_path: Path, words: bool):
help='Remove all unused imports (not just those from the standard library) via autoflake',
**OPTION_ARGS_DEFAULT_TRUE,
)
@click.option(
'--ruff-format',
help='Use Ruff "format" instead of the default tools',
**OPTION_ARGS_DEFAULT_FALSE,
)
@click.option(
'--ruff-check-fix',
help='Use Ruff "check --fix" instead of the default tools',
**OPTION_ARGS_DEFAULT_FALSE,
)
@click.argument('file_path', **ARGUMENT_EXISTING_FILE)
def format_file(
*,
Expand All @@ -392,6 +402,8 @@ def format_file(
darker_prefixes: str,
remove_all_unused_imports: bool,
file_path: Path,
ruff_format: bool,
ruff_check_fix: bool,
):
"""
Format and check the given python source code file with darker/autoflake/isort/pyupgrade/autopep8/mypy etc.
Expand All @@ -405,6 +417,8 @@ def format_file(
darker_prefixes=darker_prefixes,
remove_all_unused_imports=remove_all_unused_imports,
file_path=file_path,
ruff_format=ruff_format,
ruff_check_fix=ruff_check_fix,
)


Expand Down
6 changes: 5 additions & 1 deletion manageprojects/cli/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,11 @@ def update():
'--generate-hashes',
]

# Only "prod" dependencies:
# dependencies + "code-style"-optional-dependencies:
verbose_check_call(
*pip_compile_base,
'pyproject.toml',
'--extra=code-style',
'--output-file',
'requirements.txt',
extra_env=extra_env,
Expand All @@ -151,6 +152,7 @@ def update():
verbose_check_call(
*pip_compile_base,
'pyproject.toml',
'--extra=code-style',
'--extra=dev',
'--output-file',
'requirements.dev.txt',
Expand All @@ -162,6 +164,8 @@ def update():
# Install new dependencies in current .venv:
verbose_check_call(bin_path / 'pip-sync', 'requirements.dev.txt')

print('\nUpdate packages, done.')


cli.add_command(update)

Expand Down
5 changes: 5 additions & 0 deletions manageprojects/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import enum
import sys
from pathlib import Path

Expand Down Expand Up @@ -31,3 +32,7 @@

PY_BIN_PATH = Path(sys.executable).parent
BASE_PATH = Path(manageprojects.__file__).parent


CLI_RUFF_FORMAT = 'format'
CLI_RUFF_CHECK_FIX = 'check-fix'
102 changes: 88 additions & 14 deletions manageprojects/format_file.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import dataclasses
import subprocess
from importlib.metadata import version as importlib_version
from pathlib import Path
from typing import Optional

Expand Down Expand Up @@ -48,9 +49,14 @@ class Config:
max_line_length: int

@property
def py_ver_str(self) -> Optional[str]:
def python_ver_number_str(self) -> Optional[str]:
if pyproject_info := self.pyproject_info:
return f'py{pyproject_info.py_min_ver.major}{pyproject_info.py_min_ver.minor}'
return f'{pyproject_info.py_min_ver.major}{pyproject_info.py_min_ver.minor}'

@property
def py_ver_str(self) -> Optional[str]:
if python_ver_number_str := self.python_ver_number_str:
return f'py{python_ver_number_str}'

@property
def project_root_path(self) -> Optional[Path]:
Expand Down Expand Up @@ -159,6 +165,46 @@ def get_config(
return config


def run_isort(tools_executor, file_path, config):
args = [
'isort',
'--overwrite-in-place',
'--line-length',
config.max_line_length,
]
if python_ver_number_str := config.python_ver_number_str:
args.extend(['--python-version', python_ver_number_str])

tools_executor.verbose_check_call(
*args,
file_path,
)
tools_executor.verbose_check_call('isort', '--version', verbose=False)


def run_ruff(tools_executor, file_path, config, *, ruff_format: bool, ruff_check_fix: bool):
if ruff_format and ruff_check_fix:
raise ValueError('ruff_format and ruff_check_fix can not be used at the same time!')

if ruff_format:
ruff_args = ('format',)
else:
ruff_args = ('check', '--fix')

tools_executor.verbose_check_call(
'ruff',
*ruff_args,
'--verbose',
'--preview',
'--target-version',
config.py_ver_str,
'--line-length',
config.max_line_length,
file_path,
)
tools_executor.verbose_check_call('ruff', '--version', verbose=False)


def run_pyupgrade(tools_executor, file_path, config):
pyver_arg = f'--{config.py_ver_str}-plus'
tools_executor.verbose_check_call(
Expand All @@ -167,6 +213,9 @@ def run_pyupgrade(tools_executor, file_path, config):
pyver_arg,
file_path,
)
# There is no: "pyupgrade --version" and no __version__ info in the package!
pyupgrade_version = importlib_version('pyupgrade')
print(f'pyupgrade: {pyupgrade_version}')


def run_autoflake(tools_executor, file_path, config, remove_all_unused_imports):
Expand All @@ -176,6 +225,7 @@ def run_autoflake(tools_executor, file_path, config, remove_all_unused_imports):
args.append('--remove-all-unused-imports')
args.append(file_path)
tools_executor.verbose_check_call(*args)
tools_executor.verbose_check_call('autoflake', '--version', verbose=False)


def run_darker(tools_executor, file_path, config, darker_prefixes):
Expand Down Expand Up @@ -207,6 +257,7 @@ def run_darker(tools_executor, file_path, config, darker_prefixes):
config.py_ver_str,
file_path,
)
tools_executor.verbose_check_call('darker', '--version', verbose=False)


def run_autopep8(tools_executor, file_path, config):
Expand All @@ -220,6 +271,7 @@ def run_autopep8(tools_executor, file_path, config):
'--in-place',
file_path,
)
tools_executor.verbose_check_call('autopep8', '--version', verbose=False)


def run_flake8(tools_executor, file_path, config):
Expand All @@ -229,14 +281,18 @@ def run_flake8(tools_executor, file_path, config):
str(config.max_line_length),
file_path,
)
tools_executor.verbose_check_call('flake8', '--version', verbose=False)


def run_pyflakes(tools_executor, file_path, config):
tools_executor.verbose_check_call('pyflakes', file_path)
tools_executor.verbose_check_call('pyflakes', '--version', verbose=False)


def run_codespell(tools_executor, file_path, config):
tools_executor.verbose_check_call('codespell', file_path)
print('codespell', end=' ')
tools_executor.verbose_check_call('codespell', '--version', verbose=False)


def run_mypy(tools_executor, file_path, config):
Expand All @@ -248,6 +304,7 @@ def run_mypy(tools_executor, file_path, config):
'--allow-redefinition', # https://github.com/python/mypy/issues/7165
str(file_path),
)
tools_executor.verbose_check_call('mypy', '--version', verbose=False)


def format_one_file(
Expand All @@ -257,6 +314,8 @@ def format_one_file(
darker_prefixes: str,
remove_all_unused_imports: bool,
file_path: Path,
ruff_format: bool = False,
ruff_check_fix: bool = True,
) -> None:
file_path = file_path.resolve()
print(f'\nApply code formatter to: {file_path}')
Expand All @@ -280,21 +339,36 @@ def format_one_file(

print('\n')

run_pyupgrade(tools_executor, file_path, config)
run_autoflake(
tools_executor,
file_path,
config,
remove_all_unused_imports=remove_all_unused_imports,
)
if ruff_format or ruff_check_fix:
# Use "only" ruff to format the file...
# But it has some troubles:
# * Will not remove unused import correctly
# * Will not ordered import correctly
run_autoflake(
tools_executor,
file_path,
config,
remove_all_unused_imports=remove_all_unused_imports,
)
run_isort(tools_executor, file_path, config)
run_ruff(tools_executor, file_path, config, ruff_format=ruff_format, ruff_check_fix=ruff_check_fix)

if config.main_branch_name:
run_darker(tools_executor, file_path, config, darker_prefixes)
else:
run_autopep8(tools_executor, file_path, config)
run_pyupgrade(tools_executor, file_path, config)
run_autoflake(
tools_executor,
file_path,
config,
remove_all_unused_imports=remove_all_unused_imports,
)

if config.main_branch_name:
run_darker(tools_executor, file_path, config, darker_prefixes)
else:
run_autopep8(tools_executor, file_path, config)

run_flake8(tools_executor, file_path, config)
run_pyflakes(tools_executor, file_path, config)
run_flake8(tools_executor, file_path, config)
run_pyflakes(tools_executor, file_path, config)
run_codespell(tools_executor, file_path, config)
run_mypy(tools_executor, file_path, config)

Expand Down
6 changes: 6 additions & 0 deletions manageprojects/utilities/pyproject_toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import Optional

import tomlkit
from bx_py_utils.dict_utils import dict_get
from bx_py_utils.path import assert_is_dir, assert_is_file
from cli_base.cli_tools.rich_utils import human_error
from tomlkit import TOMLDocument
Expand Down Expand Up @@ -79,6 +80,11 @@ def get_pyproject_toml(*, file_path: Optional[Path] = None) -> TomlDocument:
return toml_document


def get_pyproject_toml_values(*keys):
toml_document: TomlDocument = get_pyproject_toml()
doc: TOMLDocument = toml_document.doc
return dict_get(doc, *keys)

class PyProjectToml:
"""
Helper for manageprojects meta information in 'pyproject.toml'
Expand Down
40 changes: 34 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ dependencies = [
"tomlkit",
"EditorConfig", # https://github.com/editorconfig/editorconfig-core-py

"cli-base-utilities", # https://github.com/jedie/cli-base-utilities
"click", # https://github.com/pallets/click/
"rich-click", # https://github.com/ewels/rich-click
"rich", # https://github.com/Textualize/rich
]
[project.optional-dependencies]
code-style = [ # Needed to use "format-file" command!
"ruff", # https://github.com/astral-sh/ruff

# https://github.com/akaihola/darker
# https://github.com/ikamensh/flynt
# https://github.com/pycqa/isort
Expand All @@ -27,13 +36,7 @@ dependencies = [
"pyupgrade", # https://github.com/asottile/pyupgrade
"codespell", # https://github.com/codespell-project/codespell
"mypy", # https://github.com/python/mypy

"cli-base-utilities", # https://github.com/jedie/cli-base-utilities
"click", # https://github.com/pallets/click/
"rich-click", # https://github.com/ewels/rich-click
"rich", # https://github.com/Textualize/rich
]
[project.optional-dependencies]
dev = [
"pip-tools", # https://github.com/jazzband/pip-tools/
"tox", # https://github.com/tox-dev/tox
Expand Down Expand Up @@ -73,6 +76,28 @@ version = {attr = "manageprojects.__version__"}
version_module_name = "manageprojects" # Used by "update-readme-history" git hook


##################################################################################################


[tool.ruff.lint]
select = [
"ALL", # enable all rules
]
ignore=[
"PT", # pytest
"ANN", # flake8-annotations
#
# disable some incompatible combinations:
"D211", # no-blank-line-before-class
"D213", # multi-line-summary-second-line
"COM812", # missing-trailing-comma
"ISC001", # single-line-implicit-string-concatenation
]

[tool.ruff.format]
quote-style = "single"


[tool.darker]
src = ['.']
revision = "origin/main..."
Expand Down Expand Up @@ -101,6 +126,9 @@ line_length=119
lines_after_imports=2


##################################################################################################


[tool.coverage.run]
branch = true
parallel = true
Expand Down
19 changes: 19 additions & 0 deletions requirements.dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,25 @@ ruamel-yaml-clib==0.2.8 \
--hash=sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875 \
--hash=sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412
# via ruamel-yaml
ruff==0.1.14 \
--hash=sha256:1c8eca1a47b4150dc0fbec7fe68fc91c695aed798532a18dbb1424e61e9b721f \
--hash=sha256:2270504d629a0b064247983cbc495bed277f372fb9eaba41e5cf51f7ba705a6a \
--hash=sha256:269302b31ade4cde6cf6f9dd58ea593773a37ed3f7b97e793c8594b262466b67 \
--hash=sha256:62ce2ae46303ee896fc6811f63d6dabf8d9c389da0f3e3f2bce8bc7f15ef5488 \
--hash=sha256:653230dd00aaf449eb5ff25d10a6e03bc3006813e2cb99799e568f55482e5cae \
--hash=sha256:6b3dadc9522d0eccc060699a9816e8127b27addbb4697fc0c08611e4e6aeb8b5 \
--hash=sha256:7060156ecc572b8f984fd20fd8b0fcb692dd5d837b7606e968334ab7ff0090ab \
--hash=sha256:722bafc299145575a63bbd6b5069cb643eaa62546a5b6398f82b3e4403329cab \
--hash=sha256:80258bb3b8909b1700610dfabef7876423eed1bc930fe177c71c414921898efa \
--hash=sha256:87b3acc6c4e6928459ba9eb7459dd4f0c4bf266a053c863d72a44c33246bfdbf \
--hash=sha256:96f76536df9b26622755c12ed8680f159817be2f725c17ed9305b472a757cdbb \
--hash=sha256:a53d8e35313d7b67eb3db15a66c08434809107659226a90dcd7acb2afa55faea \
--hash=sha256:ab3f71f64498c7241123bb5a768544cf42821d2a537f894b22457a543d3ca7a9 \
--hash=sha256:ad3f8088b2dfd884820289a06ab718cde7d38b94972212cc4ba90d5fbc9955f3 \
--hash=sha256:b2027dde79d217b211d725fc833e8965dc90a16d0d3213f1298f97465956661b \
--hash=sha256:bea9be712b8f5b4ebed40e1949379cfb2a7d907f42921cf9ab3aae07e6fba9eb \
--hash=sha256:e3d241aa61f92b0805a7082bd89a9990826448e4d0398f0e2bc8f05c75c63d99
# via manageprojects (pyproject.toml)
safety==2.3.4 \
--hash=sha256:6224dcd9b20986a2b2c5e7acfdfba6bca42bb11b2783b24ed04f32317e5167ea \
--hash=sha256:b9e74e794e82f54d11f4091c5d820c4d2d81de9f953bf0b4f33ac8bc402ae72c
Expand Down
Loading
Loading