Skip to content

Commit

Permalink
Pre-commit: add Ruff (#261)
Browse files Browse the repository at this point in the history
* Replaces flake8 and all its enabled plugins with Ruff
* Use Ruff formatter as a drop-in replacement of Black
* Simplifies the configuration using a single `pyproject.toml` instead of multiple files (`pytest.ini`, `flake8`).
  • Loading branch information
edoardob90 authored Nov 20, 2024
1 parent 5a3fa10 commit 04ab64c
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 126 deletions.
8 changes: 0 additions & 8 deletions .flake8

This file was deleted.

50 changes: 24 additions & 26 deletions .github/workflows/build-docker-image.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
---
name: Build Tutorial Container
on:
push:
branches:
- main
paths-ignore:
- '*.md'
- slides/**
- images/**
- .gitignore
workflow_dispatch:

push:
branches:
- main
paths-ignore:
- '*.md'
- slides/**
- images/**
- .gitignore
workflow_dispatch:
jobs:
repo2docker:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: checkout files in repo
uses: actions/checkout@main

- name: update jupyter dependencies with repo2docker
uses: jupyterhub/repo2docker-action@master
with:
DOCKER_USERNAME: ${{ github.actor }}
DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
DOCKER_REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
FORCE_REPO2DOCKER_VERSION: jupyter-repo2docker==2023.06.0
repo2docker:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: checkout files in repo
uses: actions/checkout@main
- name: update jupyter dependencies with repo2docker
uses: jupyterhub/repo2docker-action@master
with:
DOCKER_USERNAME: ${{ github.actor }}
DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
DOCKER_REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
FORCE_REPO2DOCKER_VERSION: jupyter-repo2docker==2023.06.0
96 changes: 31 additions & 65 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,68 +1,34 @@
---
ci:
autoupdate_schedule: quarterly

autoupdate_schedule: quarterly
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
exclude: miscellaneous/structures/SiO2.xyz
- id: check-yaml
- id: check-added-large-files
args: [--maxkb=6000]
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: [--profile, black, --filter-files]
- repo: https://github.com/PyCQA/autoflake
rev: v2.3.1
hooks:
- id: autoflake
- repo: https://github.com/asottile/pyupgrade
rev: v3.16.0
hooks:
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black
language_version: python3 # Should be a command that runs python3.6+
- repo: https://github.com/PyCQA/flake8
rev: 7.1.0
hooks:
- id: flake8
args: [--count, --show-source, --statistics]
additional_dependencies:
- flake8-bugbear
- flake8-builtins
- flake8-comprehensions
- flake8-debugger
- flake8-logging-format
- pep8-naming
- pyflakes
- tryceratops
# - repo: https://github.com/pre-commit/mirrors-mypy
# rev: v1.5.1
# hooks:
# - id: mypy
# additional_dependencies:
# - types-click-spinner
# - types-requests
# - types-tabulate
# - types-toml
- repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt
rev: 0.2.3
hooks:
- id: yamlfmt
- repo: https://github.com/asottile/setup-cfg-fmt
rev: v2.5.0
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/kynan/nbstripout
rev: 0.7.1
hooks:
- id: nbstripout
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-yaml
- id: check-added-large-files
args: [--maxkb=6000]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.4
hooks:
# Ruff fix
- id: ruff
types_or: [python, pyi]
args: [--fix]
name: ruff (fix)
# Ruff formatter
- id: ruff-format
types_or: [python, pyi]
name: ruff (format)
- repo: https://github.com/google/yamlfmt
rev: v0.14.0
hooks:
- id: yamlfmt
name: YAML (format)
types: [yaml]
- repo: https://github.com/kynan/nbstripout
rev: 0.8.1
hooks:
- id: nbstripout
5 changes: 5 additions & 0 deletions .yamlfmt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
formatter:
type: basic
include_document_start: true
retain_line_breaks: true
output_format: line
38 changes: 19 additions & 19 deletions binder/environment.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
---
name: python-tutorial
channels:
- conda-forge
- conda-forge
dependencies:
- python=3.10
- pip
- pip:
- numpy
- matplotlib
- pandas
- ipywidgets
- ipynbname
- jupyterlab
- pytest
- pytest-timeout
- markdown
- pre-commit
- geostatspy
- gstools
- scikit-learn
- attrs
- multiprocess
- python=3.10
- pip
- pip:
- numpy
- matplotlib
- pandas
- ipywidgets
- ipynbname
- jupyterlab
- pytest
- pytest-timeout
- markdown
- pre-commit
- geostatspy
- gstools
- scikit-learn
- attrs
- multiprocess
58 changes: 58 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
[tool.ruff]
# Line length (Black default)
line-length = 88

# Python target version
target-version = "py38"

# Ignored rules for the entire project
[tool.ruff.lint]
ignore = [
"E501", # Line too long
"E203", # Whitespace before ':'
# "TRY301", # Raise within try block (this is actually a good practice)
# "W503" # Line break before binary operator (not PEP8 enforced, so not implemented in Ruff)
]

# flake8 plugins to enable:
# - flake8-bugbear B
# - flake8-builtins A
# - flake8-comprehensions C4
# - flake8-debugger T10
# - flake8-logging-format G
# - pep8-naming N
# - pyflakes F
# - tryceratops TRY
select = [
"A", # flake8-builtins
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"T10", # flake8-debugger
"G", # flake8-logging-format
"N", # pep8-naming
"F", # pyflakes
"TRY", # tryceratops
"I", # isort
"E", # pycodestyle errors
"UP", # pyupgrade
]

# Per-file rule ignores
[tool.ruff.lint.per-file-ignores]
# Trailing whitespace in comment
"binder/ipython_config.py" = ["E266"]
# suppress `raise ... from err`
# Why we ignore B904 from the object-oriented tests?
# We do want to raise an assertion error if the check on the solution function attributes fails,
# but Python by default will raise a TypeError via vars(solution_result)
# if the result is not a class and therefore doesn't have a __dict__ attribute.
"tutorial/tests/test_object_oriented_programming.py" = ["B904"]

# Ruff formatting
[tool.ruff.format]
quote-style = "double"
indent-style = "space"

# pytest
[tool.pytest.ini_options]
addopts = "-v --tb=short"
2 changes: 0 additions & 2 deletions pytest.ini

This file was deleted.

2 changes: 1 addition & 1 deletion tutorial/tests/test_functional_programming.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def reference_exercise6(my_list: List[Tuple[str, int]]) -> List[Tuple[str, float


def test_exercise6(
function_to_test: Callable[[List[Tuple[str, int]]], List[Tuple[str, float]]]
function_to_test: Callable[[List[Tuple[str, int]]], List[Tuple[str, float]]],
):
input_data = reference_exercise5(get_data_exercise5())
assert function_to_test(input_data) == reference_exercise6(input_data)
Expand Down
4 changes: 1 addition & 3 deletions tutorial/tests/test_input_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ def test_write_file(function_to_test, tmp_path: pl.Path):
function_to_test(tmp_user)
reference_write_file(tmp_test)

assert (
tmp_user.exists()
), """The file was not created. Make sure to create the file in the function. Hint: use `open(output_file, "w")`"""
assert tmp_user.exists(), """The file was not created. Make sure to create the file in the function. Hint: use `open(output_file, "w")`"""

assert (
tmp_user.read_text() == tmp_test.read_text()
Expand Down
4 changes: 2 additions & 2 deletions tutorial/tests/test_object_oriented_programming.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ def test_oop_str_and_repr(first_name, last_name, function_to_test):
validate_oop_str_method(solution_result)
validate_oop_repr_method(solution_result)

assert str(solution_result) == str(
reference_result
assert (
str(solution_result) == str(reference_result)
), "The __str__() result does not match the template 'My name is {first_name} {last_name}'."
assert (
solution_result.__repr__() == reference_result.__repr__()
Expand Down
1 change: 1 addition & 0 deletions tutorial/toc.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python
"""CLI script to build a table of contents for an IPython notebook"""

import argparse as ap
import pathlib
import re
Expand Down

0 comments on commit 04ab64c

Please sign in to comment.