Skip to content
Merged
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
13 changes: 7 additions & 6 deletions .envrc
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# automatically activate dev environment when in project tree using direnv.
ACT=.nox/dev/bin/activate
ACT=".nox/dev/bin/activate"

if [ -e $ACT ]
then
source $ACT
if [[ -f "${ACT}" ]]; then
source "${ACT}"
else
echo "Activation script ${ACT} not found for dev environment.
Run nox -s dev to install dev environment"
cat <<EOF
Activation script "${ACT}" not found for dev environment.
Run 'nox -s dev' to install dev environment
EOF
fi
43 changes: 19 additions & 24 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,35 +1,30 @@
repos:
- repo: https://github.com/myint/autoflake
rev: v2.3.1
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.8
hooks:
- id: autoflake
args: ["--in-place", "--imports=fillname", "--ignore-init-module-imports", "--remove-unused-variables"]
exclude: ^.github/
- id: ruff-check
args: [--fix]
- id: ruff-format

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
exclude: ^.github/

- repo: https://github.com/pycqa/isort
rev: 7.0.0
hooks:
- id: isort
- id: end-of-file-fixer
- id: trailing-whitespace
exclude: ^.github/

- repo: https://github.com/psf/black
rev: 25.9.0
hooks:
- id: black
exclude: ^.github/

- repo: https://github.com/executablebooks/mdformat
rev: 1.0.0
hooks:
- id: mdformat
args: ["--wrap", "79"]
exclude: ^docs/
additional_dependencies:
- mdformat-gfm
- id: mdformat
args: ["--wrap", "79"]
exclude: ^docs/
additional_dependencies:
- mdformat-gfm

- repo: https://github.com/allganize/ty-pre-commit
rev: v0.0.46
hooks:
- id: ty-check
exclude: "^noxfile\\.py$"
additional_dependencies: ["pytest"]
14 changes: 8 additions & 6 deletions init.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import subprocess


def read(prompt, regex, default):
def read(prompt: str, regex: str, default: str | None) -> str:
"""
Read a string from command line.

Expand All @@ -28,7 +28,7 @@ def read(prompt, regex, default):
print(f"the project name has to match the regular expression: {regex}")


def git_config_get(attr):
def git_config_get(attr: str) -> str | None:
"""
Get a git config value.
"""
Expand All @@ -38,11 +38,10 @@ def git_config_get(attr):
return None


def main():
def main() -> None:
"""
Rename the project.
"""

author = git_config_get("user.name")
email = git_config_get("user.email")
origin = git_config_get("remote.origin.url")
Expand All @@ -60,14 +59,17 @@ def main():
email = read("email", r".+", email)
url = read("url", r".+", url)

replacements = {
replacements: dict[str, str] = {
"author@fillname.org": email,
"Author Fillname": author,
"https://fillname.org/": url,
"fillname": project,
}

def replace(filepath):
def replace(filepath: str) -> None:
"""
Apply replacements to the given file.
"""
with open(filepath, "r", encoding="utf-8") as hnd:
content = hnd.read()
for key, val in replacements.items():
Expand Down
42 changes: 22 additions & 20 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
"""
Nox sessions for linting, type checking and testing.
"""

import os

import nox
import nox # type: ignore

nox.options.sessions = "lint_pylint", "typecheck", "test"
nox.options.sessions = "lint", "typecheck", "test"
nox.options.default_venv_backend = "uv|virtualenv"

EDITABLE_TESTS = True
PYTHON_VERSIONS = None
if "GITHUB_ACTIONS" in os.environ:
PYTHON_VERSIONS = ["3.10", "3.14"]
EDITABLE_TESTS = False


@nox.session
Expand All @@ -22,38 +25,37 @@ def dev(session):


@nox.session
def lint_pylint(session):
def lint(session):
"""
Run pylint.
Run ruff.
"""
session.install("-e", ".[lint_pylint]")
session.run("pylint", "fillname", "tests")
if not session.virtualenv._reused:
session.install(".[lint]")
session.run("ruff", "check")
session.run("ruff", "format", "--check")


@nox.session
def typecheck(session):
"""
Typecheck the code using mypy.
"""
session.install("-e", ".[typecheck]")
session.run("mypy", "--strict", "-p", "fillname", "-p", "tests")
if not session.virtualenv._reused:
session.install(".[typecheck]")
session.run("ty", "check")


@nox.session(python=PYTHON_VERSIONS)
def test(session):
"""
Run the tests.

