diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 421080bcf..f09270f0d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,13 +34,11 @@ jobs: curl -LsSf https://astral.sh/uv/install.sh | sh uv pip install --system --upgrade --editable .[dev] - # We choose not to use a Python wrapper or alternative to hadolint as none - # appear to be well maintained, and they require more setup than we would - # want. - - uses: hadolint/hadolint-action@v3.1.0 - with: - dockerfile: src/mock_vws/_flask_server/Dockerfile - - name: "Lint" run: | - make lint + pre-commit run --all-files --hook-stage commit --verbose + pre-commit run --all-files --hook-stage push --verbose + pre-commit run --all-files --hook-stage manual --verbose + + - uses: pre-commit-ci/lite-action@v1.0.2 + if: always() diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..514379cd2 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,163 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + exclude: ^src/mock_vws/resources/ + + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files +- repo: local + hooks: + - id: custom-linters + name: custom-linters + entry: pytest ci/custom_linters.py + stages: [push] + language: system + types: [yaml, python] + pass_filenames: false + + - id: actionlint + name: actionlint + entry: actionlint + language: system + pass_filenames: false + types: [yaml] + + - id: mypy + name: mypy + stages: [push] + entry: mypy . + language: system + types: [python, toml] + pass_filenames: false + + - id: check-manifest + name: check-manifest + stages: [push] + entry: check-manifest . + language: system + pass_filenames: false + + - id: pyright + name: pyright + stages: [push] + entry: pyright . + language: system + types: [python, toml] + pass_filenames: false + + - id: pyright-verifytypes + name: pyright-verifytypes + stages: [push] + entry: pyright --verifytypes mock_vws + language: system + pass_filenames: false + types: [python] + + - id: vulture + name: vulture + entry: vulture --min-confidence 100 --exclude .eggs + language: system + types: [python] + + - id: pyroma + name: pyroma + entry: pyroma --min 10 . + language: system + pass_filenames: false + types: [toml] + + - id: deptry + name: deptry + entry: deptry src/ + language: system + pass_filenames: false + + - id: pylint + name: pylint + entry: pylint *.py src/ tests/ docs/ ci/ + language: system + stages: [manual] + pass_filenames: false + + - id: hadolint-docker + name: Lint Dockerfiles + description: Runs hadolint Docker image to lint Dockerfiles + language: docker_image + types: [dockerfile] + stages: [manual] # Requires Docker to be running + # We choose not to use a Python wrapper or alternative to hadolint as none + # appear to be well maintained, and they require more setup than we would + # want. + entry: ghcr.io/hadolint/hadolint hadolint + + - id: ruff-check + name: Ruff check + entry: ruff check + language: system + types: [python] + + - id: ruff-format-check + name: Ruff format check + entry: ruff format --check + language: system + types: [python] + + - id: ruff-check-fix + name: Ruff check fix + entry: ruff check --fix + language: system + types: [python] + + - id: ruff-format-fix + name: Ruff format + entry: ruff format + language: system + types: [python] + + - id: doc8 + name: doc8 + entry: doc8 + language: system + types: [rst] + + - id: pyproject-fmt-check + name: pyproject-fmt check + entry: pyproject-fmt --check + language: system + types: [toml] + files: pyproject.toml + + - id: pyproject-fmt-fix + name: pyproject-fmt + entry: pyproject-fmt + language: system + types: [toml] + files: pyproject.toml + + - id: linkcheck + name: linkcheck + entry: make -C docs/ linkcheck SPHINXOPTS=-W + language: system + types: [rst] + stages: [manual] + pass_filenames: false + + - id: spelling + name: spelling + entry: make -C docs/ spelling SPHINXOPTS=-W + language: system + types: [rst] + stages: [manual] + pass_filenames: false + + - id: docs + name: Build Documentation + entry: make docs + language: system + stages: [manual] + pass_filenames: false diff --git a/LICENSE b/LICENSE index 69f733fdf..ef26969f8 100644 --- a/LICENSE +++ b/LICENSE @@ -17,4 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/Makefile b/Makefile index f047bf528..e7c51da19 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,5 @@ SHELL := /bin/bash -euxo pipefail -include lint.mk - # Treat Sphinx warnings as errors SPHINXOPTS := -W @@ -11,29 +9,6 @@ update-secrets: tar cvf secrets.tar ci_secrets/ gpg --yes --batch --passphrase=${PASSPHRASE_FOR_VUFORIA_SECRETS} --symmetric --cipher-algo AES256 secrets.tar -.PHONY: lint -lint: \ - actionlint \ - check-manifest \ - deptry \ - doc8 \ - linkcheck \ - mypy \ - pyproject-fmt \ - pyright \ - pyright-verifytypes \ - pyroma \ - ruff \ - spelling \ - vulture \ - pylint \ - custom-linters - -.PHONY: fix-lint -fix-lint: \ - fix-pyproject-fmt \ - fix-ruff - .PHONY: docs docs: make -C docs clean html SPHINXOPTS=$(SPHINXOPTS) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index cb227290f..4ac46f0a6 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -27,20 +27,23 @@ and on Ubuntu with ``apt``: apt-get install -y enchant -Linting -------- - -Run lint tools: +Install ``pre-commit`` hooks: .. prompt:: bash - make lint + pre-commit install + pre-commit install --hook-type pre-push + +Linting +------- -To fix some lint errors, run the following: +Run lint tools either by committing, or with: .. prompt:: bash - make fix-lint + pre-commit run --all-files --hook-stage commit --verbose + pre-commit run --all-files --hook-stage push --verbose + pre-commit run --all-files --hook-stage manual --verbose .. _Homebrew: https://brew.sh diff --git a/lint.mk b/lint.mk deleted file mode 100644 index f7c96b63a..000000000 --- a/lint.mk +++ /dev/null @@ -1,73 +0,0 @@ -# Make commands for linting - -SHELL := /bin/bash -euxo pipefail - -.PHONY: custom-linters -custom-linters: - pytest ci/custom_linters.py - -.PHONY: actionlint -actionlint: - actionlint - -.PHONY: mypy -mypy: - mypy . - -.PHONY: check-manifest -check-manifest: - check-manifest . - -.PHONY: doc8 -doc8: - doc8 . - -.PHONY: ruff -ruff: - ruff check . - ruff format --check . - -.PHONY: fix-ruff -fix-ruff: - ruff check --fix . - ruff format . - -.PHONY: deptry -deptry: - deptry src/ - -.PHONY: pylint -pylint: - pylint *.py src/ tests/ docs/ ci/ - -.PHONY: pyroma -pyroma: - pyroma --min 10 . - -.PHONY: pyright -pyright: - pyright . - -.PHONY: pyright-verifytypes -pyright-verifytypes: - pyright --verifytypes mock_vws - -.PHONY: vulture -vulture: - vulture --min-confidence 100 --exclude _vendor --exclude .eggs . - -.PHONY: linkcheck -linkcheck: - $(MAKE) -C docs/ linkcheck SPHINXOPTS=$(SPHINXOPTS) - -.PHONY: pyproject-fmt -pyproject-fmt: - pyproject-fmt --check pyproject.toml - -.PHONY: fix-pyproject-fmt -fix-pyproject-fmt: - pyproject-fmt pyproject.toml - -.PHONY: spelling -spelling: - $(MAKE) -C docs/ spelling SPHINXOPTS=$(SPHINXOPTS) diff --git a/pyproject.toml b/pyproject.toml index 4b8666ceb..17c1b4c51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -294,6 +294,7 @@ dev = [ "freezegun==1.5.1", "furo==2024.5.6", "mypy==1.10.0", + "pre-commit==3.7.1", "pydocstyle==6.3", "pyenchant==3.2.2", "pylint==3.2.0", diff --git a/src/mock_vws/database.py b/src/mock_vws/database.py index 39fc3c774..865519700 100644 --- a/src/mock_vws/database.py +++ b/src/mock_vws/database.py @@ -6,7 +6,7 @@ import uuid from dataclasses import dataclass, field -from typing import TypedDict +from typing import Self, TypedDict from mock_vws._constants import TargetStatuses from mock_vws.states import States @@ -99,7 +99,7 @@ def get_target(self, target_id: str) -> Target: return target @classmethod - def from_dict(cls, database_dict: DatabaseDict) -> VuforiaDatabase: + def from_dict(cls, database_dict: DatabaseDict) -> Self: """ Load a database from a dictionary. """ diff --git a/src/mock_vws/target.py b/src/mock_vws/target.py index 1ffb0cd43..bdc47eac7 100644 --- a/src/mock_vws/target.py +++ b/src/mock_vws/target.py @@ -10,7 +10,7 @@ import statistics import uuid from dataclasses import dataclass, field -from typing import TYPE_CHECKING, TypedDict +from typing import TYPE_CHECKING, Self, TypedDict from zoneinfo import ZoneInfo from PIL import Image, ImageStat @@ -153,7 +153,7 @@ def tracking_rating(self) -> int: return self._post_processing_target_rating @classmethod - def from_dict(cls, target_dict: TargetDict) -> Target: + def from_dict(cls, target_dict: TargetDict) -> Self: """ Load a target from a dictionary. """ @@ -183,7 +183,7 @@ def from_dict(cls, target_dict: TargetDict) -> Target: target_tracking_rater = HardcodedTargetTrackingRater( rating=target_dict["tracking_rating"], ) - return Target( + return cls( target_id=target_id, name=name, active_flag=active_flag,