From cd632d34f472f84379ef1e8b606b1d4384842ace Mon Sep 17 00:00:00 2001 From: abk16 Date: Sat, 16 Mar 2024 11:32:14 +0100 Subject: [PATCH] ci: add pre-commit, linters configs, github workflows, .gitignore --- .github/workflows/pre-commit.yml | 54 +++++++++ .gitignore | 188 +++++++++++++++++++++++++++++++ .gitlint | 14 +++ .pre-commit-config.yaml | 83 ++++++++++++++ pyproject.toml | 121 ++++++++++++++++++++ 5 files changed, 460 insertions(+) create mode 100644 .github/workflows/pre-commit.yml create mode 100644 .gitignore create mode 100644 .gitlint create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..4641e63 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,54 @@ +name: pre-commit + +on: + pull_request: + push: + branches: + - main +jobs: + pre-commit: + name: pre-commit + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + clean: false + ref: ${{ github.head_ref }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.8' + cache: 'pip' + # N.B. we don't need all the dependencies to run the code for just pre-commit + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Cache pre-commit envs + uses: actions/cache@v2 + with: + path: ~/.cache/pre-commit + key: ${{ runner.os }}-pre-commit-${{ hashFiles('**/requirements-dev.txt') }}-${{ hashFiles('**/.pre-commit-config.yaml') }} + restore-keys: | + ${{ runner.os }}-pre-commit-${{ hashFiles('**/requirements-dev.txt') }}- + ${{ runner.os }}-pre-commit- + + - name: Run pre-commit + env: + REF_BEFORE: ${{ github.event_name == 'pull_request' && github.base_ref || github.event.before }} + REF_AFTER: ${{ github.event_name == 'pull_request' && github.head_ref || github.event.after }} + run: | + # make sure dropped commits are fetched + git fetch origin $REF_BEFORE:$REF_BEFORE + # if it's a push, check since the common ancestor of the before/after (for forced pushes) + if [[ "${{ github.event_name }}" == "push" ]]; then + export REF_BEFORE=$(git merge-base $REF_BEFORE $REF_AFTER) + fi + # make sure gitlint knows which commits to lint + export GITLINT_COMMITS=$REF_BEFORE..$REF_AFTER + # run pre-commit + pre-commit run --from-ref $REF_BEFORE --to-ref $REF_AFTER diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f591def --- /dev/null +++ b/.gitignore @@ -0,0 +1,188 @@ +# OS files +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ +*.msm +*.msp +*.lnk +.DS_Store +.AppleDouble +.LSOverride +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +logs + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ + +# Added by paper-dragonfly +/media/ +/models/ diff --git a/.gitlint b/.gitlint new file mode 100644 index 0000000..88aaa52 --- /dev/null +++ b/.gitlint @@ -0,0 +1,14 @@ +[general] +ignore=body-max-line-length, body-is-missing, contrib-disallow-cleanup-commits +contrib=contrib-title-conventional-commits +ignore-merge-commits=false +regex-style-search=True + +[title-max-length] +line-length=70 + +[body-min-length] +min-length=5 + +[contrib-title-conventional-commits] +types = fix,feat,chore,docs,style,refactor,ref,perf,test,revert,ci,build diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3594a85 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,83 @@ +default_language_version: + python: python3.8 +exclude: ^(build|dist|.*\.egg(-info)?|\.github) + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-added-large-files + - id: check-ast + - id: check-case-conflict + - id: trailing-whitespace + exclude: (\.md|\.rst|splash.py)$ + - id: end-of-file-fixer + - id: check-yaml + - id: check-merge-conflict + - id: check-symlinks + - id: check-xml + - id: check-executables-have-shebangs + - id: check-shebang-scripts-are-executable + exclude: (\.jinjia2?|\.j2)$ + - id: debug-statements + - id: destroyed-symlinks + - id: detect-private-key + exclude: ^(modules) + - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: fix-encoding-pragma + args: [ "--remove" ] + - id: mixed-line-ending + args: [ "--fix=lf" ] + - id: name-tests-test + args: [ "--pytest-test-first" ] + - id: requirements-txt-fixer + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.14 + hooks: + - id: ruff-format + - id: ruff + name: ruff-required + args: + - --ignore=FIX,ERA,D,PLR6301,PLR2004,RUF100 + - --fix + - --exit-non-zero-on-fix + - id: ruff + name: ruff-optional + verbose: true + args: + - --select=FIX,ERA,D,PLR6301,PLR2004 + - --ignore=D105,D107,D203,D205,D212,RUF100 + - --no-fix + - --exit-zero + # this one is needed to properly apply noqa removal when all rules are selected, N.B. will exit 0 + - id: ruff + name: ruff-cleanups + args: + - --fix + - --silent + - --exit-zero + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + exclude: ^tests/ + args: + - --install-types + - --non-interactive + additional_dependencies: + - numpy + + - repo: https://github.com/Lucas-C/pre-commit-hooks-safety + rev: v1.3.2 + hooks: + - id: python-safety-dependencies-check + files: requirements.*\.txt + + - repo: https://github.com/jorisroovers/gitlint + rev: v0.19.1 + hooks: + - id: gitlint + - id: gitlint-ci diff --git a/pyproject.toml b/pyproject.toml index f0aa3c6..2075f8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -85,3 +85,124 @@ exclude_lines = [ "if __name__ == .__main__.:", "if TYPE_CHECKING:", ] + +[tool.ruff] +fix = true +show-fixes = true +preview = true +line-length = 100 + +[tool.ruff.lint] +ignore-init-module-imports = true +select = [ + # entire rule-sets + "F", # PyFlakes + "E", # pycodestyle errors + "W", # pycodestyle warnings + "I", # isort + "N", # PEP8 naming + "D", # PyDocStyle + "UP", # PyUpgrade + "ASYNC", # flake8-async + "S", # flake8-bandit + "BLE", # flake8-blind-except + "FBT", # flake8-boolean-trap + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "DTZ", # flake8-datetimez + "T10", # flake8-debugger + "EXE", # flake8-executable + "ICN", # flake8-import-conventions + "PIE", # flake8-pie + "T20", # flake8-print + "PT", # flake8-pytest-style + "Q", # flake8-quotes + "RSE", # flake8-raise + "RET", # flake8-return + "SLF", # flake8-self + "SLOT", # flake8-slots + "SIM", # flake8-simplify + "TID", # flake8-tidy-imports + "TCH", # flake8-type-checking + "INT", # flake8-gettext + "ARG", # flake8-unused-arguments + "PTH", # flake8-use-pathlib + "TD", # flake8-todos + "FIX", # flake8-fixme + "ERA", # flake8-eradicate + "PGH", # flake8-pygrep-hooks + "PL", # Pylint + "TRY", # tryceratops + "FLY", # flynt + "PERF", # perflint + "FURB", # refurb + "LOG", # flake8-logging + "RUF", # ruff-specific-rules + + # explicit rules + "G010", # logging statement uses `warn` instead of `warning` + "G101", # logging statement uses an `extra` field that clashes with LogRecord + "G201", # `logging.exception` should be used instead of `logging.error(..., exc_info=True)` + "G202", # logging statement has redundant `exc_info` + "ISC003", # explicitly concatenated string should be implicitly concatenated +] +ignore = [ + "ARG002", # unused method argument + "ARG003", # unused class method argument + "B904", # use `raise from` within except + "C408", # unnecessary dict call - rewrite as a literal + "D105", # missing docstring in magic method + "D107", # missing docstring in __init__ + "D203", # 1 blank line required before class docstring + "D205", # 1 blank line required between summary line and description + "D212", # multi-line docstring summary should start at the first line + "F403", # `from module import *` used; unable to detect undefined names + "FBT003", # boolean positional value in function call + "N816", # variable in global scope should not be mixedCase + "N818", # exception should be named with an `Error` suffix + "PLW0602", # `global` for variable but no assignment + "PT018", # assertions should be broken down into multiple parts + "PTH123", # open() should be replaced by Path.open() + "RET505", # unnecessary else/elif after return statement + "S101", # use of assert detected + "S307", # usage of builtin `eval()` + "S311", # cryptographic usage of `random` module + "S320", # usage of `lxml` + "S404", # usage of `subprocess` module + "S603", # subprocess call - check for execution of untrusted input + "SIM105", # prefer `contextlib.suppress` over `try/except/pass` + "TD001", # invalid TODO tags + "TD002", # author name in TODOs + "TD003", # issue link in TODOs + "TRY003", # long message in exception call + "TRY301", # raise within try - abstract raise to an inner function +] + +[tool.ruff.lint.per-file-ignores] +"tests/**" = ["D", "S", "T", "SLF001", "PLR2004", "PLR6301"] + +[tool.ruff.lint.pycodestyle] +ignore-overlong-task-comments = true +max-line-length = 120 + +[tool.ruff.lint.isort] +combine-as-imports = true +lines-after-imports = 2 + +[tool.ruff.lint.pylint] +max-args = 10 +max-bool-expr = 8 +max-branches = 20 +max-returns = 8 +max-public-methods = 25 +max-statements = 70 + +[tool.mypy] +show_error_codes = true +ignore_missing_imports = true +warn_return_any = true +allow_redefinition = true +disallow_untyped_defs = true +disallow_incomplete_defs = true +disallow_untyped_decorators = true +plugins = ["numpy.typing.mypy_plugin"]