Skip to content

Commit 9c2c7b4

Browse files
authored
Added basic git pre-commit hook setup for auto-formatting (#1405)
* Added basic git pre-commit hook setup for auto-formatting. Also: - Added a simple Makefile for easily installing and using a uv-based local dev setup - Refactored pyproject.toml to use the recommended dependency-groups and minimum versions for all dependencies
1 parent c5ccd25 commit 9c2c7b4

File tree

12 files changed

+162
-77
lines changed

12 files changed

+162
-77
lines changed

.github/CONTRIBUTING.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ $ pip freeze | grep pyperclip
8888

8989
If your versions are lower than the prerequisite versions, you should update.
9090

91-
If you do not already have Python installed on your machine, we recommend using [uv](https://github.com/astral-sh/uv)
91+
If you do not already have Python installed on your machine, we recommend using [uv](https://github.com/astral-sh/uv)
9292
for all of your Python needs because it is extremely fast, meets all Python installation and packaging needs, and works
9393
on all platforms (Windows, Mac, and Linux). You can install `uv` using instructions at the link above.
9494

@@ -221,7 +221,13 @@ To create a virtual environment and install everything needed for `cmd2` develop
221221
from a GitHub checkout:
222222

223223
```sh
224-
uv venv
224+
make install
225+
```
226+
227+
To install the recommended Git pre-commit hooks for auto-formatting locally, do the following:
228+
229+
```sh
230+
uv run pre-commit run -a
225231
```
226232

227233
To create a new virtualenv, using a specific version of Python you have installed, use the

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,4 @@ uv.lock
5454
# Node/npm used for installing Prettier locally to override the outdated version that is bundled with the VSCode extension
5555
node_modules/
5656
package-lock.json
57-
package.json
57+
package.json

.pre-commit-config.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: "v5.0.0"
4+
hooks:
5+
- id: check-case-conflict
6+
- id: check-merge-conflict
7+
- id: end-of-file-fixer
8+
- id: trailing-whitespace
9+
10+
- repo: https://github.com/astral-sh/ruff-pre-commit
11+
rev: "v0.9.2"
12+
hooks:
13+
- id: ruff-format
14+
args: [--config=pyproject.toml]
15+
16+
- repo: https://github.com/pre-commit/mirrors-prettier
17+
rev: "v3.1.0"
18+
hooks:
19+
- id: prettier
20+
additional_dependencies:
21+
22+

.prettierignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# Markdown documentation files with non-standards syntax for mkdocstrings that Prettier should not auto-format
2-
docs/features/initialization.md
2+
docs/features/initialization.md

.readthedocs.yaml

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,23 @@
44
# Required
55
version: 2
66

7-
# Set the OS, Python version and other tools you might need
8-
build:
9-
os: ubuntu-24.04
10-
tools:
11-
python: "3"
12-
13-
# Build documentation in the "docs/" directory with MkDocs
14-
mkdocs:
15-
configuration: mkdocs.yml
16-
177
# Optionally build your docs in additional formats such as PDF and ePub
188
# formats:
199
# - pdf
2010
# - epub
2111
formats: all
2212

23-
# Optional but recommended, declare the Python requirements required to build your documentation
24-
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
25-
python:
26-
install:
27-
- method: pip
28-
path: .
29-
extra_requirements:
30-
- docs
13+
# Build documentation in the "docs/" directory with MkDocs
14+
mkdocs:
15+
configuration: mkdocs.yml
16+
17+
# Set the OS, Python version and other tools you might need
18+
build:
19+
os: ubuntu-24.04
20+
tools:
21+
python: "3.13"
22+
jobs:
23+
install:
24+
- pip install .
25+
- pip install dependency-groups
26+
- pip-install-dependency-groups docs

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 2.5.9 (TBD)
1+
## 2.5.9 (January 17, 2025)
22

33
- Bug Fixes
44
- Fixed 'index out of range' error when passing no arguments to an argparse-based command function.

Makefile

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Simple Makefile for use with a uv-based development environment
2+
.PHONY: install
3+
install: ## Install the virtual environment
4+
@echo "🚀 Creating virtual environment"
5+
@uv sync
6+
7+
.PHONY: check
8+
check: ## Run code quality tools.
9+
@echo "🚀 Checking lock file consistency with 'pyproject.toml'"
10+
@uv lock --locked
11+
@echo "🚀 Linting code: Running pre-commit"
12+
@uv run pre-commit run -a
13+
@echo "🚀 Static type checking: Running mypy"
14+
@uv run mypy
15+
16+
.PHONY: test
17+
test: ## Test the code with pytest.
18+
@echo "🚀 Testing code: Running pytest"
19+
@uv run python -m pytest --cov --cov-config=pyproject.toml --cov-report=xml tests
20+
@uv run python -m pytest --cov --cov-config=pyproject.toml --cov-report=xml tests_isolated
21+
22+
.PHONY: docs-test
23+
docs-test: ## Test if documentation can be built without warnings or errors
24+
@uv run mkdocs build -s
25+
26+
.PHONY: docs
27+
docs: ## Build and serve the documentation
28+
@uv run mkdocs serve
29+
30+
.PHONY: build
31+
build: clean-build ## Build wheel file
32+
@echo "🚀 Creating wheel file"
33+
@uvx --from build pyproject-build --installer uv
34+
35+
.PHONY: clean-build
36+
clean-build: ## Clean build artifacts
37+
@echo "🚀 Removing build artifacts"
38+
@uv run python -c "import shutil; import os; shutil.rmtree('dist') if os.path.exists('dist') else None"
39+
40+
.PHONY: tag
41+
tag: ## Add a Git tag and push it to origin with syntax: make tag TAG=tag_name
42+
@echo "🚀 Creating git tag: ${TAG}"
43+
@git tag -a ${TAG}
44+
@echo "🚀 Pushing tag to origin: ${TAG}"
45+
@git push origin ${TAG}
46+
47+
.PHONY: validate-tag
48+
validate-tag: ## Check to make sure that a tag exists for the current HEAD and it looks like a valid version number
49+
@echo "🚀 Validating version tag"
50+
@uv run inv validatetag
51+
52+
.PHONY: publish-test
53+
publish-test: validatetag build ## Test publishing a release to PyPI.
54+
@echo "🚀 Publishing: Dry run."
55+
@uvx twine upload --repository testpypi dist/*
56+
57+
.PHONY: publish
58+
publish: validatetag build ## Publish a release to PyPI.
59+
@echo "🚀 Publishing."
60+
@uvx twine upload --repository-url https://upload.pypi.org/legacy/ dist/*
61+
62+
.PHONY: help
63+
help:
64+
@uv run python -c "import re; \
65+
[[print(f'\033[36m{m[0]:<20}\033[0m {m[1]}') for m in re.findall(r'^([a-zA-Z_-]+):.*?## (.*)$$', open(makefile).read(), re.M)] for makefile in ('$(MAKEFILE_LIST)').strip().split()]"
66+
67+
.DEFAULT_GOAL := help

examples/scripts/nested.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
!echo "Doing a relative run script"
22
_relative_run_script script.txt
3-

examples/tmux_launch.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ if [ $# -eq 1 ]
3333
fi
3434

3535
tmux new-session -s "tmux window demo" -n "$FIRST_COMMAND" "$FIRST_COMMAND ;read" \; \
36-
new-window -n "$SECOND_COMMAND" "$SECOND_COMMAND ; read" \; previous-window
36+
new-window -n "$SECOND_COMMAND" "$SECOND_COMMAND ; read" \; previous-window

examples/tmux_split.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ fi
3131

3232
tmux new-session -s "tmux split pane demo" "$FIRST_COMMAND ; read" \; \
3333
split-window "$SECOND_COMMAND ; read" \; \
34-
select-layout even-vertical
34+
select-layout even-vertical

pyproject.toml

Lines changed: 45 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build-system]
2-
requires = ["build", "setuptools>=64", "setuptools-scm>=8"]
2+
requires = ["build>=1.2.1", "setuptools>=64", "setuptools-scm>=8"]
33
build-backend = "setuptools.build_meta"
44

55
[project]
@@ -28,58 +28,71 @@ classifiers = [
2828
"Topic :: Software Development :: Libraries :: Python Modules",
2929
]
3030
dependencies = [
31-
"gnureadline; platform_system == 'Darwin'",
32-
"pyperclip",
33-
"pyreadline3; platform_system == 'Windows'",
34-
"wcwidth",
31+
"gnureadline>=8; platform_system == 'Darwin'",
32+
"pyperclip>=1.8",
33+
"pyreadline3>=3.4; platform_system == 'Windows'",
34+
"wcwidth>=0.2.10",
3535
]
3636

37-
[project.optional-dependencies]
38-
build = ["build", "setuptools", "setuptools-scm"]
37+
[dependency-groups]
38+
build = ["build>=1.2.1", "setuptools>=64", "setuptools-scm>=8"]
3939
dev = [
40-
"black",
41-
"codecov",
42-
"griffe-typingdoc",
43-
"invoke",
44-
"mkdocs-include-markdown-plugin",
45-
"mkdocs-macros-plugin",
46-
"mkdocs-material",
47-
"mkdocstrings[python]",
48-
"mypy",
49-
"pytest",
50-
"pytest-cov",
51-
"pytest-mock",
52-
"ruff",
53-
"twine",
40+
"black>=24",
41+
"codecov>=2",
42+
"griffe-typingdoc>=0.2",
43+
"invoke>=2",
44+
"mkdocs-include-markdown-plugin>=6",
45+
"mkdocs-macros-plugin>=1",
46+
"mkdocs-material>=8",
47+
"mkdocstrings[python]>=0.26",
48+
"mypy>=1.12",
49+
"pre-commit>=2.20.0",
50+
"pytest>=7",
51+
"pytest-cov>=4",
52+
"pytest-mock>=3.14",
53+
"ruff>=0.9",
54+
"twine>=6",
5455
]
5556
docs = [
56-
"black",
57-
"griffe-typingdoc",
58-
"mkdocs-include-markdown-plugin",
59-
"mkdocs-macros-plugin",
60-
"mkdocs-material",
61-
"mkdocstrings[python]",
62-
"setuptools",
63-
"setuptools_scm",
57+
"black>=24",
58+
"griffe-typingdoc>=0.2",
59+
"mkdocs-include-markdown-plugin>=6",
60+
"mkdocs-macros-plugin>=1",
61+
"mkdocs-material>=8",
62+
"mkdocstrings[python]>=0.26",
63+
"setuptools>=64",
64+
"setuptools_scm>=8",
6465
]
65-
test = ["codecov", "coverage", "pytest", "pytest-cov", "pytest-mock"]
66-
validate = ["mypy", "ruff", "types-setuptools"]
66+
plugins = ["cmd2-ext-test"]
67+
test = [
68+
"codecov>=2",
69+
"coverage>=7",
70+
"pytest>=7",
71+
"pytest-cov>=4",
72+
"pytest-mock>=3.14",
73+
]
74+
validate = ["mypy>=1.12", "ruff>=0.9", "types-setuptools>=69"]
6775

6876
[tool.mypy]
6977
disallow_incomplete_defs = true
7078
disallow_untyped_calls = true
7179
disallow_untyped_defs = true
7280
exclude = [
81+
"^.git/",
82+
"^.venv/",
7383
"^build/", # .build directory
7484
"^docs/", # docs directory
85+
"^dist/",
7586
"^examples/", # examples directory
7687
"^plugins/*", # plugins directory
7788
"^noxfile\\.py$", # nox config file
7889
"setup\\.py$", # any files named setup.py
90+
"^site/",
7991
"^tasks\\.py$", # tasks.py invoke config file
8092
"^tests/", # tests directory
8193
"^tests_isolated/", # tests_isolated directory
8294
]
95+
files = ['.']
8396
show_column_numbers = true
8497
show_error_codes = true
8598
show_error_context = true
@@ -276,25 +289,7 @@ packages = ["cmd2"]
276289
[tool.setuptools_scm]
277290

278291
[tool.uv]
279-
dev-dependencies = [
280-
"black",
281-
"build",
282-
"cmd2-ext-test",
283-
"codecov",
284-
"griffe-typingdoc",
285-
"invoke",
286-
"mkdocs-include-markdown-plugin",
287-
"mkdocs-macros-plugin",
288-
"mkdocs-material",
289-
"mkdocstrings[python]",
290-
"mypy",
291-
"pytest",
292-
"pytest-cov",
293-
"pytest-mock",
294-
"ruff",
295-
"ruff",
296-
"twine",
297-
]
292+
default-groups = ["dev", "plugins"]
298293

299294
[tool.uv.sources]
300295
cmd2-ext-test = { path = "plugins/ext_test", editable = true }

readme_files/shout_out.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ Application Name, Description
1111

1212
Oldies but goodie,,
1313
[JSShell](https://github.com/Den1al/JSShell),An interactive multi-user web JavaScript shell.
14-
[FLASHMINGO](https://github.com/fireeye/flashmingo),Automatic analysis of SWF files based on some heuristics. Extensible via plugins.
14+
[FLASHMINGO](https://github.com/fireeye/flashmingo),Automatic analysis of SWF files based on some heuristics. Extensible via plugins.

0 commit comments

Comments
 (0)