diff --git a/.all-contributorsrc b/.all-contributorsrc
index 3537d71b..c058975f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -84,7 +84,7 @@
"login": "sfmig",
"name": "sfmig",
"avatar_url": "https://avatars.githubusercontent.com/u/33267254?v=4",
- "profile": "https://sfmig.github.io/",
+ "profile": "https://github.com/sfmig",
"contributions": [
"bug",
"code",
@@ -240,6 +240,15 @@
"code",
"question"
]
+ },
+ {
+ "login": "llapira",
+ "name": "llapira",
+ "avatar_url": "https://avatars.githubusercontent.com/u/48060852?v=4",
+ "profile": "https://github.com/LLapira",
+ "contributions": [
+ "bug"
+ ]
}
]
}
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 31c8ab9c..098b8b9e 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -1,7 +1,6 @@
---
name: Bug Report
description: Create a Report to Help us Improve
-title: "A one-line description of your problem"
labels:
- bug
body:
diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml
index 7510d2c9..582c191c 100644
--- a/.github/ISSUE_TEMPLATE/documentation.yml
+++ b/.github/ISSUE_TEMPLATE/documentation.yml
@@ -1,7 +1,6 @@
---
name: Documentation
description: How Can We Improve the Documentation
-title: "What needs improving in the documentation?"
labels:
- documentation
body:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 50e76847..de0b5193 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -1,7 +1,6 @@
---
name: Feature Request
description: Suggest a Way to Improve This Project
-title: "Feature suggestion: What should be added?"
labels:
- enhancement
body:
@@ -18,8 +17,6 @@ body:
attributes:
label: Describe the Solution You'd Like
description: A clear and concise description of what you want to happen.
- validations:
- required: true
- id: alternatives
type: textarea
attributes:
diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml
index 380e047b..30128249 100644
--- a/.github/ISSUE_TEMPLATE/question.yml
+++ b/.github/ISSUE_TEMPLATE/question.yml
@@ -1,7 +1,6 @@
---
name: Question
description: General Questions About Using the Cookiecutter Template
-title: "The title of your question."
labels:
- question
body:
diff --git a/.github/ISSUE_TEMPLATE/task.yml b/.github/ISSUE_TEMPLATE/task.yml
index 4eb49b0c..9bc69662 100644
--- a/.github/ISSUE_TEMPLATE/task.yml
+++ b/.github/ISSUE_TEMPLATE/task.yml
@@ -1,7 +1,6 @@
---
name: Task
description: A Task to be Completed
-title: "Task: What needs to be done?"
labels:
- task
body:
diff --git a/.github/ISSUE_TEMPLATE/website.yml b/.github/ISSUE_TEMPLATE/website.yml
index 93a95624..a6db3b64 100644
--- a/.github/ISSUE_TEMPLATE/website.yml
+++ b/.github/ISSUE_TEMPLATE/website.yml
@@ -1,7 +1,6 @@
---
name: Website
description: How Can We Improve the Website
-title: "Website Improvement:"
labels:
- website
body:
diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml
index 488e69e9..d9334c4a 100644
--- a/.github/workflows/links.yml
+++ b/.github/workflows/links.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
+ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Link Checker
id: lychee
@@ -23,11 +23,14 @@ jobs:
with:
# Exclude the image.sc forum (which works) but returns 403 from
# github runners and exclude relative links to other pages. Ignore
- # the whole of the project slug README since the links are
+ # gnu.org and fsf.org because they're often down but are still the right
+ # websites to link to!
+ #
+ # Ignore the whole of the project slug README since the links are
# necessarily not real links - i.e. demos and to be filled by
# cookiecutter values.
args:
- "--verbose --exclude https://forum.image.sc/ --exclude docs/pages
+ "--verbose --exclude https://forum.image.sc/ --exclude http://www.gnu.org --exclude http://fsf.org --exclude docs/pages
--exclude-path '{{cookiecutter.project_slug}}/README.md' -- ."
fail: true
jobSummary: true
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index f1ea2550..3f4839cb 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
+ uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Cache pre-commit
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
@@ -21,7 +21,7 @@ jobs:
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Set up python
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
+ uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5
with:
python-version: "3.x"
@@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
+ uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Cache pre-commit
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
@@ -44,7 +44,7 @@ jobs:
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Set up python
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
+ uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5
with:
python-version: "3.x"
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 9fd3a81b..dbc015a0 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -33,11 +33,11 @@ jobs:
BUNDLE_GEMFILE: ${{ github.workspace }}/docs/Gemfile
steps:
- name: Checkout
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
+ uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
- ruby-version: "3.1" # Not needed with a .ruby-version file
+ ruby-version: "3.3" # Not needed with a .ruby-version file
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
cache-version: 0 # Increment this number if you need to re-download cached gems
- name: Setup Pages
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c2a5a587..95f1ca22 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,13 +18,13 @@ jobs:
- ubuntu-latest
- windows-latest
python-version:
- - "3.10"
- "3.11"
- "3.12"
+ - "3.13"
steps:
- name: Checkout source
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
+ uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Cache tox
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
@@ -33,16 +33,16 @@ jobs:
key: test-${{ hashFiles('pyproject.toml') }}
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
+ uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml
- name: Install dependencies
- run: python -m pip install tox tox-gh-actions
+ run: python -m pip install tox tox-gh
- name: Run tests
- run: tox
+ run: tox run
env:
- OS: ${{ matrix.os }}
+ TOX_GH_MAJOR_MINOR: ${{ matrix.python-version }}
diff --git a/.markdownlint.yaml b/.markdownlint.yaml
new file mode 100644
index 00000000..02907b2b
--- /dev/null
+++ b/.markdownlint.yaml
@@ -0,0 +1,2 @@
+---
+MD013: false
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3d6e47b8..ba5792d5 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,7 +1,7 @@
exclude: ^{{cookiecutter.project_slug}}/
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.4.7
+ rev: v0.6.8
hooks:
- id: ruff
args:
@@ -9,6 +9,12 @@ repos:
- id: ruff-format
args:
- --config=pyproject.toml
+ - repo: https://github.com/igorshubovych/markdownlint-cli
+ rev: v0.42.0
+ hooks:
+ - id: markdownlint-fix
+ args:
+ - --dot
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
hooks:
@@ -18,7 +24,7 @@ repos:
hooks:
- id: toml-sort-fix
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.10.0
+ rev: v1.11.2
hooks:
- id: mypy
args:
@@ -43,7 +49,7 @@ repos:
- --fix=lf
- id: trailing-whitespace
- repo: https://github.com/python-jsonschema/check-jsonschema
- rev: 0.28.4
+ rev: 0.29.3
hooks:
# Schemas taken from https://www.schemastore.org/json/
- id: check-jsonschema
diff --git a/.renovaterc.json5 b/.renovaterc.json5
index ba51ac7b..879a504f 100644
--- a/.renovaterc.json5
+++ b/.renovaterc.json5
@@ -2,7 +2,7 @@
$schema: "https://docs.renovatebot.com/renovate-schema.json",
extends: [
"github>UCL-ARC/.github//renovate/default-config.json",
+ ":assignAndReview(team:collaborations-python-tooling)",
":maintainLockFilesMonthly",
],
- reviewers: ["paddyroddy", "samcunliffe"],
}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6f8f2f64..3bc57e5f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,5 @@
+# Contributing Guide
+
This template and our [recommendation pages][website] were made by [research
software engineers] at [UCL's Centre for Advanced Research Computing][UCL ARC].
We made it with research software projects in mind, but whoever you are, we hope
diff --git a/README.md b/README.md
index 4b5aa88f..b4b9b988 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
+
UCL ARC Python Recommendations
+
This repository collects the [UCL ARC] recommendations for a research software
project in Python. It contains a template for new Python packages and a
@@ -37,7 +39,7 @@ Python packages with our recommended tooling set up and ready to go.
Sam Cunliffe π€ π π» π π π π π¬ π π’ β οΈ |
David Stansby π€ π π» π π π π π β οΈ |
Matt Graham π π» π π π¨ π π π’ β οΈ |
- sfmig π π» π π β οΈ |
+ sfmig π π» π π β οΈ |
Paul Smith π π» π π π¬ π β οΈ |
Renovate Bot π§ |
@@ -56,6 +58,7 @@ Python packages with our recommended tooling set up and ready to go.
Katie Buntic π |
Robert Vickerstaff π |
David PΓ©rez-SuΓ‘rez π» π¬ |
+ llapira π |
@@ -67,79 +70,91 @@ Python packages with our recommended tooling set up and ready to go.
## Using this template
-1. Install [cookiecutter] in a Conda or `venv` environment (commented lines for
- Conda example).
-
- ```
- # conda create --channel conda-forge --name new-env-name
- # conda activate new-env-name
- # conda install pip
- pip install cookiecutter
- ```
-
-2. Run cookiecutter in the desired directory
- ```
- cookiecutter gh:ucl-arc/python-tooling
- ```
- If you have this repo locally (this may be the case if you are developing),
- you can run the following:
- ```
- cookiecutter /path/to/your/checkout/of/python-tooling
- ```
-3. A series of questions will pop up to configure the project. Type the answer
- or hit return to use the default option (shown in square brackets).
-
- Note that these project variables are defined in the `cookiecutter.json`
- file.
-
-4. This will create a specific directory structure.
-
- For example, for a project with the following variables:
-
- ```
- project_name [Python Template]: PROJECT_NAME
- project_slug [python-template]: PROJECT_SLUG
- ```
-
- we will get a project folder named `PROJECT_SLUG`, structured like this:
-
- ```
- PROJECT_SLUG
- βββ ...
- βββ README.md
- βββ pyproject.toml
- βββ src
- β βββ PROJECT_SLUG
- β βββ PROJECT_SLUG.py
- βββ tests
- βββ test_dummy.py
- ```
-
- And the `PROJECT_NAME` will appear in the README.md as the human-readable
- name of the project.
-
- ```
- cat PROJECT_SLUG/README.md
- # PROJECT_NAME
- ...
- ```
-
-5. To work on your project, initialise a git repository and _install_ it in
- editable mode.
- ```
- cd PROJECT_SLUG
- git init
- python -m pip install -e ".[dev]"
- ```
-6. Build your package
- ```
- python -m build
- ```
+Some quick instructions for using our template are below.
+We also have a detailed [tutorial](tutorial.md) that has been given in a couple of workshops geared towards researchers at UCL.
+The tutorial goes into much more pedagogical detail, it both describes using the template to create a package
+and how to use the newly created package with some of the tools included.
+
+1. Install [cookiecutter] in a Conda or `venv` environment (commented lines for
+ Conda example).
+
+ ```sh
+ # conda create --channel conda-forge --name new-env-name
+ # conda activate new-env-name
+ # conda install pip
+ pip install cookiecutter
+ ```
+
+2. Run cookiecutter in the desired directory
+
+ ```sh
+ cookiecutter gh:ucl-arc/python-tooling
+ ```
+
+ If you have this repo locally (this may be the case if you are developing),
+ you can run the following:
+
+ ```sh
+ cookiecutter /path/to/your/checkout/of/python-tooling
+ ```
+
+3. A series of questions will pop up to configure the project. Type the answer
+ or hit return to use the default option (shown in parenthesis).
+
+ Note that these project variables are defined in the `cookiecutter.json`
+ file.
+
+4. This will create a specific directory structure.
+
+ For example, for a project with the following variables:
+
+ ```yaml
+ project_name [Python Template]: PROJECT_NAME
+ project_slug [python-template]: PROJECT_SLUG
+ package_name [python_template]: PACKAGE_NAME
+ ```
+
+ we will get a project folder named `PROJECT_SLUG`, structured like this:
+
+ ```sh
+ PROJECT_SLUG
+ βββ ...
+ βββ README.md
+ βββ pyproject.toml
+ βββ src
+ β βββ PACKAGE_NAME
+ β βββ __init__.py
+ βββ tests
+ βββ test_dummy.py
+ ```
+
+ And the `PROJECT_NAME` will appear in the README.md as the human-readable
+ name of the project.
+
+ ```sh
+ cat PROJECT_SLUG/README.md
+ # PROJECT_NAME
+ ...
+ ```
+
+5. To work on your project, initialise a Git repository and _install_ it in
+ editable mode.
+
+ ```sh
+ cd PROJECT_SLUG
+ git init
+ python -m pip install -e ".[dev]"
+ ```
+
+6. Build your package
+
+ ```sh
+ python -m build
+ ```
## Notes for developers
-
-Click to expand...
+Click to expand...
First, clone repository
@@ -150,7 +165,7 @@ First, clone repository
- Clone the repository by typing (or copying) the following line in a terminal
at your selected path in your machine:
-```
+```sh
git clone git@github.com:UCL-ARC/python-tooling.git
cd python-tooling
```
@@ -159,7 +174,7 @@ cd python-tooling
- To create and remove your virtual environment
- ```
+ ```sh
conda create -n ptoolingVE pip -c conda-forge
conda activate ptoolingVE
conda deactivate ptoolingVE
@@ -169,7 +184,7 @@ cd python-tooling
- To run template in the same path of this repo. We do a test cookiecut of a
dummy package and install it to ensure the template setup works.
- ```
+ ```sh
cookiecutter .
cd python-template
git init
@@ -178,13 +193,13 @@ cd python-tooling
- To run cookiecutter using a specific branch of the template:
- ```
+ ```sh
cookiecutter https://github.com/UCL-ARC/python-tooling --checkout
```
- To run the tests locally:
- ```
+ ```sh
pytest -s
```
@@ -196,13 +211,13 @@ sub-directory, and are written in markdown.
To build the webpage locally (for testing)
-1. [Install jekyll](https://jekyllrb.com/docs/installation)
-2. Run `bundle install` from the `docs/` directory of this repository to
- install dependencies.
-3. Run `bundle exec jekyll serve` from the root directory of this repository.
- This should fire up a local web server and tell you its address. By default
- the server will automatically refresh the HTML pages if any changes are made
- to the markdown sources.
+1. [Install jekyll](https://jekyllrb.com/docs/installation)
+2. Run `bundle install` from the `docs/` directory of this repository to
+ install dependencies.
+3. Run `bundle exec jekyll serve` from the root directory of this repository.
+ This should fire up a local web server and tell you its address. By default
+ the server will automatically refresh the HTML pages if any changes are made
+ to the markdown sources.
See the [jekyll docs](https://jekyllrb.com/docs) for more info.
diff --git a/cookiecutter.json b/cookiecutter.json
index d36c2d33..61a867f5 100644
--- a/cookiecutter.json
+++ b/cookiecutter.json
@@ -1,24 +1,24 @@
{
"author_given_names": "Eva Lu",
"author_family_names": "Ator",
- "author_email": "eva.lu.ator@ucl.ac.uk",
+ "author_email": "{{'.'.join(cookiecutter.author_given_names.lower().split() + cookiecutter.author_family_names.lower().split())}}@ucl.ac.uk",
"project_name": "Python Template",
"project_slug": "{{cookiecutter.project_name.lower().replace(' ', '-').replace('_', '-')}}",
"package_name": "{{cookiecutter.project_slug.replace('-', '_')}}",
"project_short_description": "A cookiecutter package with UCL ARC recommendations.",
"initialise_git_repository": true,
- "deploy_docs_to_github_pages": false,
+ "deploy_docs_to_github_pages": true,
"github_owner": "{{cookiecutter.author_given_names.lower().replace(' ', '-')}}-{{cookiecutter.author_family_names.lower().replace(' ', '-')}}",
- "min_python_version": ["3.10", "3.11", "3.12"],
- "max_python_version": ["3.12", "3.11", "3.10"],
+ "min_python_version": ["3.11", "3.12", "3.13"],
+ "max_python_version": ["3.13", "3.12", "3.11"],
"license": ["MIT", "BSD-3", "GPL-3.0"],
- "funder": "JBFC: The Joe Bloggs Funding Council",
+ "funder": "",
"__repo_name": "{{cookiecutter.github_owner}}/{{cookiecutter.project_slug}}",
"__repo_url": "https://github.com/{{cookiecutter.__repo_name}}",
"__prompts__": {
"author_given_names": "Given name(s) of package author",
"author_family_names": "Family name(s) of package author",
- "author_email": "Email address for package author - will be part of package metadata.",
+ "author_email": "Email address for package author - will be part of package metadata",
"project_name": "Name of project - may contain spaces",
"project_slug": "'Slugified' project name for use in URLs - dash-case recommended",
"package_name": "Name for Python package - snake_case recommended",
@@ -29,6 +29,6 @@
"min_python_version": "Minimum Python version supported by package",
"max_python_version": "Maximum Python version supported by package",
"license": "Which open-source license to release package under",
- "funder": "Organisation(s) to acknowledge for funding of project"
+ "funder": "Organisation(s) to acknowledge for funding of project (optional)"
}
}
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
index 11c417f2..1f5085f4 100644
--- a/docs/Gemfile.lock
+++ b/docs/Gemfile.lock
@@ -1,32 +1,49 @@
GEM
remote: https://rubygems.org/
specs:
- addressable (2.8.6)
- public_suffix (>= 2.0.2, < 6.0)
+ addressable (2.8.7)
+ public_suffix (>= 2.0.2, < 7.0)
+ bigdecimal (3.1.8)
colorator (1.1.0)
- concurrent-ruby (1.2.3)
+ concurrent-ruby (1.3.4)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
eventmachine (1.2.7)
- ffi (1.16.3)
+ ffi (1.17.0)
+ ffi (1.17.0-aarch64-linux-gnu)
+ ffi (1.17.0-aarch64-linux-musl)
+ ffi (1.17.0-arm-linux-gnu)
+ ffi (1.17.0-arm-linux-musl)
+ ffi (1.17.0-arm64-darwin)
+ ffi (1.17.0-x86-linux-gnu)
+ ffi (1.17.0-x86-linux-musl)
+ ffi (1.17.0-x86_64-darwin)
+ ffi (1.17.0-x86_64-linux-gnu)
+ ffi (1.17.0-x86_64-linux-musl)
forwardable-extended (2.6.0)
- google-protobuf (4.26.1)
+ google-protobuf (4.28.2)
+ bigdecimal
rake (>= 13)
- google-protobuf (4.26.1-aarch64-linux)
+ google-protobuf (4.28.2-aarch64-linux)
+ bigdecimal
rake (>= 13)
- google-protobuf (4.26.1-arm64-darwin)
+ google-protobuf (4.28.2-arm64-darwin)
+ bigdecimal
rake (>= 13)
- google-protobuf (4.26.1-x86-linux)
+ google-protobuf (4.28.2-x86-linux)
+ bigdecimal
rake (>= 13)
- google-protobuf (4.26.1-x86_64-darwin)
+ google-protobuf (4.28.2-x86_64-darwin)
+ bigdecimal
rake (>= 13)
- google-protobuf (4.26.1-x86_64-linux)
+ google-protobuf (4.28.2-x86_64-linux)
+ bigdecimal
rake (>= 13)
http_parser.rb (0.8.0)
- i18n (1.14.4)
+ i18n (1.14.6)
concurrent-ruby (~> 1.0)
- jekyll (4.3.3)
+ jekyll (4.3.4)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
@@ -50,7 +67,7 @@ GEM
jekyll (>= 3.8, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
- just-the-docs (0.8.2)
+ just-the-docs (0.10.0)
jekyll (>= 3.8.5)
jekyll-include-cache
jekyll-seo-tag (>= 2.0)
@@ -66,63 +83,63 @@ GEM
mercenary (0.4.0)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
- public_suffix (5.0.5)
+ public_suffix (6.0.1)
rake (13.2.1)
rb-fsevent (0.11.2)
- rb-inotify (0.10.1)
+ rb-inotify (0.11.1)
ffi (~> 1.0)
- rexml (3.2.6)
- rouge (4.2.1)
+ rexml (3.3.8)
+ rouge (4.4.0)
safe_yaml (1.0.5)
- sass-embedded (1.76.0)
- google-protobuf (>= 3.25, < 5.0)
- rake (>= 13.0.0)
- sass-embedded (1.76.0-aarch64-linux-android)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-aarch64-linux-gnu)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-aarch64-linux-musl)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-aarch64-mingw-ucrt)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-arm-linux-androideabi)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-arm-linux-gnueabihf)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-arm-linux-musleabihf)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-arm64-darwin)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-riscv64-linux-android)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-riscv64-linux-gnu)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-riscv64-linux-musl)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86-cygwin)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86-linux-android)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86-linux-gnu)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86-linux-musl)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86-mingw-ucrt)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86_64-cygwin)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86_64-darwin)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86_64-linux-android)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86_64-linux-gnu)
- google-protobuf (>= 3.25, < 5.0)
- sass-embedded (1.76.0-x86_64-linux-musl)
- google-protobuf (>= 3.25, < 5.0)
+ sass-embedded (1.79.4)
+ google-protobuf (~> 4.27)
+ rake (>= 13)
+ sass-embedded (1.79.4-aarch64-linux-android)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-aarch64-linux-gnu)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-aarch64-linux-musl)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-aarch64-mingw-ucrt)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-arm-linux-androideabi)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-arm-linux-gnueabihf)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-arm-linux-musleabihf)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-arm64-darwin)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-riscv64-linux-android)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-riscv64-linux-gnu)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-riscv64-linux-musl)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86-cygwin)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86-linux-android)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86-linux-gnu)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86-linux-musl)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86-mingw-ucrt)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86_64-cygwin)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86_64-darwin)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86_64-linux-android)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86_64-linux-gnu)
+ google-protobuf (~> 4.27)
+ sass-embedded (1.79.4-x86_64-linux-musl)
+ google-protobuf (~> 4.27)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
- unicode-display_width (2.5.0)
- webrick (1.8.1)
+ unicode-display_width (2.6.0)
+ webrick (1.8.2)
PLATFORMS
aarch64-linux
@@ -131,7 +148,9 @@ PLATFORMS
aarch64-linux-musl
aarch64-mingw-ucrt
arm-linux-androideabi
+ arm-linux-gnu
arm-linux-gnueabihf
+ arm-linux-musl
arm-linux-musleabihf
arm64-darwin
riscv64-linux-android
@@ -156,4 +175,4 @@ DEPENDENCIES
just-the-docs (~> 0)
BUNDLED WITH
- 2.5.9
+ 2.5.14
diff --git a/docs/index.md b/docs/index.md
index cd046fcd..0e9fca2e 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -10,10 +10,10 @@ at the [Centre for Advanced Research Computing](https://www.ucl.ac.uk/arc/)
These pages started as a forum to share knowledge across projects and have now
grown into a list of our default recommendations. Each page contains a table of
-packages, tools, or services that are useful when building a Python package.
+packages, tools, or services that are useful when working on a Python project.
Each entry has
-- a link to the package or service,
+- a link to the package, tool, or service,
- a short summary of what it does,
- and traffic light!
@@ -25,7 +25,7 @@ they recommend. For example, the [napari](https://napari.org/) community have a
template and the
[SciKit-Surgery](https://scikit-surgery.github.io/scikit-surgery/) community
have [PythonTemplate](https://github.com/SciKit-Surgery/PythonTemplate), both
-used to create new Python-based libraries. Using common tooling and structure
+used to create new Python-based packages. Using common tooling and structure
makes it easier for others in the community to contribute to your package. Once
_you_ get used to the structure makes it easier for you to contribute back to
other packages.
diff --git a/docs/pages/benchmarking-profiling.md b/docs/pages/benchmarking-profiling.md
index 93d9f7c3..dd2521ee 100644
--- a/docs/pages/benchmarking-profiling.md
+++ b/docs/pages/benchmarking-profiling.md
@@ -3,29 +3,29 @@ title: Benchmarking and profiling
layout: default
---
-# Benchmarking
+## Benchmarking
| Name | Short description | π¦ |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
| [asv](https://asv.readthedocs.io/en/stable/) | A tool for benchmarking Python packages over their lifetime. Allows you to write benchmarks and then run them against every commit in the repository, to identify where performance increased or decreased. Comparative benchmarks can also be run, which can be useful for [running them in CI using GitHub runners](https://labs.quansight.org/blog/2021/08/github-actions-benchmarks). | π’ |
-# Profiling
+## Profiling
-## Time
+### Time
| Name | Short description | π¦ |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
| [pyinstrument](https://pyinstrument.readthedocs.io/en/stable) | Python profiler. Tells you how long individual lines of code take to run, so you can focus on the slowest part of your program to speed it up. | π’ |
| [line_profiler](https://pypi.org/project/line-profiler/) | A tool for line-by-line profiling of functions. | π |
-## Memory
+### Memory
| Name | Short description | π¦ |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
| [memray](https://bloomberg.github.io/memray/) | Tracks and reports memory allocations, both in Python code and in compiled extension modules. It also has a [plugin](https://pytest-memray.readthedocs.io/en/latest/) for easy integration with pytest. Only works on Linux and macOS. | π |
| [memory_profiler](https://pypi.org/project/memory-profiler/) | No longer actively maintained. A Python module for monitoring memory consumption of a process alongside line-by-line analysis of memory consumption. Might be a useful alternative to memray if you need to do memory profiling on Windows. | π |
-## General/other tools
+### General/other tools
| Name | Short description | π¦ |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------- | :-: |
diff --git a/docs/pages/ci.md b/docs/pages/ci.md
index d11834d5..68c8d0dd 100644
--- a/docs/pages/ci.md
+++ b/docs/pages/ci.md
@@ -3,7 +3,7 @@ title: Continuous integration
layout: default
---
-# Continuous integration (CI)
+## Continuous integration (CI)
| Name | Short description | π¦ |
| ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
@@ -13,12 +13,11 @@ layout: default
| [Travis CI](https://docs.travis-ci.com/) | Continuous integration and continuous delivery platform. | π |
| [pre-commit.ci](https://pre-commit.ci/) | A bot that adds a pre-commit job to your GitHub Actions CI, and can automatically fix most trivial linting failures. Free for open-source projects. | π’ |
-
- π’ explanation
+ π’ explanation
We have many projects using GitHub CI and, it has good integration with GitHub itself, and is free for public repositories (with limited free monthly minutes for private repositories).
-# Coverage monitoring
+## Coverage monitoring
These services report and track test code coverage over time. They render the
code with highlighting to show which lines are not executed by tests. See
@@ -30,7 +29,6 @@ during tests.
| [Codecov](https://docs.codecov.com/docs) | Hosted service to report code coverage metrics. Occasionally slow to update after a report is updated, can be configured to add extra CI checks. This service is probably more widely used and is [free for both open-source and private projects](https://about.codecov.io/pricing/). | π’ |
| [Coveralls](https://docs.coveralls.io/) | Hosted service to report code coverage metrics. Very similar to codecov and we don't strongly recommend one over the other. This service is only [free for open-source projects](https://coveralls.io/pricing). | π’ |
-
- π’ explanation
+ π’ explanation
Both services are similar, so both π’.
diff --git a/docs/pages/community.md b/docs/pages/community.md
index 85716264..01cb7292 100644
--- a/docs/pages/community.md
+++ b/docs/pages/community.md
@@ -3,7 +3,7 @@ title: Community
layout: default
---
-# Community building
+## Community building
There are many platforms to build a community for users and developers. We
recommend you choose one, and not more than one. If you are creating a new
diff --git a/docs/pages/docs.md b/docs/pages/docs.md
index 87636315..7315af7a 100644
--- a/docs/pages/docs.md
+++ b/docs/pages/docs.md
@@ -3,7 +3,7 @@ title: Documentation
layout: default
---
-# Documentation
+## Documentation
With Python, as with many other languages, it's very common to automatically
create a web page with documentation. This can include reference for the API
@@ -23,7 +23,7 @@ If you're using GitHub, one option is to host your docs on [GitHub pages].
[our template]: https://github.com/UCL-ARC/python-tooling?tab=readme-ov-file#using-this-template
[template-docs-dot-yaml]: https://github.com/UCL-ARC/python-tooling/blob/main/%7B%7Bcookiecutter.project_slug%7D%7D/.github/workflows/docs.yml
-## Documentation build tools
+### Documentation build tools
| Name | Short description | π¦ |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
@@ -32,8 +32,7 @@ If you're using GitHub, one option is to host your docs on [GitHub pages].
| [gitbook] | General documentation builder; integrates with GitHub. | π |
| [pdoc] | Auto-generates API documentation from docstrings, beginner friendly but with less of a plugin ecosystem than others. | π |
-
-More details about Sphinx
+More details about Sphinx
We marginally recommend [MkDocs] over [Sphinx] due to it's ease of use,
preference for Markdown, and more support for a variety of docstring styles.
@@ -44,7 +43,7 @@ a [Sphinx extension](#sphinx-extensions) that does not have an equivalent
[MkDocs plugin](https://github.com/mkdocs/catalog), or if you are part of a
community that heavily uses [Sphinx] then we recommend you use that instead.
-### See also
+#### See also
- Our internal discussions about which to recommend
([#16](https://github.com/UCL-ARC/python-tooling/issues/16) and
@@ -60,13 +59,13 @@ community that heavily uses [Sphinx] then we recommend you use that instead.
[gitbook]: https://www.gitbook.com/
[pdoc]: https://pdoc.dev/
-## MkDocs plugins
+### MkDocs plugins
| Name | Short description | π¦ |
| ------------------------------------------------------------- | -------------------------------------------- | :-: |
| [mkdocstrings-python](https://mkdocstrings.github.io/python/) | Automatically generates API reference pages. | π’ |
-## Sphinx extensions
+### Sphinx extensions
| Name | Short description | π¦ |
| -------------------------------------------------------------------- | ---------------------------------------------------------------- | :-: |
diff --git a/docs/pages/bindings.md b/docs/pages/libraries/bindings.md
similarity index 95%
rename from docs/pages/bindings.md
rename to docs/pages/libraries/bindings.md
index d08467c4..05839831 100644
--- a/docs/pages/bindings.md
+++ b/docs/pages/libraries/bindings.md
@@ -1,11 +1,12 @@
---
title: Bindings
layout: default
+parent: Recommended libraries
---
-# Bindings
+## Bindings
-## C/C++
+### C/C++
| Name | Short description | π¦ |
| --------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | :-: |
@@ -13,13 +14,13 @@ layout: default
| [ctypes](https://docs.python.org/3.8/library/ctypes.html) | Native python method for calling functions in shared C libraries | π |
| [pybind11](https://github.com/pybind/pybind11) | Bindings to C++ with a steep learning curve | π |
-## Rust
+### Rust
| Name | Short description | π¦ |
| ------------------------------------ | ---------------------------------------------------------------------------------------------- | :-: |
| [pyO3](https://github.com/PyO3/pyo3) | Straightforward bindings to rust with support for [packaging](https://github.com/PyO3/maturin) | π’ |
-## Fortran
+### Fortran
| Name | Short description | π¦ |
| ---------------------------------------------------------------- | -------------------------------------- | :-: |
diff --git a/docs/pages/utilities.md b/docs/pages/libraries/clis.md
similarity index 56%
rename from docs/pages/utilities.md
rename to docs/pages/libraries/clis.md
index eb2b9bd4..bff605e0 100644
--- a/docs/pages/utilities.md
+++ b/docs/pages/libraries/clis.md
@@ -1,15 +1,10 @@
---
-title: Utility libraries
+title: Command-line interfaces
layout: default
+parent: Recommended libraries
---
-# Utility libraries
-
-Useful packages for _utility_ functionality, normally we highlight these if
-we've found a library that we prefer to Python's builtin. You probably don't
-want to write these yourself but might need logging or a command-line interface.
-
-## Command-line interface
+## Command-line interfaces
| Name | Short description | π¦ |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------ | :-: |
@@ -18,14 +13,7 @@ want to write these yourself but might need logging or a command-line interface.
| [argparse](https://docs.python.org/3/library/argparse.html) | Python's builtin CLI system uses object configuration. | π |
| [optparse](https://docs.python.org/3/library/optparse.html) | A now-deprecated CLI system built into Python. | π΄ |
-## Logging
-
-| Name | Short description | π¦ |
-| --------------------------------------------------------- | -------------------------------------------------------------------- | :-: |
-| [loguru](https://loguru.readthedocs.io/) | Simple and user-friendly with many nice features enabled by default. | π’ |
-| [logging](https://docs.python.org/3/library/logging.html) | Python's builtin logging framework. Needs some configuration. | π |
-
-## User interface
+### Other useful tools for CLIs
| Name | Short description | π¦ |
| ------------------------------- | ----------------------- | :-: |
diff --git a/docs/pages/libraries/guis.md b/docs/pages/libraries/guis.md
new file mode 100644
index 00000000..d68b8049
--- /dev/null
+++ b/docs/pages/libraries/guis.md
@@ -0,0 +1,22 @@
+---
+title: Graphical user interface toolkits
+layout: default
+parent: Recommended libraries
+---
+
+## Graphical user interface toolkits
+
+| Name | Short description | π¦ |
+| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
+| [QtPy] | A Python interface to the [Qt] GUI system. Recommended if you need to be binding-independent. | π’ |
+| [PySlide] | A Python binding to the [Qt] GUI system. Recommended if you're developing an app that you'll build and distribute as an executable. In which case you don't need to be binding-independent. | π’ |
+| [PyQt] | A Python binding to the [Qt] GUI system. A specific binding but with a more restrictive license. | π |
+| [tkinter] | A Python interface to the Tcl/Tk GUI toolkit. Built into the Python standard library. | π |
+
+
+
+[tkinter]: https://docs.python.org/3/library/tkinter.html
+[Qt]: https://www.qt.io/
+[QtPy]: https://github.com/spyder-ide/qtpy
+[PySlide]: https://wiki.qt.io/Qt_for_Python
+[PyQt]: https://wiki.python.org/moin/PyQt
diff --git a/docs/pages/libraries/index.md b/docs/pages/libraries/index.md
new file mode 100644
index 00000000..42919b36
--- /dev/null
+++ b/docs/pages/libraries/index.md
@@ -0,0 +1,14 @@
+---
+title: Recommended libraries
+layout: default
+has_children: true
+---
+
+## Recommended libraries
+
+Python has a large ecosystem of packages and modules beyond what is built in to Python.
+Here is a list of libraries and toolkits that we've used in our projects, and can recommend (or might recommend that you avoid!).
+
+The libraries listed here are not really "tooling" in the sense that some projects will need some of the functionalities here, but it is project-dependent, so we don't include any of these in [our template](https://github.com/UCL-ARC/python-tooling/blob/main/README.md#using-this-template).
+If you need some functionality discussed in this list, it's good practice to add the package to your project's dependencies list.
+To test it out, simply `pip install` into your enviroment and follow the package's "Getting Started" docs.
diff --git a/docs/pages/jupyter-notebooks.md b/docs/pages/libraries/jupyter-notebooks.md
similarity index 97%
rename from docs/pages/jupyter-notebooks.md
rename to docs/pages/libraries/jupyter-notebooks.md
index 53823763..ffb78563 100644
--- a/docs/pages/jupyter-notebooks.md
+++ b/docs/pages/libraries/jupyter-notebooks.md
@@ -1,9 +1,10 @@
---
title: Jupyter Notebooks
layout: default
+parent: Recommended libraries
---
-# Jupyter notebooks
+## Jupyter notebooks
We generally recommend packaging reusable code components into Python modules
where possible. However occasionally we support researchers who prefer a
@@ -11,7 +12,7 @@ notebook environment or projects which want to provide examples and tutorials in
notebook format. Notebooks can also be a valid alternative to Python scripts for
running and recording the results of numerical experiments for example.
-## Live executable environments
+### Live executable environments
| Name | Short description | π¦ |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
@@ -19,7 +20,7 @@ running and recording the results of numerical experiments for example.
| [Google Colab](https://colab.google/) | Colab is a hosted Jupyter Notebook service that requires no setup to use and provides free access to computing resources, including GPUs and TPUs. | π’ |
| [GitHub codespaces with JupyterLab](https://docs.github.com/en/codespaces/developing-in-a-codespace/getting-started-with-github-codespaces-for-machine-learning#opening-your-codespace-in-jupyterlab) | A codespace is a development environment that is hosted in the cloud and can run [Python and Jupyter notebooks](https://github.com/github/codespaces-jupyter) | π |
-## Linting
+### Linting
Many of [our recommended linters](linting) don't work out-of-the box on Jupyter
notebooks, however [nbQA] has been found to work well. This is a translation
@@ -35,7 +36,7 @@ more reliably than [black] via [nbQA].
| [pre-commit] | Has cell output cleanup hooks (if desired). Also found to work well with [nbQA]. | π’ |
| `nbqa black` | [black] via [nbQA]. | π |
-## Other
+### Other
| Name | Short description | π¦ |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
diff --git a/docs/pages/libraries/logging.md b/docs/pages/libraries/logging.md
new file mode 100644
index 00000000..586b595e
--- /dev/null
+++ b/docs/pages/libraries/logging.md
@@ -0,0 +1,12 @@
+---
+title: Logging
+layout: default
+parent: Recommended libraries
+---
+
+## Logging
+
+| Name | Short description | π¦ |
+| --------------------------------------------------------- | -------------------------------------------------------------------- | :-: |
+| [loguru](https://loguru.readthedocs.io/) | Simple and user-friendly with many nice features enabled by default. | π’ |
+| [logging](https://docs.python.org/3/library/logging.html) | Python's builtin logging framework. Needs some configuration. | π |
diff --git a/docs/pages/parallel-async.md b/docs/pages/libraries/parallel-async.md
similarity index 94%
rename from docs/pages/parallel-async.md
rename to docs/pages/libraries/parallel-async.md
index 75d5a63d..fe47f3cc 100644
--- a/docs/pages/parallel-async.md
+++ b/docs/pages/libraries/parallel-async.md
@@ -1,9 +1,10 @@
---
title: Parallel and asynchronous processing
layout: default
+parent: Recommended libraries
---
-# Parallel and asynchronous processing
+## Parallel and asynchronous processing
Python has a good ecosystem of libraries for parallelising the processing of
tasks, as well as asynchronous processing.
@@ -19,7 +20,7 @@ a specific interface or parallelisation scheme. Possibly due to the nature of
the research problem, the high-performance computing resources available or
simply due to pre-existing code using a library like [pandas].
-## Process-based (and thread-based) parallelism
+### Process-based (and thread-based) parallelism
| Name | Short description | π¦ |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
@@ -30,22 +31,22 @@ simply due to pre-existing code using a library like [pandas].
| [mpi4py] | Support for MPI based parallelism. | π |
| [threading] | The standard library module for multi-threading. Due to the _global interpreter lock_ [currently][PEP703] only one thread can execute Python code at a time. | π΄ |
-## Compiler-based parallelism
+### Compiler-based parallelism
| Name | Short description | π¦ |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
| [Cython] | Has [support for OpenMP based parallelism](https://cython.readthedocs.io/en/latest/src/userguide/parallelism.html) | π |
-| [numba] | [Support for parallelism via `jit(parallel=True)`](https://numba.pydata.org/numba-doc/latest/user/parallel.html). | π |
+| [numba] | [Support for parallelism via `jit(parallel=True)`](https://numba.readthedocs.io/en/stable/user/parallel.html). | π |
| [jax] | [Support for parallelising NumPy / scientific computing like operations using functional transforms](https://jax.readthedocs.io/en/latest/jax-101/06-parallelism.html). | π |
-## Asynchronous processing
+### Asynchronous processing
| Name | Short description | π¦ |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
| [asyncio] | Python standard library for asynchronous programming with tasks run in a single-threaded event loop. Used for [cooperative multitasking](https://en.wikipedia.org/wiki/Cooperative_multitasking). | π |
| [concurrent.futures] | Another Python standard library for asynchronous processing. Provides a common interface for thread and process based concurrency as an alternative to using `multiprocess(ing)` or `threading` directly. | π |
-## See also
+### See also
- This [Stack Overflow post](https://stackoverflow.com/a/61360215) is a nice
summary of what each of [threading], [multiprocessing], [asyncio] and
@@ -61,7 +62,7 @@ simply due to pre-existing code using a library like [pandas].
[mpi4py]: https://mpi4py.readthedocs.io/
[pandas]: https://pandas.pydata.org/
[dask]: https://docs.dask.org/
-[numba]: https://numba.pydata.org/
+[numba]: https://numba.readthedocs.io/
[jax]: https://jax.readthedocs.io/
[asyncio]: https://docs.python.org/3/library/asyncio.html
[concurrent.futures]: https://docs.python.org/3/library/concurrent.futures.html
diff --git a/docs/pages/linting.md b/docs/pages/linting.md
index 5c5df1de..8559605f 100644
--- a/docs/pages/linting.md
+++ b/docs/pages/linting.md
@@ -3,13 +3,13 @@ title: Linting
layout: default
---
-# Linting
+## Linting
See
[here for an example configuration](https://github.com/UCL-ARC/python-tooling/blob/main/%7B%7Bcookiecutter.project_slug%7D%7D/.pre-commit-config.yaml)
for some of these.
-## Code formatting
+### Code formatting
| Name | Short description | π¦ |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
@@ -27,7 +27,7 @@ for some of these.
| [yapf](https://github.com/google/yapf) | Google formatter. | π |
| [flake8](https://flake8.pycqa.org/en/latest/) | Linter which complains if code doesn't follow a rule. Does not support modern `pyproject.toml` configuration. | π΄ |
-## Type checking
+### Type checking
| Name | Short description | π¦ |
| ---------------------------------------------- | ----------------------------------------------------------------------------- | :-: |
diff --git a/docs/pages/packaging.md b/docs/pages/packaging.md
index 9da0ecdb..58c0714a 100644
--- a/docs/pages/packaging.md
+++ b/docs/pages/packaging.md
@@ -3,7 +3,7 @@ title: Packaging
layout: default
---
-# General packaging
+## General packaging
A common question facing developers is "_How much code should go into a
package?_". Where code to solve a research problem might be large and perform
@@ -23,7 +23,7 @@ software tasks. Typically there is a separate git repository per package, and we
recommend you stick to this. You can always add the packages as dependencies to
a higher-level package which is effectively the same, but much easier to reuse.
-# Packaging tools
+## Packaging tools
| Name | Short description | π¦ |
| --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --- |
@@ -34,14 +34,14 @@ a higher-level package which is effectively the same, but much easier to reuse.
| [bump2version](https://pypi.org/project/bump2version/) | Tool for version-bumping your software. No longer maintained | π΄ |
| [bump-my-version](https://github.com/callowayproject/bump-my-version) | Tool for version-bumping your software. Superseded by setuptools_scm | π΄ |
-# Building
+## Building
| Name | Short description | π¦ |
| ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | --- |
| [build](https://pypa-build.readthedocs.io/en/stable/) | Straightforward tool to build a Python package. | π’ |
| [cibuildwheel](https://cibuildwheel.readthedocs.io) | Builds python wheels for the main operating systems on continuous integration runs (e.g. GitHub actions). | π |
-## Package configuration file
+### Package configuration file
| Name | Short description | π¦ |
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --- |
@@ -49,7 +49,7 @@ a higher-level package which is effectively the same, but much easier to reuse.
| [setup.py](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/) | Strongly coupled with setuptools and therefore not recommended. | π |
| [setup.cfg](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/) | An ini file that contains defaults for setup.py commands. | π |
-## Conda
+### Conda
These tools are helpful if you're looking to publish your package on
[conda-forge](https://conda-forge.org/), so users can install it through the
diff --git a/docs/pages/refactoring.md b/docs/pages/refactoring.md
index c606753b..9d381e05 100644
--- a/docs/pages/refactoring.md
+++ b/docs/pages/refactoring.md
@@ -3,7 +3,7 @@ title: Refactoring tools
layout: default
---
-# Refactoring Tools
+## Refactoring Tools
| Name | Short description | π¦ |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | --- |
diff --git a/docs/pages/templates.md b/docs/pages/templates.md
index 805e48c8..83da2e9b 100644
--- a/docs/pages/templates.md
+++ b/docs/pages/templates.md
@@ -4,20 +4,23 @@ layout: default
nav_order: 2
---
-# Package templates
+## Package templates
-## Recommended ARC template
+### Recommended ARC template
The [UCL-ARC/python-tooling](https://github.com/UCL-ARC/python-tooling)
repository contains our recommended package template for new ARC projects. It
pre-configures the recommended tools listed in the other pages of this site. If
you are working on a new project, our template should be a good starting point!
+We have a [tutorial](https://github.com/UCL-ARC/python-tooling/blob/main/tutorial.md)
+available with detailed instructions for creating a package using the template
+and how to use the newly created package with some of the tools included.
If you're making a package for a community that already has a template in
general use (some examples are listed below) we recommend using their template
instead.
-## Community-specific templates
+### Community-specific templates
If you're making a package within one of these communities, we recommend using
their package template.
@@ -28,7 +31,7 @@ their package template.
| [SciKit-Surgery](https://github.com/SciKit-Surgery/PythonTemplate) | Cookiecutter template developed by the Wellcome EPSRC Centre for Interventional and Surgical Sciences. |
| [Scientific Python](https://github.com/scientific-python/cookie) | Cookiecutter template developed by [SciKit-HEP](https://github.com/scikit-hep) but now adopted by the more general Scientific Python community. |
-## Template engines
+### Template engines
Tools that can be used for creating your own package template.
diff --git a/docs/pages/testing.md b/docs/pages/testing.md
index 30e2d54a..ddc784ed 100644
--- a/docs/pages/testing.md
+++ b/docs/pages/testing.md
@@ -3,9 +3,9 @@ title: Testing
layout: default
---
-# Testing
+## Testing
-## Test runners
+### Test runners
| Name | Short description | π¦ |
| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
@@ -13,9 +13,10 @@ layout: default
| [tox](https://tox.wiki/en/latest/index.html) | A framework that allows running tests and packaging in different environments. | π’ |
| [unittest](https://docs.python.org/dev/library/unittest.html#module-unittest) | Python's built in framework for writing and running tests. Encourages use of classes as test fixtures. | π |
-## pytest plugins
+### pytest plugins
-| Name | Short description | π¦ |
-| ---------------------------------------------------------------------- | ------------------------------------------------------------------------- | :-: |
-| [pytest-cov](https://pytest-cov.readthedocs.io/en/latest/index.html) | A framework to generate coverage reports that plays nicely with `pytest`. | π’ |
-| [pytest-mock](https://pytest-mock.readthedocs.io/en/latest/index.html) | A framework to mock/patch objects that plays nicely with `pytest`. | π’ |
+| Name | Short description | π¦ |
+| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
+| [pytest-cov](https://pytest-cov.readthedocs.io/en/latest/index.html) | A framework to generate coverage reports that plays nicely with `pytest`. | π’ |
+| [pytest-mock](https://pytest-mock.readthedocs.io/en/latest/index.html) | A framework to mock/patch objects that plays nicely with `pytest`. | π’ |
+| [pyfakefs](https://pytest-pyfakefs.readthedocs.io/en/latest/) | A plugin to create a full fake file system, for situations where you need something more complicated than the built in [`tmp_path` fixture](https://docs.pytest.org/en/stable/how-to/tmp_path.html#how-to-use-temporary-directories-and-files-in-tests). | π’ |
diff --git a/docs/pages/virtual.md b/docs/pages/virtual.md
index 6e189cb1..6814a577 100644
--- a/docs/pages/virtual.md
+++ b/docs/pages/virtual.md
@@ -3,12 +3,23 @@ title: Virtual environments
layout: default
---
-# Virtual environments
-
-| Name | Short description | π¦ |
-| -------------------------------------------------------- | ------------------------------------------------------------------------- | :-: |
-| [Conda](https://docs.conda.io/projects/conda/en/stable/) | Installs, runs, and updates packages and their dependencies. | π’ |
-| [pipenv](https://pipenv.pypa.io/en/latest/) | Automatically creates and manages a virtualenv for your projects. | π |
-| [pyenv](https://github.com/pyenv/pyenv) | Lets you easily switch between multiple versions of Python. | π |
-| [virtualenv](https://virtualenv.pypa.io/en/latest/) | Creates isolated Python environments, and offers more features than venv. | π |
-| [venv](https://docs.python.org/3/library/venv.html) | Creates isolated Python environments. | π΄ |
+## Virtual environments
+
+| Name | Short description | π¦ |
+| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-: |
+| conda-forge [miniforge] | Installs, runs, and updates packages and their dependencies. Uses `conda`, but with community maintained packages from `conda-forge` channel instead of commercially maintained packages. | π’ |
+| [pipenv] | Automatically creates and manages a virtualenv for your projects. | π |
+| [pyenv] | Lets you easily switch between multiple versions of Python. | π |
+| [virtualenv] | Creates isolated Python environments, and offers more features than venv. | π |
+| [venv] | Creates isolated Python environments. Fewer features than other tools, but very widely used and comes built into Python. | π |
+| [anaconda] | Due to recent [licensing ambiguity][anaconda-problems], we recommend avoiding anaconda and many of the default channels. We recommend installing miniforge and sticking to the `conda-forge` channel. | π΄ |
+
+
+
+[miniforge]: https://conda-forge.org/download/
+[pipenv]: https://pipenv.pypa.io/en/latest/
+[pyenv]: https://github.com/pyenv/pyenv
+[virtualenv]: https://virtualenv.pypa.io/en/latest/
+[anaconda]: https://www.anaconda.com/
+[anaconda-problems]: https://www.theregister.com/2024/08/08/anaconda_puts_the_squeeze_on/
+[venv]: https://docs.python.org/3/library/venv.html
diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py
index 0d0f8a71..fe617d7d 100644
--- a/hooks/post_gen_project.py
+++ b/hooks/post_gen_project.py
@@ -22,16 +22,16 @@ def main(initialise_git_repository: str, deploy_docs_to_github_pages: str) -> in
if initialise_git_repository == "True":
try:
# initialise git repo
- subprocess.run(
- [ # noqa: S603,S607
+ subprocess.run( # noqa: S603
+ [ # noqa: S607
"git",
"init",
],
check=True,
)
# old versions of git still default to `master`
- subprocess.run(
- [ # noqa: S603,S607
+ subprocess.run( # noqa: S603
+ [ # noqa: S607
"git",
"branch",
"-M",
@@ -51,8 +51,8 @@ def main(initialise_git_repository: str, deploy_docs_to_github_pages: str) -> in
try:
# check for presence of GitHub CLI
- subprocess.run(
- [ # noqa: S603,S607
+ subprocess.run( # noqa: S603
+ [ # noqa: S607
"gh",
"--version",
],
@@ -63,7 +63,7 @@ def main(initialise_git_repository: str, deploy_docs_to_github_pages: str) -> in
"GitHub CLI detected, you can create a repo with the following:\n\n"
"gh repo create "
"{{cookiecutter.__repo_name}} "
- "-d '{{cookiecutter.project_short_description}}' "
+ '-d "{{cookiecutter.project_short_description}}" '
"--public "
"-r origin "
"--source {{cookiecutter.project_slug}}\n"
diff --git a/pyproject.toml b/pyproject.toml
index 59fb3f14..2e03f83c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -38,31 +38,27 @@ spaces_indent_inline_array = 4
trailing_comma_inline_array = true
overrides."project.classifiers".inline_arrays = false
overrides."tool.coverage.paths.source".inline_arrays = false
+overrides."tool.tox.env_run_base.commands".inline_arrays = false
[tool.tox]
-legacy_tox_ini = """
- [gh-actions]
- python =
- 3.10: py310
- 3.11: py311
- 3.12: py312
-
- [gh-actions:env]
- OS =
- ubuntu-latest: linux
- macos-latest: macos
- windows-latest: windows
-
- [testenv]
- skip_install = true
- description =
- Test package creation
- deps =
- cookiecutter
- pytest
- commands =
- pytest {posargs}
-
- [tox]
- env_list = py3{9,10,11,12}-{linux,macos,windows}
-"""
+env_list = [
+ "py311",
+ "py312",
+ "py313",
+]
+env_run_base = {commands = [
+ [
+ "pytest",
+ "{posargs}",
+ ],
+], deps = [
+ "cookiecutter",
+ "pytest",
+], description = "Test package creation", skip_install = true}
+gh.python = {"3.11" = [
+ "py311",
+], "3.12" = [
+ "py312",
+], "3.13" = [
+ "py313",
+]}
diff --git a/tests/conftest.py b/tests/conftest.py
index 1549178e..c95247ed 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,24 +1,39 @@
-"""Defines fixtures for tests."""
+"""Fixtures for the cookiecutter template tests."""
+
+import pathlib
+import subprocess
+import typing
import pytest
-@pytest.fixture()
-def project_config() -> dict:
+def _generate_package(
+ config: dict[str, str], path: pathlib.Path
+) -> subprocess.CompletedProcess[str]:
"""
- Pytest fixture for defining the project config.
+ Generate a project from the cookiecutter template.
- Returns
- -------
- dict
- dictionary with values for the cookiecutter template,
+ Arguments:
+ ---------
+ config: dict
+ A dictionary with values for the cookiecutter template,
as defined in the cookiecutter.json
+ path: Path
+ Directory to create package in.
"""
- return {
- "github_owner": "test-user",
- "project_short_description": "description",
- "project_name": "Cookiecutter Test",
- "expected_repo_name": "cookiecutter-test",
- "expected_package_name": "cookiecutter_test",
- }
+ args = [f"{key}={val}" for key, val in config.items()]
+ cmd = ["cookiecutter", ".", "--no-input", "--output-dir", f"{path}"]
+ return subprocess.run( # noqa: S603
+ cmd + args,
+ check=False,
+ shell=False,
+ capture_output=True,
+ text=True,
+ )
+
+
+@pytest.fixture
+def generate_package() -> typing.Callable:
+ """Generate project from cookiecutter template."""
+ return _generate_package
diff --git a/tests/test_git_init.py b/tests/test_git_init.py
index 4c42839a..2f372e8d 100644
--- a/tests/test_git_init.py
+++ b/tests/test_git_init.py
@@ -2,56 +2,34 @@
import pathlib
import subprocess
+import typing
import pytest
-@pytest.mark.parametrize(
- "git_init_cookiecutter_option",
- ["initialise_git_repository=True", "initialise_git_repository=False"],
-)
+@pytest.mark.parametrize("initialise_git_repository", [True, False])
def test_initialisation_of_git_repo(
+ initialise_git_repository: bool, # noqa: FBT001
+ generate_package: typing.Callable,
tmp_path: pathlib.Path,
- project_config: dict,
- git_init_cookiecutter_option: str,
) -> None:
- """
- Checks to see if git was correctly initialised if desired.
-
- Args:
- tmp_path: A temporary directory path object which is unique.
- project_config: A dictionary with values for the cookiecutter template,
- as defined in the cookiecutter.json
- git_init_cookiecutter_option: A string defined in cookiecutter.json,
- which determines if git should be initialised or not
-
- """
+ """Checks to see if git was correctly initialised if desired."""
+ test_config = {
+ "github_owner": "test-user",
+ "project_short_description": "description",
+ "project_name": "Cookiecutter Test",
+ "initialise_git_repository": initialise_git_repository,
+ }
# Run cookiecutter with initialise_git_repository
- cookie = subprocess.run(
- [ # noqa: S603,S607
- "cookiecutter",
- ".",
- "--no-input",
- "--output-dir",
- f"{tmp_path}",
- f"github_owner={project_config['github_owner']}",
- f"project_name={project_config['project_name']}",
- f"project_short_description={project_config['project_short_description']}",
- git_init_cookiecutter_option,
- ],
- capture_output=True,
- check=True,
- text=True,
- )
+ result = generate_package(config=test_config, path=tmp_path)
- test_project_dir = tmp_path / project_config["expected_repo_name"]
+ test_project_dir = tmp_path / "cookiecutter-test"
# check if git is initialised
- git_status = subprocess.run(
- [ # noqa: S603,S607
+ git_status = subprocess.run( # noqa: S603
+ [ # noqa: S607
"git",
- "-C",
- f"{test_project_dir}",
+ f"--git-dir={test_project_dir / '.git'}",
"status",
],
capture_output=True,
@@ -59,46 +37,43 @@ def test_initialisation_of_git_repo(
text=True,
)
- if "True" in git_init_cookiecutter_option:
- # git status should succeed
- assert git_status.returncode == 0
-
- try:
- # check for presence of GitHub CLI
- subprocess.run(
- [ # noqa: S603,S607
- "gh",
- "--version",
- ],
- check=True,
- capture_output=True,
- )
- assert (
- "GitHub CLI detected, you can create a repo with the following:\n\n"
- f"gh repo create {project_config['github_owner']}/"
- f"{project_config['expected_repo_name']} -d "
- f"'{project_config['project_short_description']}' --public -r "
- f"origin --source {project_config['expected_repo_name']}"
- in cookie.stdout
- )
- except FileNotFoundError:
- # if GitHub CLI isn't installed then instead point to GitHub
- # Note: On GitHub Actions, the CLI is always installed
- # https://docs.github.com/en/actions/using-workflows/using-github-cli-in-workflows
- assert (
- "You now have a local git repository. To sync this to GitHub you "
- "need to create an empty GitHub repo with the name "
- f"{project_config['github_owner']}/"
- f"{project_config['expected_repo_name']} - DO NOT SELECT ANY "
- "OTHER OPTION.\n\nSee this link for more detail "
- "https://docs.github.com/en/get-started/quickstart/create-a-repo"
- ".\n\nThen run:\n\ngit remote add origin git@github.com:"
- f"{project_config['github_owner']}/"
- f"{project_config['expected_repo_name']}.git" in cookie.stdout
- )
- else:
+ if not initialise_git_repository:
# should not have found git
+ assert "fatal: not a git repository" in git_status.stderr
+ return # nothing more to test
+
+ # git status should succeed
+ assert git_status.returncode == 0
+
+ try:
+ # check for presence of GitHub CLI
+ subprocess.run( # noqa: S603
+ [ # noqa: S607
+ "gh",
+ "--version",
+ ],
+ check=True,
+ capture_output=True,
+ )
+ assert (
+ "GitHub CLI detected, you can create a repo with the following:\n\n"
+ f"gh repo create {test_config['github_owner']}/"
+ f"cookiecutter-test -d "
+ f"\"{test_config['project_short_description']}\" --public -r "
+ f"origin --source cookiecutter-test" in result.stdout
+ )
+ except FileNotFoundError:
+ # if GitHub CLI isn't installed then instead point to GitHub
+ # Note: On GitHub Actions, the CLI is always installed
+ # https://docs.github.com/en/actions/using-workflows/using-github-cli-in-workflows
assert (
- git_status.stderr
- == "fatal: not a git repository (or any of the parent directories): .git\n"
+ "You now have a local git repository. To sync this to GitHub you "
+ "need to create an empty GitHub repo with the name "
+ f"{test_config['github_owner']}/"
+ f"cookiecutter-test - DO NOT SELECT ANY "
+ "OTHER OPTION.\n\nSee this link for more detail "
+ "https://docs.github.com/en/get-started/quickstart/create-a-repo"
+ ".\n\nThen run:\n\ngit remote add origin git@github.com:"
+ f"{test_config['github_owner']}/"
+ f"cookiecutter-test.git" in result.stdout
)
diff --git a/tests/test_package_gen.py b/tests/test_package_gen.py
deleted file mode 100644
index 7d4d8516..00000000
--- a/tests/test_package_gen.py
+++ /dev/null
@@ -1,84 +0,0 @@
-"""Checks that the cookiecutter works."""
-
-import pathlib
-import subprocess
-
-
-def test_package_generation(
- tmp_path: pathlib.Path,
- project_config: dict,
-) -> None:
- """
- Creates a project from the cookiecutter template.
-
- Once the project is made it verifies a series of files and
- directories exist.
-
- Args:
- ----
- tmp_path: Path
- A temporary directory path object which is unique.
- project_config: dict
- A dictionary with values for the cookiecutter template,
- as defined in the cookiecutter.json
-
- Note that 'tmp_path' pytest fixture is preferred over 'tmpdir'
- (see https://docs.pytest.org/en/7.3.x/how-to/tmp_path.html#the-tmpdir-and-tmpdir-factory-fixtures)
-
- """
- # Run cookiecutter with project_slug set to the value in the project config
- subprocess.run(
- [ # noqa: S607
- "cookiecutter",
- ".",
- "--no-input",
- "--output-dir",
- f"{tmp_path}",
- f"project_name={project_config['project_name']}",
- ],
- check=False,
- shell=False, # noqa: S603
- )
-
- # Check project directory exists
- test_project_dir = tmp_path / project_config["expected_repo_name"]
- assert test_project_dir.exists()
-
- # Check main files and directories inside
- expected_files = [
- "README.md",
- ".pre-commit-config.yaml",
- "LICENSE.md",
- "pyproject.toml",
- "src",
- pathlib.Path("src") / project_config["expected_package_name"],
- pathlib.Path("src") / project_config["expected_package_name"] / "__init__.py",
- "tests",
- pathlib.Path(".github"),
- pathlib.Path(".github") / "workflows",
- "mkdocs.yml",
- pathlib.Path("docs") / "index.md",
- pathlib.Path("docs") / "api.md",
- ]
- for f in expected_files:
- full_path = test_project_dir / f
- assert (
- full_path.exists()
- ), f"Expected file/folder: {full_path}, but didn't find it."
-
- # Check it's pip-installable
- pipinstall = subprocess.run(
- [ # noqa: S603,S607
- "python",
- "-m",
- "pip",
- "install",
- "-e",
- test_project_dir,
- ],
- capture_output=True,
- check=False,
- )
- assert (
- pipinstall.returncode == 0
- ), f"Something went wrong with installation: {pipinstall.stderr!r}"
diff --git a/tests/test_package_generation.py b/tests/test_package_generation.py
new file mode 100644
index 00000000..95f79a5a
--- /dev/null
+++ b/tests/test_package_generation.py
@@ -0,0 +1,133 @@
+"""Checks that the cookiecutter works."""
+
+import os
+import pathlib
+import subprocess
+import typing
+
+import pytest
+
+
+def get_all_files_folders(root_path: pathlib.Path) -> set[pathlib.Path]:
+ """
+ Get all files and folders under a directory.
+
+ The paths are returned relative to the root path given.
+ """
+ file_set: set[pathlib.Path] = set()
+ for dirpath, _, filenames in os.walk(root_path):
+ dirpath_path = pathlib.Path(dirpath).relative_to(root_path)
+
+ # Add this directory
+ file_set.update((dirpath_path,))
+ # Add any files in it
+ for filename in filenames:
+ file_set.update((dirpath_path / filename,))
+
+ return file_set
+
+
+def test_package_generation(
+ tmp_path: pathlib.Path,
+ generate_package: typing.Callable,
+) -> None:
+ """Test package generation."""
+ test_config = {
+ "github_username": "test-user",
+ "project_short_description": "description",
+ "project_name": "Cookiecutter Test",
+ }
+ generate_package(config=test_config, path=tmp_path)
+
+ # Check project directory exists
+ test_project_dir = tmp_path / "cookiecutter-test"
+ assert test_project_dir.exists()
+
+ # Check main files and directories inside
+ expected_files: set[pathlib.Path] = {
+ pathlib.Path(),
+ pathlib.Path(".github"),
+ pathlib.Path(".github/ISSUE_TEMPLATE"),
+ pathlib.Path(".github/ISSUE_TEMPLATE/bug_report.yml"),
+ pathlib.Path(".github/ISSUE_TEMPLATE/config.yml"),
+ pathlib.Path(".github/ISSUE_TEMPLATE/documentation.yml"),
+ pathlib.Path(".github/ISSUE_TEMPLATE/feature_request.yml"),
+ pathlib.Path(".github/ISSUE_TEMPLATE/question.yml"),
+ pathlib.Path(".github/workflows"),
+ pathlib.Path(".github/workflows/docs.yml"),
+ pathlib.Path(".github/workflows/linting.yml"),
+ pathlib.Path(".github/workflows/tests.yml"),
+ pathlib.Path(".gitignore"),
+ pathlib.Path(".markdownlint.yaml"),
+ pathlib.Path(".pre-commit-config.yaml"),
+ pathlib.Path("CITATION.cff"),
+ pathlib.Path("LICENSE.md"),
+ pathlib.Path("README.md"),
+ pathlib.Path("docs"),
+ pathlib.Path("docs/LICENSE.md"),
+ pathlib.Path("docs/api.md"),
+ pathlib.Path("docs/index.md"),
+ pathlib.Path("mkdocs.yml"),
+ pathlib.Path("pyproject.toml"),
+ pathlib.Path("schemas"),
+ pathlib.Path("schemas/github-issue-forms.json"),
+ pathlib.Path("src"),
+ pathlib.Path("src/cookiecutter_test"),
+ pathlib.Path("src/cookiecutter_test/__init__.py"),
+ pathlib.Path("tests"),
+ pathlib.Path("tests/test_dummy.py"),
+ }
+
+ actual_files = get_all_files_folders(test_project_dir)
+ # Filter out anything under specific directories to make comparison easier
+ actual_files = {
+ a
+ for a in actual_files
+ if not (a.parts and (a.parts[0] == ".git" or "__pycache__" in a.parts))
+ }
+
+ assert actual_files == expected_files
+
+ # Check it's pip-installable
+ pipinstall = subprocess.run( # noqa: S603
+ [ # noqa: S607
+ "python",
+ "-m",
+ "pip",
+ "install",
+ "-e",
+ test_project_dir,
+ ],
+ capture_output=True,
+ check=False,
+ )
+ assert (
+ pipinstall.returncode == 0
+ ), f"Something went wrong with installation: {pipinstall.stderr!r}"
+
+
+@pytest.mark.parametrize("funder", ["", "STFC"])
+def test_optional_funder(
+ tmp_path: pathlib.Path, generate_package: typing.Callable, funder: str
+) -> None:
+ """Test package generation."""
+ config = {
+ "github_username": "test-user",
+ "project_short_description": "description",
+ "project_name": "Cookiecutter Test",
+ "funder": funder,
+ }
+
+ generate_package(config, tmp_path)
+
+ test_project_dir = tmp_path / "cookiecutter-test"
+ with (test_project_dir / "README.md").open() as f:
+ readme_text = "".join(f.readlines())
+
+ if funder == "":
+ assert "## Acknowledgements" not in readme_text
+ else:
+ assert (
+ f"## Acknowledgements\n\nThis work was funded by {config['funder']}."
+ in readme_text
+ ), readme_text
diff --git a/tutorial.md b/tutorial.md
new file mode 100644
index 00000000..bb14cd01
--- /dev/null
+++ b/tutorial.md
@@ -0,0 +1,328 @@
+# Tutorial: creating a package using template
+
+In this tutorial we will go through in detail the steps required to set-up a Python package using the `UCL-ARC/python-tooling` πͺ cookiecutter template as well as some follow on steps illustrating how to use the newly created package with some of the included tools.
+
+> [!TIP]
+> Some of the commands and URLs in the instructions contain placeholders within curly braces such as `{project_slug}`. You will need to replace these placeholders (including the curly braces) with the relevant values for your particular package / project - the text should give details of what should be subsituted for each placeholder.
+
+## βοΈ Setting up dependencies for using template
+
+Click to expand...
+
+To use the template you will need to have at least the following software tools installed,
+
+- [cookiecutter](https://cookiecutter.readthedocs.io/en/stable/),
+- [Git](https://git-scm.com/),
+
+and ideally also,
+
+- [the GitHub command line interface (CLI)](https://cli.github.com/),
+- [pre-commit](https://pre-commit.com/),
+- [tox](https://tox.wiki).
+
+These additional three tools are required to complete some of the follow on steps for using the package generated with the template, so while they are not strictly needed, you will get more out of the tutorial if you have them installed. For the follow on exercises you will also need an [account set up on GitHub](https://github.com/join) if you don't already have one.
+
+An easy way to get all the software you need installed is using the tool [Conda](https://conda.io/projects/conda/en/latest/user-guide/getting-started.html) to create a dedicated environment with the necessary packages installed by following the step by step instructions below:
+
+1. Download and install [Miniconda](https://docs.anaconda.com/free/miniconda/) following the operating system specific instructions at either
+
+ - for a graphical installer
+ - or for installation via the command line.
+
+ If you already have Miniconda (or Anaconda) installed you can skip this step.
+
+2. Once Miniconda is installed, you need to open a terminal window:
+
+ - On Windows: open the Start menu from the taskbar, type `miniconda` in the search field, then click `Anaconda Prompt (miniconda3)` from the results (or `Anaconda Prompt (anaconda3)` if using a previous Anaconda installation).
+ - On MacOS: click the Launchpad icon in the Dock, type `Terminal` in the search field, then click `Terminal` from the results.
+ - On Linux: open the default terminal application installed in your distribution.
+
+3. Once you have a terminal window open you should see text `(base)` as part of your [command prompt](https://en.wikipedia.org/wiki/Command-line_interface#Command_prompt) if Minconda has been installed and set up correctly, indicating you currently have the default `base` environment active. If this is the case you should run
+
+ ```sh
+ conda create -y -n python-tooling -c conda-forge cookiecutter git gh pre-commit tox
+ ```
+
+ to create a new environment named `python-tooling` in to which will be installed the packages necessary for creating and using a package using the `UCL-ARC/python-tooling` cookiecutter template.
+
+4. To check that all the dependencies have installed correctly in the new environment first activate the environment by running
+
+ ```sh
+ conda activate python-tooling
+ ```
+
+ at which point you should see `(base)` in the command prompt change to `(python-tooling)`, Then try running each of the following commands in turn, one at a time,
+
+ ```sh
+ cookiecutter --version
+ gh --version
+ git --version
+ pre-commit --version
+ tox --version
+ ```
+
+ For each command you should see some text outputted to the terminal giving details of the installed versions of the applications - the output itself is not important as long as you do not see any error messages.
+
+5. If you also want to try out creating a GitHub repository for the package you will need to [sign-up for a free GitHub account](https://github.com/join) if you don't already have one. Once you have a GitHub account, open a terminal window - you can either use the same one as previously if you still have it open, or open a new terminal window as described in step 2 and then activate the `python-tooling` Conda environment by running
+
+ ```sh
+ conda activate python-tooling
+ ```
+
+ Once you have a terminal window with the `python-tooling` environment active (you should see `(python-tooling)` in your command prompt) run
+
+ ```sh
+ gh auth login
+ ```
+
+ to authenticate the GitHub command line interface tool `gh` with your GitHub account credentials. The tool will ask you a series of question, for most of which you can select the default options by just hitting the `Enter` key. Specifically select:
+
+ - `GitHub.com` for account to log into,
+ - `HTTPS` for preferred protocol,
+ - `Y` to authenticate Git with your GitHub credentials,
+ - `Login with a web browser` as the method to authenticate.
+
+ Once you have selected all these options, a one-time code will be printed to the terminal. You need to copy this code and then hit the `Enter` key to open a page to complete the authentication in your default browser. Once you have entered and submitted the code in the authenticatication page, you should see a `Authentication complete` message appear in the terminal window.
+
+
+
+## πͺ Creating a package using the template
+
+We will first go through the steps for creating a new package using the `UCL-ARC/python-tooling` cookiecutter template.
+
+1. Open a terminal window:
+
+ - On Windows: open the Start menu from the taskbar, type `miniconda` in the search field, then click `Anaconda Prompt (miniconda3)` from the results.
+ - On MacOS: click the Launchpad icon in the Dock, type `Terminal` in the search field, then click `Terminal` from the results.
+ - On Linux: open the default terminal application installed in your distribution.
+
+2. In the opened terminal window change the working directory to the path you wish to create the package in using the `cd` (change directory) command.
+3. Activate the `python-tooling` Conda environment you previously created ([see instructions above](#%EF%B8%8F-setting-up-dependencies-for-using-template)) by running
+
+ ```sh
+ conda activate python-tooling
+ ```
+
+ You should now see the text `(python-tooling)` in your [command prompt](https://en.wikipedia.org/wiki/Command-line_interface#Command_prompt). If you installed, or already had installed, the tools listed above in the set up instructions at a system level you can skip this step.
+
+4. To begin creating the package run
+
+ ```sh
+ cookiecutter gh:ucl-arc/python-tooling
+ ```
+
+ You will then be shown a series of prompts at the command line asking for details of the project and package. You can choose to use the default placeholder value (shown in parenthesis `()` in prompt) for any question by hitting `Enter`. If you already have a specific project in mind you want to set up a package for using the template you can use this project's details, otherwise you can just use the placeholder values. You should choose `Y` (yes) to the questions on whether to initialise Git repository and automatically deploy HTML documentation to GitHub Pages to allow you to complete the follow on exercises which rely on these options being enabled. For the prompt asking for the GitHub user or organization name to be owner of repository you should supply your GitHub user name.
+
+5. Once you have completed all the cookiecutter prompts some additional instructions will be printed to screen (which we will come back to in the next sections) and your new package will be generated in a directory named `{project_slug}` in the current working directory (where `{project_slug}` is the value entered for the `'Slugified' project name...`[^slug] prompt, this will be `python-template` if you used the default placeholder values). You can see the directory tree of files generated by running (if on Linux or MacOS)
+
+ ```sh
+ tree {project_slug}
+ ```
+
+ or on Windows
+
+ ```sh
+ tree /F {project_slug}
+ ```
+
+ in both cases replacing `{project_slug}` with the relevant value you used (`python-template` if you used the default values).
+ Some of the key files and directories are
+
+ - The `README.md` file which is a Markdown file describing the project and acting as a landing page for first-time users.
+ - The `LICENSE.md` file which contains the terms of the open-source license the code is released under.
+ - The `src` directory which will contain the Python package source code.
+ - The `docs` directory which will contain the Markdown files used to generate the documentation pages for the package.
+ - The `tests` directory which will contain the Python modules defining tests to check for the correctness of the package code.
+
+ Try viewing the content of some of the files generated by running
+
+ ```sh
+ cat {path_to_file}
+ ```
+
+ replacing `{path_to_file}` with the relevant path.
+
+[^slug]: A ['slug'](https://en.wikipedia.org/wiki/Clean_URL#Slug) in this context is a human readable identifier with words typically separated by hyphens that can be used as part of a URL.
+
+## π¦ Creating a repository on GitHub for the new package
+
+The package you created in the previous section will have been initialised locally as a Git repository (providing you answered 'Y' to the relevant prompt!) to allow keeping the package under version control, but some extra steps are required to have the local repository synchronised to a remote repository on [GitHub](https://github.com/). The advantages of doing this are that makes it easy for other people to both download and use the package but also contribute to your project. The package has also been set up to take advantage of GitHub's continuous integration and deployment service [GitHub Actions](https://docs.github.com/en/actions) (which is free to use for public repositories) with workflows included for automatically running the package tests, performing [linting checks]() and building the project documentation, on every [pull-request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) and on updates to the default `main` [branch](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) for the repository.
+
+When you completed setting up the package using the `cookiecutter` command you should have seen some additional instructions printed to screen including, providing you have the [GitHub CLI](https://cli.github.com/) `gh` installed, a message of the form
+
+```sh
+GitHub CLI detected, you can create a repo with the following:
+
+gh repo create {github_user}/{project_slug} -d "{project_description}" --public -r origin --source {project_slug}
+```
+
+where `{github_user}`, `{project_slug}` and `{project_description}` are replaced with the relevant GitHub user name, project slug and description that you entered when setting up the package using `cookiecutter`. You should now copy-paste and run the `gh repo create ...` command that was printed out in the message - if you no longer have access to the message you can use the example above, being careful to subsitute the placeholders in braces `{}` with the relevant values.
+
+If you get an error message at this point it may be because you have not installed the GitHub CLI or set up the authorisation for the GitHub CLI as [described in the setup instructions above](#%EF%B8%8F-setting-up-dependencies-for-using-template).
+
+If the command runs successfully you should see a message of the form
+
+```sh
+β Created repository {github_user}/{project_slug} on GitHub
+ https://github.com/{github_user}/{project_slug}
+β Added remote https://github.com/{github_user}/{project_slug}.git
+```
+
+A repository should have been created at the printed URL which you should be able to navigate to in your browser (either copy-paste in to browser or depending on terminal application you may be able to hold `Ctrl` and click on URL directly). Currently both the remote and local repositories are empty as we have not made any commits.
+
+To commit the package files generated by `cookiecutter` locally on the default `main` branch and also push this commit to the repository on GitHub, run each of the commands below in turn, replacing the `{project_slug}` placeholder with the relevant value you used when creating package (`python-template` if you used default)
+
+```sh
+cd {project_slug}
+git add .
+git commit -m "Initial commit"
+git push --set-upstream origin main
+```
+
+If you now navigate to the GitHub repository URL in your browser you should see the package files present, with the content of the top-level `README.md` being displayed as the repository landing page.
+
+The push of the initial commit to the default `main` branch will have also triggered runs of the GitHub Actions workflows set up in the repository. You can view the status of the workflow job runs by opening the `Actions` pane from the top navigation bar on the repository landing page, or going to the URL `https://github.com/{github_user}/{project_slug}/actions`.
+
+Depending on your account settings, you may find that the `Documentation` workflow shows as failed (β). If this is the case this is likely because the repository has been set by default to only allow GitHub Actions workflows read permissions on the repository, which prevents the step in the `Documentation` workflow which pushes the built HTML documentation to a branch `gh-pages` from completing. In the next section we will look at how to configure the repository to ensure the permissions are set correctly and have the HTML documentation deployed to a GitHub Pages website.
+
+## π Configuring repository to host docs on GitHub Pages
+
+Now that the repository is synchronised to GitHub, a few additional steps are required to configure the repository for the HTML documentation to be automatically deployed to [GitHub Pages](https://pages.github.com/). On completion of the `cookiecutter` command to create the package, a message of the form below should have been displayed
+
+```sh
+The 'Documentation' GitHub Actions workflow has been set up to push the built
+HTML documentation to a branch gh-pages on pushes to main for deploying as a
+GitHub Pages website. To allow the GitHub Actions bot to push to the gh-pages
+branch you need to enable 'Read and write permissions' under 'Workflow
+permissions' at
+
+https://github.com/{github_user}/{project_slug}/settings/actions
+
+After the 'Documentation' workflow has successfully completed at least once
+you will also need to configure the repository to deploy a GitHub pages site
+from the content on the gh-pages branch by going to
+
+https://github.com/{github_user}/{project_slug}/settings/pages
+
+and under 'Built and deployment' selecting 'Deploy from a branch' for the
+'Source' drop-down and 'gh-pages' for the 'Branch' drop-down, leaving the
+branch path drop-down with its default value of '/ (root)'.
+```
+
+where as before `{github_user}` and `{project_slug}` are replaced with the relevant GitHub user name and project slug that you entered when setting up the package.
+
+The first part of the instructions gives details of how to set the permissions for GitHub Actions workflows in the repository to allow the GitHub Actions bot to push the built HTML documentation to a branch `gh-pages` on updates to the default `main` branch on the repository, so that the documentation is automatically updated whenever changes are merged in to `main`. After going to the Actions settings page at the URL indicated (which can also be reached by going to the `Settings` tab in the top navigation bar of the repository and then selecting `Action > General` in the left hand navigation menu) and ensuring `Workflow permissions` is set to allow `Read and write permissions`, if you have changed the permissions you will also need to re-run the documentation workflow with the updated permissions. This can be done by going to the Actions pane in the repository (accessible from top navigation bar or by going to `https://github.com/{github_user}/{project_slug}/actions`), clicking on the (top / latest if there are multiple) entry for the _Documentation_ workflow, which should be showing as failing, and then from the resulting page click the `Re-run all jobs` button.
+
+Once the _Documentation_ workflow has successfully completed, a new branch `gh-pages` should have been created in the repository containing the HTML documentation. The second part of the instructions printed in the message output by the `cookiecutter` command indicate to go to a URL `https://github.com/{github_user}/{project_slug}/settings/pages` to set this branch as the source for a GitHub Pages website for the repository. If you now follow those instructions, setting the `Source` to `Deploy from branch` and `Branch` to `gh-pages`, the a new Actions workflow `pages-build-deployment` will be automatically triggered. Once this workflow has completed, you should be able to view the HTML documentation for the repository at a URL
+
+```sh
+https://{github_user}.github.io/{project_slug}
+```
+
+The index page of the documentation reproduces the content from the repository README file. The documentation site also importantly includes _application programming interface_ (API) reference documentation built from the [docstrings](https://peps.python.org/pep-0257/#what-is-a-docstring) in the package source code; this API documentation is accessible from the `API reference` link in the navigation.
+
+## π Setting up a virtual environment for project
+
+Whenever you are working on a Python project we would recommend setting up a project-specific [virtual environment](https://docs.python.org/3/tutorial/venv.html). This allows you to install the versions of third-party packages the project requires without conflicting with the requirements of other projects you are developing.
+
+There are a variety of virtual environment management tools available for Python. One option is [Conda](https://conda.io/projects/conda/en/latest/index.html), which you will have installed if you followed our detailed set-up instructions above, or may already have installed previously. Conda can install both Python packages and other tools - for example in the set-up instructions we recommended using it to install Git. Compared to other Python virtual environment options, Conda has the advantage that it can also be used to install different versions of Python itself, which can be useful to set up environments to test across multiple Python versions rather than having to use the Python versions installed at a system level or using a separate tool like [pyenv](https://github.com/pyenv/pyenv) to manage multiple Python versions.
+
+A Conda environment for the project can be created by running in a terminal the command
+
+```sh
+conda create -y -n {project_slug} -c conda-forge python
+```
+
+This will create a new environment with name `{project_slug}` (which you should replace with the relevant project slug value for your project), installing the latest version of Python using the package hosted on the [community driven `conda-forge` channel](https://conda-forge.org/). To make this Conda environment the current active environment run
+
+```sh
+conda activate {project_slug}
+```
+
+again replacing `{project_slug}` with the relevant project slug for your package.
+
+An alternative to Conda is the [`venv` module](https://docs.python.org/3/library/venv.html) built-in to the Python standard library. This has the advantage of being available in any Python (3.3+) environment, but unlike Conda will not by itself allow you to use a different Python version from the system level install. In contrast to Conda which by default creates all environments in a shared user-level directory (if using Miniconda, by default in a directory `miniconda3/envs` in your user or home directory), the `venv` module requires being passed a path in which to create the directory containing the files associated with the virtual environment. A common pattern is to store the virtual environment files in a directory `.venv` within the root directory of the project repository. This can be achieved by running
+
+```sh
+python -m venv .venv
+```
+
+from the root of the project repository. To activate the new virtual environment, if on Linux or MacOS run from the root of the project repository
+
+```sh
+source .venv/bin/activate
+```
+
+or if on Windows
+
+```sh
+.venv\Scripts\activate
+```
+
+Once you have activated the environment you should make sure the version of the Python package manager `pip` installed in the environment is up to date by running
+
+```sh
+python -m pip install --upgrade pip
+```
+
+Once you have created and activated a virtual environment for the project, you can install the package in [editable mode](https://setuptools.pypa.io/en/latest/userguide/development_mode.html), along with both its required dependencies and optional sets of dependencies for development (`dev`), documentation (`docs`) and testing (`test`) by running
+
+```sh
+python -m pip install --editable ".[dev,docs,test]"
+```
+
+from the root of the project repository.
+
+## π§ͺ Running package tests locally
+
+The package template includes support for running tests using the [`pytest` testing framework](https://docs.pytest.org/). Tests are defined in modules in the `tests` directory. By default a single test module `tests/test_dummy.py` is created with a placeholder test. You can run the test locally using `pytest` directly (you will need to have the virtual environment active in which you installed the package and its dependencies) by running
+
+```sh
+pytest
+```
+
+from the root of the project repository.
+
+The package template also sets up [`tox`](https://tox.wiki), an automation tool which allows easily running tests in isolated environments and under multiple Python versions. You can run the tests across all compatible Python versions currently installed using `tox` by running
+
+```sh
+tox
+```
+
+from the root of the project repository.
+
+## π Building documentation locally
+
+It can sometimes be useful when editing docstrings or adding additional pages in the `docs` directory to be able to render the HTML documentation locally. The package is set up to use [MkDocs](https://www.mkdocs.org/) to build the documentation with the package API documentation generated using the [`mkdocstrings` plug-in](https://mkdocstrings.github.io/). These packages will have been installed in to you local development environment providing you installed the package with optional `docs` dependencies as recommended above. To build and serve the documentation locally run
+
+```sh
+mkdocs serve
+```
+
+from the root of the project repository and navigate to `http://127.0.0.1:8000/` in your browser. The development server used here supports auto-reloading, meaning the content will be automatically refreshed in your browser if you make any edits to source.
+
+A `tox` environment `docs` to build the documentation is also available. This will be build the documentation in an isolated environment and is also used for building the documentation in the GitHub Actions _Documentation_ workflow so can be useful to run locally when debugging issues with the workflow - it can be executed by running
+
+```sh
+tox -e docs
+```
+
+from the root of the project repository. The built documentation will be output to a directory `site`.
+
+## β
Using `pre-commit` to run checks when committing
+
+The package is set-up to use [pre-commit](https://pre-commit.com/), a framework for running [Git hook scripts](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) on each commit to the repository. In particular the a `.pre-commit-config.yaml` configuration file is provided which will run a series of linters, checks and formatters on the repository such as [ruff](https://docs.astral.sh/ruff/), [mypy](https://mypy.readthedocs.io/en/stable/) and [prettier](https://prettier.io/) on every commit. These Git hook scripts can installed locally by running
+
+```sh
+pre-commit install
+```
+
+from the root of the project repository. Once installed the hook scripts will be called to inspect the changes each time `git commit` is run, with any failures of the checks needing to be resolved before the changes can be commited. Some of the `pre-commit` hooks include support for auto-fixing some problems - in this case you will be alerted that a file has been changed by a hook and these changes need to be staged using `git add` before recommitting.
+
+The `pre-commit` hooks can be run against all files in the repository by running
+
+```sh
+pre-commit run --all-files
+```
+
+from the root of the project repository. As the hooks are typically only run on the files changed in a commit, this can be useful to check the hooks will pass on all files when the `pre-commit` configuration is updated by, for example, [adding a new plug-in](https://pre-commit.com/#plugins).
diff --git a/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/bug_report.yml b/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/bug_report.yml
index 78112419..16f16f13 100644
--- a/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -1,7 +1,6 @@
---
name: Bug Report
description: Create a Report to Help us Improve
-title: "A one-line description of your problem"
labels:
- bug
body:
diff --git a/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/documentation.yml b/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/documentation.yml
index 7510d2c9..582c191c 100644
--- a/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/documentation.yml
+++ b/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/documentation.yml
@@ -1,7 +1,6 @@
---
name: Documentation
description: How Can We Improve the Documentation
-title: "What needs improving in the documentation?"
labels:
- documentation
body:
diff --git a/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/feature_request.yml b/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/feature_request.yml
index 50e76847..8e1ad7fe 100644
--- a/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -1,7 +1,6 @@
---
name: Feature Request
description: Suggest a Way to Improve This Project
-title: "Feature suggestion: What should be added?"
labels:
- enhancement
body:
diff --git a/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/question.yml b/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/question.yml
index 7a36a49d..d7d181ad 100644
--- a/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/question.yml
+++ b/{{cookiecutter.project_slug}}/.github/ISSUE_TEMPLATE/question.yml
@@ -1,7 +1,6 @@
---
name: Question
description: General Questions About Using {{cookiecutter.project_name}}
-title: "The title of your question."
labels:
- question
body:
diff --git a/{{cookiecutter.project_slug}}/.github/workflows/docs.yml b/{{cookiecutter.project_slug}}/.github/workflows/docs.yml
index b9401fdb..5aadee67 100644
--- a/{{cookiecutter.project_slug}}/.github/workflows/docs.yml
+++ b/{{cookiecutter.project_slug}}/.github/workflows/docs.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
+ uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Cache tox
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
@@ -20,7 +20,7 @@ jobs:
key: tox-${{ '{{' }} hashFiles('pyproject.toml') {{ '}}' }}
- name: Set up Python
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
+ uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5
with:
python-version: "3.x"
cache: "pip"
diff --git a/{{cookiecutter.project_slug}}/.github/workflows/linting.yml b/{{cookiecutter.project_slug}}/.github/workflows/linting.yml
index 6c3d6da5..88ae5976 100644
--- a/{{cookiecutter.project_slug}}/.github/workflows/linting.yml
+++ b/{{cookiecutter.project_slug}}/.github/workflows/linting.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
+ uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Cache pre-commit
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
@@ -20,7 +20,7 @@ jobs:
key: pre-commit-${{ '{{' }} hashFiles('.pre-commit-config.yaml') {{ '}}' }}
- name: Set up python
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
+ uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5
with:
python-version: "3.x"
cache: pip
diff --git a/{{cookiecutter.project_slug}}/.github/workflows/tests.yml b/{{cookiecutter.project_slug}}/.github/workflows/tests.yml
index 595d1ec8..ffe309eb 100644
--- a/{{cookiecutter.project_slug}}/.github/workflows/tests.yml
+++ b/{{cookiecutter.project_slug}}/.github/workflows/tests.yml
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout source
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4
+ uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- name: Cache tox
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
@@ -32,14 +32,14 @@ jobs:
key: tox-${{ '{{' }}hashFiles('pyproject.toml') {{ '}}' }}
- name: Set up python
- uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
+ uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5
with:
python-version: ${{ '{{' }} matrix.python-version {{ '}}' }}
cache: pip
cache-dependency-path: pyproject.toml
- name: Install dependencies
- run: python -m pip install tox tox-gh-actions
+ run: python -m pip install tox tox-gh
- name: Test with tox
- run: tox
+ run: tox run
diff --git a/{{cookiecutter.project_slug}}/.markdownlint.yaml b/{{cookiecutter.project_slug}}/.markdownlint.yaml
new file mode 100644
index 00000000..02907b2b
--- /dev/null
+++ b/{{cookiecutter.project_slug}}/.markdownlint.yaml
@@ -0,0 +1,2 @@
+---
+MD013: false
diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
index 8dcad847..d0b9f320 100644
--- a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
+++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
@@ -1,9 +1,15 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.4.7
+ rev: v0.6.8
hooks:
- id: ruff
- id: ruff-format
+ - repo: https://github.com/igorshubovych/markdownlint-cli
+ rev: v0.42.0
+ hooks:
+ - id: markdownlint-fix
+ args:
+ - --dot
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
hooks:
@@ -13,7 +19,7 @@ repos:
hooks:
- id: toml-sort-fix
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.10.0
+ rev: v1.11.2
hooks:
- id: mypy
- repo: https://github.com/pre-commit/mirrors-prettier
@@ -35,7 +41,7 @@ repos:
- --fix=lf
- id: trailing-whitespace
- repo: https://github.com/python-jsonschema/check-jsonschema
- rev: 0.28.4
+ rev: 0.29.3
hooks:
# Schemas taken from https://www.schemastore.org/json/
- id: check-jsonschema
diff --git a/{{cookiecutter.project_slug}}/LICENSE.md b/{{cookiecutter.project_slug}}/LICENSE.md
index 4901310c..866f8c19 100644
--- a/{{cookiecutter.project_slug}}/LICENSE.md
+++ b/{{cookiecutter.project_slug}}/LICENSE.md
@@ -1,3 +1,5 @@
+
+
{%- if cookiecutter.license == "MIT" -%}
# MIT License
diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.project_slug}}/README.md
index 0a2fb1ff..8451edf1 100644
--- a/{{cookiecutter.project_slug}}/README.md
+++ b/{{cookiecutter.project_slug}}/README.md
@@ -6,12 +6,6 @@
[![Documentation status][documentation-badge]][documentation-link]
[![License][license-badge]](./LICENSE.md)
-
-
[tests-badge]: {{cookiecutter.__repo_url}}/actions/workflows/tests.yml/badge.svg
[tests-link]: {{cookiecutter.__repo_url}}/actions/workflows/tests.yml
@@ -19,18 +13,13 @@
[linting-link]: {{cookiecutter.__repo_url}}/actions/workflows/linting.yml
[documentation-badge]: {{cookiecutter.__repo_url}}/actions/workflows/docs.yml/badge.svg
[documentation-link]: {{cookiecutter.__repo_url}}/actions/workflows/docs.yml
-[conda-badge]: https://img.shields.io/conda/vn/conda-forge/{{cookiecutter.project_slug}}
-[conda-link]: https://github.com/conda-forge/{{cookiecutter.project_slug}}-feedstock
-[pypi-link]: https://pypi.org/project/{{cookiecutter.project_slug}}/
-[pypi-platforms]: https://img.shields.io/pypi/pyversions/{{cookiecutter.project_slug}}
-[pypi-version]: https://img.shields.io/pypi/v/{{cookiecutter.project_slug}}
-{% if cookiecutter.license == "MIT" -%}
+{%- if cookiecutter.license == "MIT" %}
[license-badge]: https://img.shields.io/badge/License-MIT-yellow.svg
-{%- elif cookiecutter.license == "BSD-3" -%}
+{%- elif cookiecutter.license == "BSD-3" %}
[license-badge]: https://img.shields.io/badge/License-BSD_3--Clause-blue.svg
-{%- elif cookiecutter.license == "GPL-3.0" -%}
+{%- elif cookiecutter.license == "GPL-3.0" %}
[license-badge]: https://img.shields.io/badge/License-GPLv3-blue.svg
-{% endif %}
+{%- endif %}
{{cookiecutter.project_short_description}}
@@ -141,7 +130,9 @@ mkdocs serve
- [ ] Minimum viable product <-- You are Here
- [ ] Alpha Release
- [ ] Feature-Complete Release
+{%- if cookiecutter.funder != '' %}
## Acknowledgements
-This work was funded by a grant from the {{cookiecutter.funder}}.
+This work was funded by {{cookiecutter.funder}}.
+{%- endif %}
diff --git a/{{cookiecutter.project_slug}}/docs/LICENSE.md b/{{cookiecutter.project_slug}}/docs/LICENSE.md
index 8dbe6e25..75b899af 100644
--- a/{{cookiecutter.project_slug}}/docs/LICENSE.md
+++ b/{{cookiecutter.project_slug}}/docs/LICENSE.md
@@ -1 +1,3 @@
+
+
{! include-markdown "../LICENSE.md" !}
diff --git a/{{cookiecutter.project_slug}}/docs/index.md b/{{cookiecutter.project_slug}}/docs/index.md
index 42911bd5..e8a17ad1 100644
--- a/{{cookiecutter.project_slug}}/docs/index.md
+++ b/{{cookiecutter.project_slug}}/docs/index.md
@@ -1 +1,3 @@
+
+
{! include-markdown "../README.md" rewrite-relative-urls=false !}
diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.project_slug}}/pyproject.toml
index 3416d848..218e7396 100644
--- a/{{cookiecutter.project_slug}}/pyproject.toml
+++ b/{{cookiecutter.project_slug}}/pyproject.toml
@@ -111,36 +111,37 @@ spaces_indent_inline_array = 4
trailing_comma_inline_array = true
overrides."project.classifiers".inline_arrays = false
overrides."tool.coverage.paths.source".inline_arrays = false
+overrides."tool.tox.env.docs.commands".inline_arrays = false
+overrides."tool.tox.env_run_base.commands".inline_arrays = false
[tool.tox]
-legacy_tox_ini = """
- [gh-actions]
- python =
- {%- for python_version in range(
- cookiecutter.min_python_version | replace('3.', '') | int,
- cookiecutter.max_python_version | replace('3.', '') | int + 1
- ) %}
- 3.{{python_version}}: py3{{python_version}}
- {%- endfor %}
-
- [testenv]
- commands =
- pytest --cov --cov-report=xml
- extras =
- test
-
- [testenv:docs]
- commands =
- mkdocs build --strict
- extras =
- docs
-
- [tox]
- env_list =
- {%- for python_version in range(
- cookiecutter.min_python_version | replace('3.', '') | int,
- cookiecutter.max_python_version | replace('3.', '') | int + 1
- ) %}
- py3{{python_version}}
- {%- endfor %}
-"""
+env_list = [
+{%- for python_version in range(
+ cookiecutter.min_python_version | replace('3.', '') | int,
+ cookiecutter.max_python_version | replace('3.', '') | int + 1
+) %}
+ "py3{{python_version}}",
+{%- endfor %}
+]
+env_run_base = {commands = [
+ [
+ "pytest",
+ "--cov",
+ "--cov-report=xml",
+ ],
+], extras = [
+ "test",
+]}
+env.docs = {commands = [
+ "mkdocs",
+ "build",
+ "--strict",
+], extras = [
+ "docs",
+]}
+{%- for python_version in range(
+ cookiecutter.min_python_version | replace('3.', '') | int,
+ cookiecutter.max_python_version | replace('3.', '') | int + 1
+) %}
+gh.python."3.{{python_version}}" = ["py3{{python_version}}"]
+{%- endfor %}