Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Basic continuous integration and deployment (CI/CD) workflow for Python packages.

- checks formatting (black)
- checks formatting (black, isort)
- checks linting (ruff)
- run unit tests (pytest)
- optional: add c extensions to a package
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: psf/black@stable
- uses: isort/isort-action@v1
lint:
name: Lint with ruff
runs-on: ubuntu-latest
Expand Down Expand Up @@ -106,6 +107,8 @@ jobs:
publish:
name: Publish package
if: startsWith(github.ref, 'refs/tags')
permissions:
id-token: write
needs:
- format
- lint
Expand Down
4 changes: 2 additions & 2 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ version: 2

# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
os: ubuntu-24.04
tools:
python: "3.11"
python: "3.13"
# You can also specify other tool versions:
# nodejs: "19"
# rust: "1.64"
Expand Down
12 changes: 12 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Last"
given-names: "First"
orcid: "https://orcid.org/0000-0000-0000-0000"
title: "Python Package Template repository"
version: 0.0.1
doi: 10.5281/zenodo.1234
date-released: 2025-07-23
url: "https://github.com/biosustain/python_package"
36 changes: 36 additions & 0 deletions Contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Contributing code

Install the code with development dependencies:

```bash
pip install -e '.[dev]'
```

## Format code and sort imports

```bash
black .
isort .
```

## lint code

```bash
ruff check .
```

## Run tests

```bash
pytest
```

## Sync notebooks with jupytext

For easier diffs, you can use jupytext to sync notebooks in the `docs/tutorial` directory with the percent format.

```bash
jupytext --sync docs/tutorial/*.ipynb
```

