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

Moving to Ruff and pyproject.toml #204

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
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
4 changes: 1 addition & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
os:
- ubuntu-latest
- macos-latest
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.10", "3.11", "3.12", "3.13"]
runs-on: ${{ matrix.os }}
name: Run pytest
steps:
Expand All @@ -44,7 +44,6 @@ jobs:
which python
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
conda config --remove channels defaults
conda config --add channels conda-forge
conda config --add channels nodefaults
$CONDA/bin/conda init bash
Expand All @@ -60,7 +59,6 @@ jobs:
which python
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
conda config --remove channels defaults
conda config --add channels conda-forge
conda config --add channels nodefaults
$CONDA/bin/conda init bash
Expand Down
18 changes: 5 additions & 13 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,11 @@ repos:
language: python
args: ["-b", dev, "-b", master, "-b", main]
pass_filenames: false
- id: black
name: black
entry: black
language: system
types: [python]
require_serial: true
# - id: flake8
caldwellst marked this conversation as resolved.
Show resolved Hide resolved
# name: flake8
# entry: flake8
# language: system
# types: [python]
# args: ["--config='{{ cookiecutter.repo_name }}/setup.cfg'"]
# require_serial: true
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
hooks:
- id: ruff
- id: ruff-format
- repo: https://github.com/prettier/pre-commit
rev: v2.1.2
hooks:
Expand Down
2 changes: 1 addition & 1 deletion GUIDELINES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In this document we set out some basic "tips" (either mandatory or encouraged) w

## Foreword

