Open-source project
uwescience/shablona avatar
uwescience/shablona

shablona: a project template for scientific Python that explains itself

A template for small scientific python projects

610 stars139 forksJupyter NotebookMIT

At a glance

What is it?
shablona is a small scientific Python project used as a template, and its real content is the reasoning: a package layout, a data folder, pytest tests, a Sphinx doc directory, a flake8 target and a make target for running tests with coverage. It is MIT licensed and generated with a module whose code does curve fitting on psychophysical data.
Who is it for?
Adopt shablona if you are starting a small scientific Python project and want a layout, a lint setup, a test target and a documentation scaffold that other people in the ecosystem will recognise, especially if you are handing the work to collaborators or reviewers. Skip it if you need a modern packaging setup, since it still uses setup.py with a minimal pyproject, or if you need a Jupyter-first workflow beyond the example notebooks it ships.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Jupyter Notebook, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A template that argues for its own conventions

shablona is a template project for small scientific Python projects, and the recommendations it makes follow the standards and conventions of much of the scientific Python ecosystem. The stated reason is practical rather than aesthetic. Following these standards and recommendations will make it easier for others to use your code, and can make it easier for you to port your code into other projects and collaborate with other users of the ecosystem. That is the pitch of a template, and it is a different pitch from a starter kit of convenience wrappers. The README does not open with a feature list, it opens by explaining all the different moving parts that make up a small scientific Python project and the elements which allow us to share it with others, test it, document it and track its evolution. You use it as a template by clicking the green use this template button at the top of the front page of the repository, so the result is a new repository with the layout already in place and the project name substituted. The example code inside is deliberately trivial, a little curve fitting on data from a psychophysical experiment, because the point is the structure and not the science.

The package layout and the import shim

The project structure the README presents is the convention it is teaching. At the top there is a README.md, a setup.py, a .travis.yml, an appveyor.yml, a .mailmap, a LICENSE and a Makefile, plus a doc/ directory and an ipynb/ directory. Inside is a package directory with an __init__.py, a shablona.py, a due.py, a data/ folder and a tests/ folder. The README is honest that the structure is a bit confusing at first, and explains why it exists. It is a simple way to create a structure where typing import shablona as sb in an interactive session makes the classes and functions available in the sb namespace, which requires the __init__.py to pull everything in.

python
    from .shablona import *

Inside the module the convention is that all functions are either imported from other places or defined in lines that precede the lines that use them, so a reader who sees a name knows the definition appears earlier in the file. The example module follows that pattern, with the main classes at the bottom of the file making use of functions defined in preceding lines. The file also contains a due.py, which is a lightweight dependency scheduler the template includes so that recurring jobs have a home. The stated principle behind the whole approach is that code will probably be read more times than it will be written, and that you should make it easy to read for others and for yourself when you come back to it.

Data lives next to the code, and there is a standard path to it

The data question gets a specific answer rather than a general principle. In this case the project data is rather small and recorded in csv files, so it can be stored alongside the module code, and even if the data you are analysing is too large to be tracked with GitHub, you might still want to store some data for testing purposes. The recommendation is a data folder inside the package, with a standard filesystem location computed at import time so the test scripts and the analysis scripts agree on where the files are.

python
    import os.path as op
    import shablona as sb
    data_path = op.join(sb.__path__[0], 'data')

Using the package's own __path__ to locate the data is the detail that makes this work after installation, since it resolves relative to wherever the package ended up on disk rather than to the current working directory. The alternative arrangement, keeping data outside the package and pointing at it with a relative path, is the one that breaks the moment someone runs the code from a different directory or installs the package, and this template avoids it. The examples directory in the repository carries two worked examples, a model_fitting folder and an sg_tutorial folder, with a README.txt alongside them, which is the fastest way to see how the layout is meant to be used rather than only described.

Testing for scientists who did not write a specification first

The testing section is the most argued part of the README, and the argument is well worth reading whatever you think of the tooling. It starts from a practice most scientists already have, running every new function and examining the inputs and the outputs, and describes automated testing as making that informal practice formal and automated. Then it explains why scientists rarely write a specification, because when they start writing code they do not yet know what they will discover in their data, and those discoveries might affect how the software evolves, and because scientific code often needs to be good enough to cover the use case rather than any possible use case. The resolution offered is that testing serves as a way to provide a reader of the code with a very rough specification, in the sense that it at least specifies certain input and output relationships that will certainly hold. The recommended tool is pytest, with the py.test application traversing the directory tree for files matching test_*.py and then looking for functions matching test_*. The template also distinguishes unit tests from end-to-end tests, the latter checking that particular values evaluate to the same values over time, and names one such test, test_params_regression. The README's framing of regressions is memorable, calling them canaries in the coal mine that tell you to examine changes in your dependencies or the platform you are running on.

