Skip to content

Commit

Permalink
Use Ruff for linting and formatting
Browse files Browse the repository at this point in the history
Ruff is a Python linter and formatter that has gained popularity due to
its high performance and numerous capabilities.
https://docs.astral.sh/ruff/

Now that Ruff has released its first minor version series and has a
versioning policy, it's a good time to consider adopting it.
https://docs.astral.sh/ruff/versioning/
https://astral.sh/blog/ruff-v0.1.0

This commit will replace Black, Flake8, and isort with Ruff.

Black

Ruff is a drop-in replacement for Black. No additional configuration is
necessary.

Ruff supports opt-in docstring formatting with `docstring-code-format`.
The format is compatible with Black string formatting.

```toml
[tool.ruff.format]
docstring-code-format = true
```

https://docs.astral.sh/ruff/faq/
https://docs.astral.sh/ruff/formatter/#docstring-formatting
https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#strings

Flake8

Ruff is a drop-in replacement for Flake8. No additional configuration is
necessary. In addition to replacing Flake8 itself, Ruff can also replace
many Flake8 plugins and related projects.

isort

Ruff is not a drop-in replacement for isort at this time. Additional
configuration is needed.

1. Import sorting is opt-in. Ruff will not automatically sort imports.
   The `extend-select` setting is needed with the `I` ruleset.
2. There is no `src_paths` setting. The `src` and `known-first-party`
   settings are used instead. The Ruff FAQ currently says, "Ruff accepts
   a `src` option that in your `pyproject.toml`, `ruff.toml`, or
   `.ruff.toml` file, which specifies the directories that Ruff should
   consider when determining whether an import is first-party," making
   it sound like only `src` would be needed. However, to match isort
   behavior, both `src` and `known-first-party` may need to be set to
   the same list of directories.
3. Although isort is a formatter, Ruff does not run import sorting with
   the Ruff formatter. The Ruff linter is used instead
   (`ruff check --fix`).

Taken together, Ruff configuration settings in `pyproject.toml` related
to import sorting look like this:

```toml
[tool.ruff]
extend-select = ["I"]
src = ["package_name", "tests"]

[tool.ruff.lint.isort]
known-first-party = ["package_name", "tests"]
```

https://docs.astral.sh/ruff/faq/
https://docs.astral.sh/ruff/settings/
https://docs.astral.sh/ruff/rules/#isort-i
https://pycqa.github.io/isort/docs/configuration/options.html#src-paths

Notes on additional tools

Hatch

Hatch 1.8.0 introduced static analysis with Ruff. Although this is a
promising feature of Hatch, it will not be used at this time because of
differences between Hatch default settings and Ruff default settings,
and because it is not yet possible to fully override the Hatch default
settings (though this will likely be improved in the next release).
https://hatch.pypa.io/1.9/config/static-analysis/#default-settings
https://docs.astral.sh/ruff/configuration/
https://hatch.pypa.io/latest/blog/2023/12/11/hatch-v180/#static-analysis

VSCode

To use Ruff in VSCode, install `charliermarsh.ruff` from the VSCode
extension marketplace or Open VSX marketplace (for VSCodium), then
update `settings.json` like this:

```json
{
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.fixAll": "always",
      "source.organizeImports": "always"
    },
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true
  },
  "ruff.lint.args": ["--extend-select=I"]
}
```

https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff
https://open-vsx.org/extension/charliermarsh/ruff
https://vscodium.com/
  • Loading branch information
br3ndonland committed Jan 14, 2024
1 parent b61a49e commit 90b3678
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 24 deletions.
10 changes: 1 addition & 9 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,7 @@ Code quality checks can be run using the Hatch scripts in _pyproject.toml_.

### Code style

- **Python code is formatted with [Black](https://black.readthedocs.io/en/stable/)**. Configuration for Black is stored in _pyproject.toml_.
- **Python imports are organized automatically with [isort](https://pycqa.github.io/isort/)**.
- The isort package organizes imports in three sections:
1. Standard library
2. Dependencies
3. Project
- Within each of those groups, `import` statements occur first, then `from` statements, in alphabetical order.
- You can run isort from the command line with `hatch run isort .`.
- Configuration for isort is stored in _pyproject.toml_.
- Python code is formatted with [Ruff](https://docs.astral.sh/ruff/). Ruff configuration is stored in _pyproject.toml_.
- Other web code (JSON, Markdown, YAML) is formatted with [Prettier](https://prettier.io/).

### Static type checking
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Python template repository

[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://black.readthedocs.io/en/stable/)
[![ci](https://github.com/br3ndonland/template-python/workflows/ci/badge.svg)](https://github.com/br3ndonland/template-python/actions/workflows/ci.yml)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

Brendon Smith ([br3ndonland](https://github.com/br3ndonland))

Expand Down
29 changes: 16 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ build-backend = "hatchling.build"
requires = ["hatchling"]

[project]
authors = [{email = "[email protected]", name = "Your Name"}]
authors = [{ email = "[email protected]", name = "Your Name" }]
classifiers = [
"Natural Language :: English",
"Programming Language :: Python :: 3",
Expand All @@ -21,10 +21,8 @@ requires-python = ">=3.10,<4"

[project.optional-dependencies]
checks = [
"black>=23,<24",
"flake8>=6,<7",
"isort>=5,<6",
"mypy==1.8.0",
"ruff>=0.1,<0.2",
]
docs = [
"mkdocs-material>=9,<10",
Expand Down Expand Up @@ -70,16 +68,15 @@ path = ".venv"

[tool.hatch.envs.default.scripts]
check = [
"black --check --diff .",
"isort --check --diff .",
"flake8 --extend-exclude=.venv,bin,build,cache,dist,lib --max-line-length=88",
"ruff check",
"ruff format --check",
"mypy",
"npx -s -y prettier@'^2' . --check",
"npx -s -y cspell --dot --gitignore *.md **/*.md",
]
format = [
"black .",
"isort .",
"ruff check --fix",
"ruff format",
"npx -s -y prettier@'^2' . --write",
]

Expand All @@ -91,10 +88,6 @@ path = ".venv"
[tool.hatch.version]
path = "template_python/__init__.py"

[tool.isort]
profile = "black"
src_paths = ["template_python", "tests"]

[tool.mypy]
files = ["**/*.py"]
show_error_codes = true
Expand All @@ -104,3 +97,13 @@ strict = true
addopts = "-q"
minversion = "6.0"
testpaths = ["tests"]

[tool.ruff]
extend-select = ["I"]
src = ["template_python", "tests"]

[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint.isort]
known-first-party = ["template_python", "tests"]

0 comments on commit 90b3678

Please sign in to comment.