In advance, we recommend installing the autoformatter [black](https://pypi.org/project/black/) in your IDE. In future we will use `flake8` (or similar) for automatically checking our python codebases.
In advance, we recommend installing the linter and autoformatter [ruff](https://pypi.org/project/ruff/) in your IDE.

Hopefully the conventions laid out here are the easy and intuitive set of [pep8](https://www.python.org/dev/peps/pep-0008/).

Expand Down
10 changes: 3 additions & 7 deletions docs/docs/structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,23 +311,19 @@ You can write reports in markdown and put them in `outputs/reports` and referenc
│ ├── pipeline/ | Pipeline components
│ └── utils/ | Utilities
├── docs/ | DOCUMENTATION
├── pyproject.toml | PROJECT METADATA AND CONFIGURATION
├── environment.yaml | CONDA ENVIRONMENT SPECIFICATION (optional component)
├── requirements.txt | PYTHON DEPENDENCIES NEEDED TO RUN THE CODE
├── requirements_dev.txt | PYTHON DEV DEPENDENCIES (e.g. building docs/running tests)
├── inputs/ | INPUTS (should be immutable)
├── jupytext.toml | JUPYTEXT CONFIGURATION
├── LICENSE |
├── outputs/ | OUTPUTS PRODUCED FROM THE PROJECT
├── outputs/ | OUTPUTS PRODUCED FROM THE PROJECT
caldwellst marked this conversation as resolved.
Show resolved Hide resolved
├── Makefile | TASKS TO COORDINATE PROJECT (`make` shows available commands)
├── README.md |
├── setup.py | ALLOWS US TO PIP INSTALL src/
├── setup.cfg | ADDITIONAL PROJECT CONFIGURATION, e.g. flake8
├── .pre-commit-config.yaml | DEFINES CHECKS THAT MUST PASS BEFORE git commit SUCCEEDS
├── .gitignore | TELLS git WHAT FILES WE DON'T WANT TO COMMIT
├── .github/ | GITHUB CONFIGURATION
├── .env | SECRETS (never commit to git!)
├── .envrc | SHARED PROJECT CONFIGURATION VARIABLES
── .cookiecutter | COOKIECUTTER SETUP & CONFIGURATION (user can safely ignore)
── .cookiecutter | COOKIECUTTER SETUP & CONFIGURATION (user can safely ignore)
```

## The Makefile
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ mkdocs
mkdocs-material
mkdocs-material-extensions
cookiecutter
tomli
pytest
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"project_name": "NestaTestCookie".lower(),
"author_name": "Nesta",
"repo_name": "nestatestcookie",
"openness": "public"
}


Expand Down
42 changes: 18 additions & 24 deletions tests/test_creation.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import os
import re
import sys
import tomli
from contextlib import contextmanager
from pathlib import Path
from subprocess import CalledProcessError, check_output
from typing import List

import pytest


@contextmanager
def ch_dir(path):
"""Context Manager to change directory to `path`."""
Expand Down Expand Up @@ -42,13 +42,6 @@ def test_project_name(self):
name = "NestaTestCookie".lower()
assert project.name == name

def test_author(self):
"""Test author set in `setup.py`."""
setup_ = self.path / "setup.py"
args = ["python", setup_, "--author"]
p = "".join(shell(args))
assert p == "Nesta"

def test_readme(self):
"""Test README.md exists with no curlies."""
readme_path = self.path / "README.md"
Expand All @@ -57,28 +50,29 @@ def test_readme(self):
with open(readme_path) as fin:
assert "# NestaTestCookie".lower() == next(fin).strip()

def test_version(self):
"""Test version set in `setup.py`."""
setup_ = self.path / "setup.py"
args = ["python", setup_, "--version"]
p = "".join(shell(args))
assert p == "0.1.0"

def test_license(self):
"""Test LICENSE exists with no curlies."""
license_path = self.path / "LICENSE"
assert license_path.exists()
assert no_curlies(license_path)

def test_license_type(self):
"""Test License set appropriately in `setup.py`."""
setup_ = self.path / "setup.py"
args = ["python", setup_, "--license"]
p = "".join(shell(args))
if pytest.param.get("openess") == "private":
assert p == "proprietary"
def test_metadata(self):
"""Test project metadata in pyproject.toml."""
pyproject_path = self.path / "pyproject.toml"
assert pyproject_path.exists()
assert no_curlies(pyproject_path)

with open(pyproject_path, "rb") as f:
pyproject = tomli.load(f)

project = pyproject.get("project", {})
assert project.get("name") == "nestatestcookie"
assert project.get("version") == "0.1.0"
assert any(author.get("name") == "Nesta" for author in project.get("authors", []))
if pytest.param.get("openness") == "private":
assert project.get("license", {}).get("text") == "proprietary"
else:
assert p == "MIT"
assert project.get("license", {}).get("text") == "MIT"

def test_makefile(self):
"""Test Makefile exists with no curlies."""
Expand All @@ -93,7 +87,7 @@ def test_curlies(self):
".env",
".envrc",
"README.md",
"setup.cfg",
"pyproject.toml",
"docs/conf.py",
"docs/index.rst",
f"{repo_name}/config/logging.yaml",
Expand Down
23 changes: 5 additions & 18 deletions {{ cookiecutter.repo_name }}/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
repos:
- repo: local
hooks:
- id: black
name: black
entry: black
language: system
types: [python]
require_serial: true
- id: check-added-large-files
name: Check for added large files
entry: check-added-large-files
Expand Down Expand Up @@ -37,24 +31,17 @@ repos:
entry: check-yaml
language: system
types: [yaml]
# - id: reorder-python-imports
# name: Reorder python imports
# entry: reorder-python-imports
# language: system
# types: [python]
# - id: flake8
# name: flake8
# entry: flake8
# language: system
# types: [python]
# args: ["--config=.flake8"]
# require_serial: true
- id: no-commit-to-branch
name: Prevent commits to dev / master
entry: no-commit-to-branch
language: python
args: ["-b", dev, "-b", master, "-b", main]
pass_filenames: false
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
hooks:
- id: ruff
- id: ruff-format
- repo: https://github.com/prettier/pre-commit
rev: v2.1.2
hooks:
Expand Down
16 changes: 12 additions & 4 deletions {{ cookiecutter.repo_name }}/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,18 @@ pip-install:
@pip install -e ".[dev]"

.PHONY: conda-remove
## Remove the conda-environment cleanly, using -f so works even if no environment to be removed
## Remove the conda-environment cleanly
conda-remove:
conda env remove -n ${REPO_NAME}
rm -f .cookiecutter/state/conda-create*
@echo "Checking if conda environment ${REPO_NAME} exists"
@if conda info --envs | grep -q ${REPO_NAME}; then \
if conda info --envs | grep '*' | grep -q ${REPO_NAME}; then \
echo "Error: Conda environment ${REPO_NAME} is currently active. Please run `conda deactivate` before proceeding."; \
exit 1; \
fi; \
conda env remove -n ${REPO_NAME}; \
echo "Removing conda-create state files"; \
rm -f .cookiecutter/state/conda-create*; \
fi
@direnv reload

.PHONY: clean
Expand Down Expand Up @@ -97,7 +105,7 @@ endef
.cookiecutter/state/setup-git:
@echo -n "Installing and configuring git pre-commit hooks"
@(eval "$$(conda shell.bash activate "${REPO_NAME}")"\
&&pre-commit install --install-hooks)\
&& pre-commit install --install-hooks)\
> [email protected] 2>&1\
|| $(call err,Git pre-commit setup failed)
@touch $@
Expand Down
1 change: 0 additions & 1 deletion {{ cookiecutter.repo_name }}/docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from datetime import datetime


project = "{{ cookiecutter.project_name }}"
author = "{{ cookiecutter.author_name }}"
copyright = f"{datetime.now().year}, {author}"
Expand Down
10 changes: 0 additions & 10 deletions {{ cookiecutter.repo_name }}/jupytext.toml

This file was deleted.

61 changes: 61 additions & 0 deletions {{ cookiecutter.repo_name }}/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
packages = ["{{ cookiecutter.repo_name }}"]

[project]
name = "{{ cookiecutter.project_name }}"
version = "0.1.0"
description = "{{ cookiecutter.description }}"
authors = [{name = "{{ cookiecutter.author_name }}"}]
license = {text = "{% if cookiecutter.openness == 'public' %}MIT{% else %}proprietary{% endif %}"}
readme = "README.md"
requires-python = ">=3.10"
dependencies = []

[project.urls]
repository = "https://github.com/nestauk/{{ cookiecutter.repo_name }}"
issues = "https://github.com/nestauk/{{ cookiecutter.repo_name }}/issues"

[project.optional-dependencies]
dev = [
"ipykernel",
"jupytext",
"ruff",
"Sphinx",
"sphinxcontrib-napoleon",
"sphinx-rtd-theme",
"pytest",
"pre-commit",
"pre-commit-hooks"
]

[tool.jupytext]
# Always pair ipynb notebooks to py:percent files
default_jupytext_formats = "ipynb,py:percent"
# Comment out magics (allows code formatting)
comment_magics = true
# Strip cell-level metadata (avoid polluting git diffs)
default_cell_metadata_filter = "-all"

[tool.ruff.lint]
select = ["ANN", "B", "C", "D", "E", "F", "I", "N", "W"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a reasonable selection! Will be mainly interested how people using the current code base feel. Particularly around mandating a docstring convention? But I am all for it!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I noticed that was enabled in current flake8 config, I don't usually support those but just tried to stay close for now

# S101 - warns about assert being removed when compiled
# D100 - warns about missing module-level docstrings
ignore = ["S101", "D100"]
mccabe = { max-complexity = 10 }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please!


[tool.ruff.lint.isort]
known-first-party = ["{{ cookiecutter.repo_name }}"]

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401", "E402", "D104"]

[tool.ruff.format]
docstring-code-format = true
docstring-code-line-length = "dynamic"
Empty file.
14 changes: 0 additions & 14 deletions {{ cookiecutter.repo_name }}/requirements_dev.txt

This file was deleted.

38 changes: 0 additions & 38 deletions {{ cookiecutter.repo_name }}/setup.cfg

This file was deleted.

Loading
Loading