Scientific Python Library Development Guide and Cookiecutter
See the codeA copier/cookiecutter template for new Python projects based on the Scientific Python Developer Guide. What makes this different from other templates for Python packages?
github.com url (the default), and
adds experimental GitLab CI support otherwise.sp-repo-review to evaluate existing repos against the
guidelines, with a WebAssembly version integrated with the guide. Checks are
hyperlinked back to the guide.Be sure you have read the Scientific-Python Development Guide first, and
possibly used them on a project or two. This is not a minimal example or
tutorial. It is a collection of useful tooling for starting a new project using
cookiecutter, or for copying in individual files for an existing project (by
hand, from {{cookiecutter.project_name}}/).
During generation you can select from the following backends for your package:
uv_build backend is written in Rust and is integrated into'
uv, meaning it can build without downloading anything extra and can even
avoid running Python at all when building, making it the fastest backend for
simple packages. No dynamic metadata support.Currently, the best choice is probably hatch for pure Python projects, and scikit-build (such as the scikit-build-core + pybind11 choice) for binary projects.
Install copier and copier-templates-extensions. Using uv, that's:
uv tool install --with copier-templates-extensions copier
Now, run copier to generate your project:
copier copy gh:scientific-python/cookie <pkg> --trust --vcs-ref=HEAD
(<pkg> is the path to put the new project. --vcs-ref=HEAD gets the current
version instead of the last tag, matching cookiecutter's behavior. Note you can
combine these two lines into one with uvx, just remember to pass --with
before the program name in that case.)
You will get a nicer CLI experience with answer validation. You will also get a
.copier-answers.yml file, which will allow you to perform updates in the
future.
Note: Add
--vcs-ref=HEADto get the latest version instead of the last tagged version; HEAD always passes tests (and is what cookiecutter uses).
Install cookiecutter, ideally with brew install cookiecutter if you use brew,
otherwise with uv tool install cookiecutter (or prepend uvx to the command
below, and skip installation). Then run:
cookiecutter gh:scientific-python/cookie
If you are using cookiecutter 2.2.3+, you will get nice descriptions for the options like copier!
You can also use cruft, which adds the ability update to cookiecutter
projects. Install with uv tool install cruft (or prepend uvx to the command
below, and skip installation). Then run:
cruft create https://github.com/scientific-python/cookie
Check the key setup files, pyproject.toml, and possibly setup.cfg and
setup.py (pybind11 example). Update README.md. Also update and add docs to
docs/.
There are a few example dependencies and a minimum Python version of 3.11, feel free to change it to whatever you actually need/want. There is also a basic backports structure with a small typing example.
docs/ folder and docs dependency-grouptests/ folder and pytest test dependency-groupuv run integrationYou can test locally with nox:
# See all commands
nox -l
# Run a specific check
nox -s "lint(scikit-build)"
# Run a noxfile command on the project noxfile
nox -s "nox(hatch)" -- docs
If you don't have nox locally, you can use uv, such as uvx nox instead.
Hypermodern-Python is another project worth checking out with many similarities, like great documentation for each feature and many of the same tools used. It has a slightly different set of features, and has a stronger focus on GitHub Actions - most our guide could be adapted to a different CI system fairly easily if you don't want to use GHA. It also forces the use of Poetry (instead of having a backend selection), and doesn't support compiled projects. It currently dumps all development dependencies into a shared environment, causing long solve times and high chance of conflicts. It also does not use pre-commit the way it was intended to be used. It also has quite a bit of custom code.
A lot of the guide, cookiecutter, and repo-review started out as part of Scikit-HEP. These projects were merged, generalized, and combined with the NSLS-II guide during the 2023 Scientific-Python Developers Summit.
sp-repo-review provides checks based on the Scientific-Python Development
Guide at scientific-python/cookie for repo-review.
This tool can check the style of a repository. Use like this:
uvx sp-repo-review[cli] <path to repository>
This will produce a list of results - green checkmarks mean this rule is followed, red x’s mean the rule is not. A yellow warning sign means that the check was skipped because a previous required check failed. Some checks will fail, that’s okay - the goal is bring all possible issues to your attention, not to force compliance with arbitrary checks. Eventually there might be a way to mark checks as ignored.
For example, GH101 expects all your action files to have a nice name: field.
If you are happy with the file-based names you see in CI, you should feel free
to simply ignore this check (you can specify ignored checks in pyproject.toml or
by passing args to repo-review, see the repo-review
docs).
All checks are mentioned at least in some way in the Scientific-Python
Development Guide. You should read that first - if you are not attempting to
follow them, some of the checks might not work. For example, the guidelines
specify pytest configuration be placed in pyproject.toml. If you place it
somewhere else, then all the pytest checks will be skipped.
This was originally developed for Scikit-HEP before moving to Scientific Python.
cli: Dependencies to run the CLI (not needed for programmatic access, like
on Web Assembly)pyproject: Include validate pyproject with schema store.all: All extrasThere's also a script, accessible as sp-ruff-checks, that will compare your
ruff checks to the known values. It's a little more elegant on the command line
than the Ruff family description, which will only print out a basic list.
You can also use GitHub Actions:
- uses: scientific-python/cookie@<version>
Or pre-commit:
- repo: https://github.com/scientific-python/cookie
rev: <version>
hooks:
- id: sp-repo-review
If you use additional_dependencies to add more plugins, like
validate-pyproject, you should also include "repo-review[cli]" to ensure the
CLI requirements are included.
PY001: Has a pyproject.tomlPY002: Has a README.(md|rst) filePY003: Has a LICENSE* filePY004: Has docs folderPY005: Has tests folderPY006: Has pre-commit configPY007: Supports an easy task runner (nox, tox, pixi, etc.)PY008: Has a .gitignore filePP002: Has a proper build-system tablePP003: Does not list wheel as a build-depPP004: Does not upper cap Python requiresPP005: Using SPDX project.license should not use deprecated trove classifiersPP006: The dev dependency group should be definedPP301: Has pytest in pyprojectPP302: Sets a minimum pytest to at least 6 or 9PP303: Sets the test pathsPP304: Sets the log level in pytestPP305: Specifies strict xfailPP306: Specifies strict configPP307: Specifies strict markersPP308: Specifies useful pytest summaryPP309: Filter warnings specifiedGH100: Has GitHub Actions configGH101: Has nice namesGH102: Auto-cancel on repeated PRsGH103: At least one workflow with manual dispatch triggerGH104: Use unique names for upload-artifactGH105: Use Trusted Publishing instead of token-based publishing on PyPIGH200: Maintained by DependabotGH210: Maintains the GitHub action versions with DependabotGH211: Do not pin core actions as major versionsGH212: Require GHA update groupingMY100: Uses a type checker (pyproject config)MY101: Type checker in strict modeMY102: MyPy show_error_codes deprecatedMY103: MyPy warn unreachableMY104: MyPy enables ignore-without-codeMY105: MyPy enables redundant-exprMY106: MyPy enables truthy-boolWill not show up if no noxfile.py file is present.
NOX101: Sets minimum nox versionNOX102: Sets venv backendNOX103: Set default per session instead of session listNOX201: Set a script block with dependencies in your noxfileNOX202: Has a shebang lineNOX203: Provide a main block to run noxWill not show up if using lefthook instead of pre-commit/prek.
PC100: Has pre-commit-hooksPC110: Uses black or ruff-formatPC111: Formats code in docs (ruff-format or blacken-docs)PC140: Uses a type checkerPC160: Uses a spell checkerPC170: Uses PyGrep hooks (only needed if rST present)PC180: Uses a markdown formatterPC190: Uses a linter (Ruff/Flake8)PC191: Ruff show fixes if fixes enabledPC192: Ruff uses ruff-check instead of ruff (legacy)PC901: Custom pre-commit CI update messagePC902: Custom pre-commit CI autofix messagePC903: Specified pre-commit CI scheduleWill not show up if no .readthedocs.yml/.readthedocs.yaml file is present.
RTD100: Uses ReadTheDocs (pyproject config)RTD101: You have to set the RTD version number to 2RTD102: You have to set the RTD build imageRTD103: You have to set the RTD python versionRTD104: You have to specify a build configuration now for readthedocs.RF001: Has Ruff configRF002: Target version must be setRF003: src directory doesn't need to be specified anymore (0.6+)RF101: Bugbear must be selectedRF201: Avoid using deprecated config settingsRF202: Use (new) lint config sectionSEC001: Use zizmor to check the GitHub ActionsWill not show up if no setup.cfg file is present.
SCFG001: Avoid deprecated setup.cfg names40,727 followers · starred Jun 2023
146 followers · starred Nov 2023
995 followers · starred Sep 2023
8,334 followers · starred Jan 2024
Scientific Python Library Development Guide and Cookiecutter
See the codeA copier/cookiecutter template for new Python projects based on the Scientific Python Developer Guide. What makes this different from other templates for Python packages?
github.com url (the default), and
adds experimental GitLab CI support otherwise.sp-repo-review to evaluate existing repos against the
guidelines, with a WebAssembly version integrated with the guide. Checks are
hyperlinked back to the guide.Be sure you have read the Scientific-Python Development Guide first, and
possibly used them on a project or two. This is not a minimal example or
tutorial. It is a collection of useful tooling for starting a new project using
cookiecutter, or for copying in individual files for an existing project (by
hand, from {{cookiecutter.project_name}}/).
During generation you can select from the following backends for your package:
uv_build backend is written in Rust and is integrated into'
uv, meaning it can build without downloading anything extra and can even
avoid running Python at all when building, making it the fastest backend for
simple packages. No dynamic metadata support.Currently, the best choice is probably hatch for pure Python projects, and scikit-build (such as the scikit-build-core + pybind11 choice) for binary projects.
Install copier and copier-templates-extensions. Using uv, that's:
uv tool install --with copier-templates-extensions copier
Now, run copier to generate your project:
copier copy gh:scientific-python/cookie <pkg> --trust --vcs-ref=HEAD
(<pkg> is the path to put the new project. --vcs-ref=HEAD gets the current
version instead of the last tag, matching cookiecutter's behavior. Note you can
combine these two lines into one with uvx, just remember to pass --with
before the program name in that case.)
You will get a nicer CLI experience with answer validation. You will also get a
.copier-answers.yml file, which will allow you to perform updates in the
future.
Note: Add
--vcs-ref=HEADto get the latest version instead of the last tagged version; HEAD always passes tests (and is what cookiecutter uses).
Install cookiecutter, ideally with brew install cookiecutter if you use brew,
otherwise with uv tool install cookiecutter (or prepend uvx to the command
below, and skip installation). Then run:
cookiecutter gh:scientific-python/cookie
If you are using cookiecutter 2.2.3+, you will get nice descriptions for the options like copier!
You can also use cruft, which adds the ability update to cookiecutter
projects. Install with uv tool install cruft (or prepend uvx to the command
below, and skip installation). Then run:
cruft create https://github.com/scientific-python/cookie
Check the key setup files, pyproject.toml, and possibly setup.cfg and
setup.py (pybind11 example). Update README.md. Also update and add docs to
docs/.
There are a few example dependencies and a minimum Python version of 3.11, feel free to change it to whatever you actually need/want. There is also a basic backports structure with a small typing example.
docs/ folder and docs dependency-grouptests/ folder and pytest test dependency-groupuv run integrationYou can test locally with nox:
# See all commands
nox -l
# Run a specific check
nox -s "lint(scikit-build)"
# Run a noxfile command on the project noxfile
nox -s "nox(hatch)" -- docs
If you don't have nox locally, you can use uv, such as uvx nox instead.
Hypermodern-Python is another project worth checking out with many similarities, like great documentation for each feature and many of the same tools used. It has a slightly different set of features, and has a stronger focus on GitHub Actions - most our guide could be adapted to a different CI system fairly easily if you don't want to use GHA. It also forces the use of Poetry (instead of having a backend selection), and doesn't support compiled projects. It currently dumps all development dependencies into a shared environment, causing long solve times and high chance of conflicts. It also does not use pre-commit the way it was intended to be used. It also has quite a bit of custom code.
A lot of the guide, cookiecutter, and repo-review started out as part of Scikit-HEP. These projects were merged, generalized, and combined with the NSLS-II guide during the 2023 Scientific-Python Developers Summit.
sp-repo-review provides checks based on the Scientific-Python Development
Guide at scientific-python/cookie for repo-review.
This tool can check the style of a repository. Use like this:
uvx sp-repo-review[cli] <path to repository>
This will produce a list of results - green checkmarks mean this rule is followed, red x’s mean the rule is not. A yellow warning sign means that the check was skipped because a previous required check failed. Some checks will fail, that’s okay - the goal is bring all possible issues to your attention, not to force compliance with arbitrary checks. Eventually there might be a way to mark checks as ignored.
For example, GH101 expects all your action files to have a nice name: field.
If you are happy with the file-based names you see in CI, you should feel free
to simply ignore this check (you can specify ignored checks in pyproject.toml or
by passing args to repo-review, see the repo-review
docs).
All checks are mentioned at least in some way in the Scientific-Python
Development Guide. You should read that first - if you are not attempting to
follow them, some of the checks might not work. For example, the guidelines
specify pytest configuration be placed in pyproject.toml. If you place it
somewhere else, then all the pytest checks will be skipped.
This was originally developed for Scikit-HEP before moving to Scientific Python.
cli: Dependencies to run the CLI (not needed for programmatic access, like
on Web Assembly)pyproject: Include validate pyproject with schema store.all: All extrasThere's also a script, accessible as sp-ruff-checks, that will compare your
ruff checks to the known values. It's a little more elegant on the command line
than the Ruff family description, which will only print out a basic list.
You can also use GitHub Actions:
- uses: scientific-python/cookie@<version>
Or pre-commit:
- repo: https://github.com/scientific-python/cookie
rev: <version>
hooks:
- id: sp-repo-review
If you use additional_dependencies to add more plugins, like
validate-pyproject, you should also include "repo-review[cli]" to ensure the
CLI requirements are included.
PY001: Has a pyproject.tomlPY002: Has a README.(md|rst) filePY003: Has a LICENSE* filePY004: Has docs folderPY005: Has tests folderPY006: Has pre-commit configPY007: Supports an easy task runner (nox, tox, pixi, etc.)PY008: Has a .gitignore filePP002: Has a proper build-system tablePP003: Does not list wheel as a build-depPP004: Does not upper cap Python requiresPP005: Using SPDX project.license should not use deprecated trove classifiersPP006: The dev dependency group should be definedPP301: Has pytest in pyprojectPP302: Sets a minimum pytest to at least 6 or 9PP303: Sets the test pathsPP304: Sets the log level in pytestPP305: Specifies strict xfailPP306: Specifies strict configPP307: Specifies strict markersPP308: Specifies useful pytest summaryPP309: Filter warnings specifiedGH100: Has GitHub Actions configGH101: Has nice namesGH102: Auto-cancel on repeated PRsGH103: At least one workflow with manual dispatch triggerGH104: Use unique names for upload-artifactGH105: Use Trusted Publishing instead of token-based publishing on PyPIGH200: Maintained by DependabotGH210: Maintains the GitHub action versions with DependabotGH211: Do not pin core actions as major versionsGH212: Require GHA update groupingMY100: Uses a type checker (pyproject config)MY101: Type checker in strict modeMY102: MyPy show_error_codes deprecatedMY103: MyPy warn unreachableMY104: MyPy enables ignore-without-codeMY105: MyPy enables redundant-exprMY106: MyPy enables truthy-boolWill not show up if no noxfile.py file is present.
NOX101: Sets minimum nox versionNOX102: Sets venv backendNOX103: Set default per session instead of session listNOX201: Set a script block with dependencies in your noxfileNOX202: Has a shebang lineNOX203: Provide a main block to run noxWill not show up if using lefthook instead of pre-commit/prek.
PC100: Has pre-commit-hooksPC110: Uses black or ruff-formatPC111: Formats code in docs (ruff-format or blacken-docs)PC140: Uses a type checkerPC160: Uses a spell checkerPC170: Uses PyGrep hooks (only needed if rST present)PC180: Uses a markdown formatterPC190: Uses a linter (Ruff/Flake8)PC191: Ruff show fixes if fixes enabledPC192: Ruff uses ruff-check instead of ruff (legacy)PC901: Custom pre-commit CI update messagePC902: Custom pre-commit CI autofix messagePC903: Specified pre-commit CI scheduleWill not show up if no .readthedocs.yml/.readthedocs.yaml file is present.
RTD100: Uses ReadTheDocs (pyproject config)RTD101: You have to set the RTD version number to 2RTD102: You have to set the RTD build imageRTD103: You have to set the RTD python versionRTD104: You have to specify a build configuration now for readthedocs.RF001: Has Ruff configRF002: Target version must be setRF003: src directory doesn't need to be specified anymore (0.6+)RF101: Bugbear must be selectedRF201: Avoid using deprecated config settingsRF202: Use (new) lint config sectionSEC001: Use zizmor to check the GitHub ActionsWill not show up if no setup.cfg file is present.
SCFG001: Avoid deprecated setup.cfg names40,727 followers · starred Jun 2023
146 followers · starred Nov 2023
995 followers · starred Sep 2023
8,334 followers · starred Jan 2024