This is configured in the [`.jupytext`](docs/tutorial/.jupytext) file in that directory.
696 changes: 674 additions & 22 deletions LICENSE

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ see [GitHub documentation](https://docs.github.com/en/repositories/creating-and-
You will need to find and replace occurences of

- `python_package` -> `your_package_name`
- also the folder `src/python_package`
- also the folder `src/python_package`
- `RasmussenLab` -> `GitHub_user_name` (or `organization`)
with the name of your package and GitHub user name (or organization).
with the name of your package and GitHub user name (or organization).

- look for `First Last` to see where to replace with your name
- choose a license, see [GitHub documentation](https://docs.github.com/en/repositories/creating-and-managing-repositories/licensing-a-repository)
and [Creative Commons](https://creativecommons.org/chooser/).
Replace [`LICENSE`](LICENSE) file with the license you choose.
- Update the `CITATION.cff` file with your information.

## Development environment

Expand All @@ -41,7 +42,7 @@ print(hello_world(4))
## Readthedocs

The documentation can be build using readthedocs automatically. See
[project on Readthedocs](https://readthedocs.org/projects/rasmussenlab-python-package/)
[project on Readthedocs](https://readthedocs.org/projects/rasmussenlab-python-package/)
for the project based on this template. A new project needs
to [be registered on ReadTheDocs](https://docs.readthedocs.com/platform/stable/intro/add-project.html).

Expand Down
22 changes: 22 additions & 0 deletions developing.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,28 @@ Please also update the project URL to your project:
"Homepage" = "https://github.com/RasmussenLab/python_package"
```

The template also sets a command line script entry point, which allows to run
the function `main` in the `mockup` module of the package as a command line script,
wrapping the `hello_world` function from the `mockup` module.
The template uses the standard library [argparse](https://docs.python.org/3/library/argparse.html)
module to parse parameters from the command line and creates a basic interface.

```toml
# Script entry points, i.e. command line commands available after installing the package
# e.g. implemented using argparse
# Then you can type: `python-package-hello -h` in the terminal
[project.scripts]
python-package-hello = "python_package.cli:main"
```

You can therefore run the command line script using:

```bash
python-package-hello -h
# print hello world 3 times
python-package-hello -n 3
```

## Source directory layout of the package

The source code of the package is located in the `src` directory, to have a project
Expand Down
15 changes: 8 additions & 7 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Docs creation

In order to build the docs you need to
In order to build the docs you need to

1. install sphinx and additional support packages
2. build the package reference files
3. run sphinx to create a local html version
1. install sphinx and additional support packages
2. build the package reference files
3. run sphinx to create a local html version

The documentation is build using readthedocs automatically.

Expand All @@ -17,12 +17,13 @@ pip install ".[docs]"

## Build docs using Sphinx command line tools

Command to be run from `path/to/docs`, i.e. from within the `docs` package folder:
Command to be run from `path/to/docs`, i.e. from within the `docs` package folder:

Options:
- `--separate` to build separate pages for each (sub-)module

```bash
- `--separate` to build separate pages for each (sub-)module

```bash
# pwd: docs
# apidoc
sphinx-apidoc --force --implicit-namespaces --module-first -o reference ../src/python_package
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
html_js_files = [
"https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js"
]
os.environ["PLOTLY_RENDERER"] = "notebook" # compatibility with plotly6

# https://myst-nb.readthedocs.io/en/latest/configuration.html
# Execution
Expand Down
6 changes: 5 additions & 1 deletion docs/tutorial/.jupytext
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# all notebooks in this directory are in the percent format
# all notebooks in this directory are synced percent format when typing
# (jupytext is a dev dependency)
# jupytext --sync *.ipynb
# or from root directory
# jupytext --sync docs/api_examples/*.ipynb
formats = "ipynb,py:percent"
25 changes: 15 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
# ref: https://setuptools.pypa.io/en/stable/userguide/pyproject_config.html
[project]
authors = [
{ name = "First Last", email = "first.last@gmail.com" },
]
authors = [{ name = "First Last", email = "first.last@gmail.com" }]
description = "A small example package"
name = "python_package"
# This means: Load the version from the package itself.
# See the section below: [tools.setuptools.dynamic]
dynamic = ["version", # version is loaded from the package
#"dependencies", # add if using requirements.txt
dynamic = [
"version", # version is loaded from the package
#"dependencies", # add if using requirements.txt
]
readme = "README.md"
requires-python = ">=3.9" # test all higher Python versions
Expand All @@ -17,7 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
]
license = "MIT" # https://choosealicense.com/
# Also update LICENSE file if you pick another one
license = "GPL-3.0-or-later" # https://choosealicense.com/licenses/gpl-3.0/
# # add dependencies here: (use one of the two)
# dependencies = ["numpy", "pandas", "scipy", "matplotlib", "seaborn"]
# use requirements.txt instead of pyproject.toml for dependencies
Expand All @@ -44,20 +44,19 @@ docs = [
"sphinx-copybutton",
]
# local development options
dev = ["black[jupyter]", "ruff", "pytest"]
dev = ["black[jupyter]", "ruff", "pytest", "isort", "jupytext"]

# Configure the Ruff linter: Ignore error number 501
[tool.ruff]
# https://docs.astral.sh/ruff/rules/#flake8-bandit-s
# lint.ignore = ["E501"] # Ignore line length errors
# Allow lines to be as long as (default is 88 in black)

[tool.ruff.lint]
# https://docs.astral.sh/ruff/tutorial/#rule-selection
# 1. Enable flake8-bugbear (`B`) rules
# 2. Enable pycodestyle (`E`) errors and (`W`) warnings
# 3. Pyflakes (`F`) errors
extend-select = ["E", "W", "F", "B"]
# Ignore line length errors:
# ignore = ["E501"]

[build-system]
build-backend = "setuptools.build_meta"
Expand All @@ -69,3 +68,9 @@ requires = ["setuptools>=64", "setuptools_scm>=8"]

[tool.isort]
profile = "black"

# Script entry points, i.e. command line commands available after installing the package
# e.g. implemented using argparse
# Then you can type: `python-package-hello -h` in the terminal
[project.scripts]
python-package-hello = "python_package.cli:main"
4 changes: 2 additions & 2 deletions src/python_package/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

__version__ = metadata.version("python_package")

from .mockup import hello_world
from .mockup import hello_world, saved_world

# The __all__ variable is a list of variables which are imported
# when a user does "from example import *"
__all__ = ["hello_world"]
__all__ = ["hello_world", "saved_world"]
17 changes: 17 additions & 0 deletions src/python_package/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import argparse

from .mockup import hello_world


def main():
parser = argparse.ArgumentParser(description="Python Package CLI")
parser.add_argument(
"-n",
"--repeat",
type=int,
default=1,
help="Number of times to repeat the greeting hello world",
)
args = parser.parse_args()
msg = hello_world(args.repeat)
print(msg)
28 changes: 28 additions & 0 deletions src/python_package/mockup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,33 @@ def hello_world(n: int) -> str:
-------
str
str of 'hello world' n-times

Examples
--------
>>> hello_world(3)
'hello world hello world hello world'
"""
return " ".join(repeat("hello world", n))


def saved_world(filename: str) -> int:
"""
Count how many times 'hello world' is in a file.

Parameters
----------
filename : str
The file to read

Returns
-------
int
How many times 'hello world' is in the file

Examples
--------
>>> saved_world("not-real.txt") # doctest: +SKIP
"""
with open(filename, "r") as f:
content = f.read()
return content.count("hello world")
Loading