diff --git a/.gemini/commands/templatize.toml b/.gemini/commands/templatize.toml
new file mode 100644
index 0000000..4fe2537
--- /dev/null
+++ b/.gemini/commands/templatize.toml
@@ -0,0 +1,29 @@
+description = "Templatize a new Python repo"
+prompt = """
+I want you to "templatize" a new Python repository (cloned from a GitHub repo template) by following these steps:
+
+1. Run the `templatize` script:
+ ```bash
+ ./templatize
+ ```
+ This updates placeholders like `{{REPO_NAME}}`, so everything is configured with my username, repo name, email, etc.
+2. Install the package, dev dependencies, and pre-commit hooks (see README).
+3. Use `pip list` or `uv pip list` to very which package versions were installed, and pin them in `pyproject.toml` for consistency. Do not add any new packages to `pyproject.toml` -- just pin the ones that are already listed.
+4. Delete:
+ - the "usage" section of the README on templatization
+ - the `./templatize` script
+ - the `Templatize` step in `.github/workflows/test.yaml`
+ - the "templatize" slash-command file at `.gemini/commands/templatize.toml`
+5. Update the README to give a brief description of the project. If you are unable to infer the description based on the repo, please ask me for more details.
+6. Commit and push the changes.
+ ```bash
+ # you'll need to re-activate the virtual environment here
+ source .venv/bin/activate
+ git add .
+ git commit -m "Templatize"
+ git push
+ ```
+ Type checking, linting, and formatting will run automatically on commit. You may fix any issues and recommit as needed.
+
+Do not add any new files. Only modify or delete existing files.
+"""
\ No newline at end of file
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index e1e6433..0000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-# These are supported funding model platforms
-
-github: [fkodom]
-custom: [fkodom.substack.com]
-# patreon: # Replace with a single Patreon username
diff --git a/.github/disabled-workflows/test-slow.yaml b/.github/disabled-workflows/test-slow.yaml
deleted file mode 100644
index 97a1474..0000000
--- a/.github/disabled-workflows/test-slow.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-name: Test Slow
-
-on:
- workflow_dispatch: {}
- pull_request:
- types: [opened]
-
-jobs:
- test:
- name: Test
- runs-on: ubuntu-latest
- continue-on-error: true
-
- strategy:
- matrix:
- python: ["3.10"]
-
- steps:
- - name: Checkout
- uses: actions/checkout@v2
-
- - name: Install uv
- uses: astral-sh/setup-uv@v5
- with:
- python-version: ${{ matrix.python }}
-
- - name: Templatize
- # Templatize the repo before attempting to run tests. (Tests will fail
- # otherwise, due to syntax errors.)
- # NOTE: Check if the 'templatize' script exists, so that this doesn't
- # immediately fail for repos that have already run the script.
- run: |
- if test -f "templatize"; then
- ./templatize
- fi
-
- - name: Install Package
- run: |
- uv pip install -e .[test]
-
- - name: Test
- run: |
- uv run pytest --slow --cov --cov-report term-missing --cov-fail-under 80 tests/
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 2913a60..30c4522 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
- python: ["3.10", "3.11", "3.12"]
+ python: ["3.11", "3.12"]
steps:
- name: Checkout
@@ -39,6 +39,7 @@ jobs:
- name: Test
run: |
+ uv run ruff format --check .
uv run ruff check .
+ uv run ty check .
uv run pytest --cov --cov-report term-missing --cov-fail-under 80 tests/
- uv run mypy
diff --git a/.gitignore b/.gitignore
index 13f98a2..d2d6df2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.vscode
+uv.lock
worktrees/
# Byte-compiled / optimized / DLL files
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 2255b1a..612acfc 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,16 +1,23 @@
repos:
- repo: local
hooks:
- - id: black
- name: black
+ - id: ruff-format
+ name: ruff format
stages: [pre-commit]
language: system
- entry: black
+ entry: ruff format
types: [python]
- - id: ruff
+ - id: ruff-check
name: ruff check
stages: [pre-commit]
language: system
entry: ruff check
types: [python]
+
+ - id: ty-check
+ name: ty check
+ stages: [pre-commit]
+ language: system
+ entry: ty check
+ types: [python]
diff --git a/README.md b/README.md
index 95a4bac..1daa861 100644
--- a/README.md
+++ b/README.md
@@ -1,34 +1,28 @@
# {{REPO_NAME}}
-A simple template for Python projects, with CI/CD configured through GitHub Actions. Compatible with any virtual environment manager (e.g. `uv`, `venv`, `pyenv`, `poetry`, `conda`).
+A simple template for Python projects, with CI/CD configured through GitHub Actions.
## Usage
1. Create a new repository, using this one as a template.
-2. Run the `templatize` script:
+2. Install and open [Gemini CLI](https://github.com/google-gemini/gemini-cli), then run the `/templatize` command:
```bash
- ./templatize
+ gemini run /templatize
```
- This updates placeholders like `{{REPO_NAME}}`, so everything is configured with your username, repo name, email, etc.
-3. Commit and push the changes.
- ```bash
- git add .
- git commit -m "Templatize"
- git push
- ```
-4. (Probably) delete this section of the README.
## Install
-```bash
-pip install "{{REPO_NAME}} @ git+ssh://git@github.com/{{REPO_OWNER}}/{{REPO_NAME}}.git"
+> **Note:** For simplicity, I assume you are using [uv](https://docs.astral.sh/uv/getting-started/installation/), but this project is compatible with any virtual environment or package manager (`pip`, `venv`, `poetry`, `pipenv`, `conda`).
-# Install all dev dependencies (tests etc.)
-pip install "{{REPO_NAME}}[test] @ git+ssh://git@github.com/{{REPO_OWNER}}/{{REPO_NAME}}.git"
+```bash
+# Create and activate a new virtual environment
+uv venv --python 3.12
+source .venv/bin/activate
-# Setup pre-commit hooks
+# Install development dependencies and pre-commit hoooks
+uv sync --all-extras
pre-commit install
```
@@ -37,11 +31,9 @@ pre-commit install
| Tool | Description | Runs on |
| --- | --- | --- |
-| [black](https://github.com/psf/black) | Code formatter | - `git commit` (through `pre-commit`)
- `git push`
- pull requests |
| [ruff](https://github.com/astral-sh/ruff) | Code linter | - `git commit` (through `pre-commit`)
- `git push`
- pull requests |
+| [ty](https://docs.astral.sh/ty/) | Static type checker | - `git commit`
- pull requests |
| [pytest](https://github.com/pytest-dev/pytest) | Unit testing framework | - `git push`
- pull requests |
-| [mypy](https://github.com/python/mypy) | Static type checker | - `git push`
- pull requests |
-| [pre-commit](https://github.com/pre-commit/pre-commit) | Pre-commit hooks | - `git commit` |
| [twine](https://github.com/pypa/twine) $\dagger$ | PyPI package uploader | - New release (`git tag`) |
> $\dagger$ Requires enabling the `publish.yaml` workflow. To activate, move the file from `.github/disabled-workflows/publish.yaml.disabled` to `.github/workflows/publish.yaml`, and set a valid PyPI token as `PYPI_API_TOKEN` in the repo secrets.
diff --git a/pyproject.toml b/pyproject.toml
index c36ae85..ef44f6e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -10,7 +10,7 @@ description = "{{REPO_NAME}}"
license = {text = "MIT"}
dynamic = ["version", "readme"] # NOTE: Must be in sync with [tool.setuptools.dynamic] below
dependencies = []
-requires-python = ">=3.8"
+requires-python = ">=3.11"
classifiers = ["Programming Language :: Python :: 3"]
[tool.setuptools.dynamic]
@@ -24,12 +24,12 @@ exclude = ["tests"]
# extra packages (e.g. pip install .[test])
[project.optional-dependencies]
test = [
- "black",
"mypy",
"pre-commit",
"pytest",
"pytest-cov",
"ruff",
+ "ty",
]
diff --git a/tests/conftest.py b/tests/conftest.py
index cf3859b..e69de29 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,21 +0,0 @@
-import pytest
-
-
-def pytest_addoption(parser):
- parser.addoption("--slow", action="store_true")
-
-
-def pytest_configure(config):
- config.addinivalue_line("markers", "slow: slow to run")
-
-
-def pytest_collection_modifyitems(config, items):
- run_slow = config.getoption("--slow")
- skip_fast = pytest.mark.skip(reason="remove --slow option to run")
- skip_slow = pytest.mark.skip(reason="need --slow option to run")
-
- for item in items:
- if ("slow" in item.keywords) and (not run_slow):
- item.add_marker(skip_slow)
- if ("slow" not in item.keywords) and (run_slow):
- item.add_marker(skip_fast)