A Makefile that runs the linter and the tests with coverage

The Makefile is small and it encodes two habits, checking style and running tests, in a form that works the same on every machine that has make.

code
flake8:
	@if command -v flake8 > /dev/null; then \
		echo "Running flake8"; \
		flake8 flake8 --ignore N802,N806 `find . -name \*.py | grep -v setup.py | grep -v /doc/`; \
	else \
		echo "flake8 not found, please install it!"; \
		exit 1; \
	fi;
	@echo "flake8 passed"

test:
	py.test --pyargs shablona --cov-report term-missing --cov=shablona

The lint target follows the PEP8 code formatting standard, enforced by running flake8, which the README describes as automatically checking the code and reporting violations of the standard along with other general code hygiene issues. The two ignored codes, N802 and N806, are the two places where scientific code legitimately breaks the naming convention, a function name in capitals and a variable name that shadows an imported module. The test target runs pytest against the installed package with coverage reporting that shows which lines were not hit, using the term-missing report. The setup.py reads the version and release information from a version.py file inside the package, and the pyproject.toml is minimal, declaring only the setuptools and wheel build requirements, so the packaging is still setup.py based.

Documentation, notebooks and the age of the toolchain

The doc/ directory holds a Makefile and a conf.py for Sphinx, along with a sphinxext/ directory for extensions and a _static/ directory, which is a standard Sphinx documentation tree. The ipynb/ directory at the top level holds notebooks, which is the other half of the scientific Python workflow, since a paper or a report is often a notebook that mixes prose, figures and computation. The wider repository has a .coveragerc for coverage configuration, requirements.txt and requirements-dev.txt, a scripts/ directory, a pyproject.toml and a setup.py. The runtime requirements are the four names you would expect for scientific work, with numpy, scipy, matplotlib and pandas listed. The template is MIT licensed, has a build badge for Travis CI and an appveyor.yml for Windows, and a .mailmap for mapping contributors onto a canonical identity, which is the kind of small piece of infrastructure that matters when several people contribute to a scientific codebase. The dates are worth noting for anyone picking this up today. The last push to the repository was on 2026-04-13, the project has no GitHub releases, and the build badge points at Travis CI and the pyproject pins setuptools at 24.2.0 or newer, so the conventions in the README are sound but the specific tooling versions are from an earlier era and you will likely need to adjust them.

Editorial conclusion

Adopt shablona if you are starting a small scientific Python project and want a layout, a lint setup, a test target and a documentation scaffold that other people in the ecosystem will recognise, especially if you are handing the work to collaborators or reviewers. Skip it if you need a modern packaging setup, since it still uses setup.py with a minimal pyproject, or if you need a Jupyter-first workflow beyond the example notebooks it ships. Verify first that the tool versions it assumes still match your environment, particularly pytest and flake8, and that the two example scripts, model_fitting and sg_tutorial, show you the shape of use it was written for.

Frequently asked questions

How do I use shablona as a template for my own project?

Click the green use this template button at the top of the front page of the repository, which creates your own repository with the same structure. The layout it sets up is a package directory with an __init__.py, a module file, a data folder and a tests folder, plus doc, ipynb, a Makefile, setup.py and CI configuration.

What testing and linting does shablona set up?

The Makefile has a flake8 target that checks PEP8 style and general code hygiene, ignoring N802 and N806, and a test target that runs py.test with coverage reporting including missing lines. The README recommends pytest, with test files named test_*.py and test functions named test_*, and distinguishes unit tests from regression tests such as test_params_regression.

Where should data files live in a shablona-style project?

In a data folder inside the package, with the location resolved from the package path rather than the working directory. The README shows the pattern using os.path.join with sb.__path__[0] and a data subdirectory, and notes that even when the real dataset is too large to track, some data should still be stored for testing purposes.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. uwescience/shablona on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/uwescience-shablona.svg)](https://hysenlabs.com/projects/uwescience-shablona)

Was this useful?