Accepts an additional arguments which are passed to the unittest module.
This can for example be used to selectively run test cases.
Accepts additional arguments which are passed to the pytest module. This
can for example be used to selectively run test cases via option `-k`.
"""

args = [".[test]"]
if EDITABLE_TESTS:
args.insert(0, "-e")
session.install(*args)
if not session.virtualenv._reused:
session.install(".[test]")
if session.posargs:
session.run("coverage", "run", "-m", "unittest", session.posargs[0], "-v")
session.run("pytest", "-v", *session.posargs)
else:
session.run("coverage", "run", "-m", "unittest", "discover", "-v")
session.run("coverage", "report", "-m", "--fail-under=100")
session.run("pytest", "--cov", "-v")
70 changes: 40 additions & 30 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
name = "fillname"
authors = [{ name = "Author Fillname", email = "author@fillname.org" }]
description = "A template project."
requires-python = ">=3.9"
requires-python = ">=3.10"
license = { file = "LICENSE" }
dynamic = ["version"]
readme = "README.md"
Expand All @@ -15,12 +15,11 @@ readme = "README.md"
Homepage = "https://fillname.org/"

[project.optional-dependencies]
format = ["black", "isort", "autoflake"]
lint_pylint = ["pylint"]
typecheck = ["types-setuptools", "mypy"]
test = ["coverage[toml]"]
lint = ["ruff"]
typecheck = ["pytest", "ty"]
test = ["pytest", "pytest-cov", "coverage[toml]"]
doc = ["mkdocs", "mkdocs-material", "mkdocstrings[python]", "mkdoclingo"]
dev = ["fillname[test,typecheck,lint_pylint]"]
dev = ["pre[test,typecheck,lint]"]

[project.scripts]
fillname = "fillname.__main__:main"
Expand All @@ -39,35 +38,46 @@ line_length = 120
[tool.black]
line-length = 120

[tool.pylint.format]
max-line-length = 120
[tool.ruff]
line-length = 120
target-version = "py310"
exclude = [
"/usr/**",
"**/site-packages/**",
"**/node_modules/**",
"**/typeshed-fallback/**",
]

[tool.pylint.design]
max-args = 10
max-attributes = 7
max-bool-expr = 5
max-branches = 12
max-locals = 30
max-parents = 7
max-public-methods = 20
max-returns = 10
max-statements = 50
min-public-methods = 1
[tool.ruff.lint]
extend-select = ["I", "E", "F", "B", "C4", "D", "ARG", "SIM", "ANN", "Q"]
ignore = [
"E741",
"D200",
"D203",
"D212",
"D413",
"B023", # broken lint
]

[tool.pylint.similarities]
ignore-comments = true
ignore-docstrings = true
ignore-imports = true
ignore-signatures = true
[tool.ruff.lint.per-file-ignores]
"noxfile.py" = ["ANN"]

[tool.pylint.basic]
argument-rgx = "^[a-z][a-z0-9]*((_[a-z0-9]+)*_?)?$"
variable-rgx = "^[a-z][a-z0-9]*((_[a-z0-9]+)*_?)?$"
good-names = ["_"]
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = "test_*.py"
python_functions = "test_*"

[tool.coverage.run]
source = ["fillname", "tests"]
omit = ["*/fillname/__main__.py"]
omit = ["*/fillname/__main__.py", "*/fillname/utils/logging.py"]

[tool.coverage.report]
exclude_lines = ["assert", "nocoverage"]
show_missing = true
fail_under = 100
exclude_lines = [
"raise NotImplementedError",
"raise TypeError",
"nocoverage",
"assert",
"\\.\\.\\.",
]
11 changes: 10 additions & 1 deletion src/fillname/utils/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,18 @@ class SingleLevelFilter(logging.Filter):
passlevel: int
reject: bool

def __init__(self, passlevel: int, reject: bool):
def __init__(self, passlevel: int, reject: bool) -> None:
"""
Initialize the filter.
"""
# pylint: disable=super-init-not-called
self.passlevel = passlevel
self.reject = reject

def filter(self, record: logging.LogRecord) -> bool:
"""
Apply custom filter for records.
"""
if self.reject:
return record.levelno != self.passlevel # nocoverage

Expand All @@ -63,6 +69,9 @@ def make_handler(level: int, color: str) -> "logging.StreamHandler[TextIO]":
handler.setFormatter(formatter)
return handler

for h in logging.root.handlers[:]:
logging.root.removeHandler(h)

handlers = [
make_handler(logging.INFO, "GREEN"),
make_handler(logging.WARNING, "YELLOW"),
Expand Down
3 changes: 3 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
The tests package contains all the test cases for the project.
"""
Loading