Comment on page
Chapter 3: Contributing Guidelines
- 3.4 Development
- 3.4.1 Testing & Code Coverage
- 3.4.2 Documentation
- 3.4.3 Security
- 3.4.4 Repository Notes
- 3.5 Contributing to this Manual
Epispot is built on open-source contributions and we're glad that you want to contribute. First things first, if you want to contribute you will need the link to the GitHub source: https://github.com/epispot/epispot. All contributions to epispot should be submitted as pull requests on GitHub which we can then merge. In order to facilitate this review process, epispot has created a set of contributing guidelines which you can view here. The goal of this page in the manual is to further expand on some of the principles touched on in that document and make it easier to contribute to epispot. Continue reading to learn how to start.
The installation process for development is just a bit different from the standard installation process. This will make it easier to do testing and code coverage analysis locally, which will be described later. However, you can always perform these on GitHub if you prefer and just install
pip install epispot-nightly
In this case, you can skip all but the first section of this chapter. However, it will be worth it to build
epispotfrom the source as it is easier to run tests and debug your code locally.
If you don't have
gitalready, you can install it here: https://git-scm.com. Epispot uses
gitas its de-facto version control system, so it'll help to get familiar with the fundamentals of
git. After you have, make sure to learn the basics of GitHub so that you understand how to submit your pull request when it's time. The first step will be to fork the GitHub repository by clicking the "Fork" button and creating a copy under your username. Next, clone your local copy with
gitby providing the GitHub URL to your fork like this:
# replace username with your GitHub username
git clone https://github.com/username/epispot
This should create a folder containing the
epispotcodebase. Run the following commands from inside the folder to initialize the repository properly and get it up-to-date:
git checkout master
Finally, create a new branch to work on locally with:
git branch name # replace name with branch name
Choose a name that clearly states, in one or two words, what the purpose of the branch is and what it does. Good branch names are short, concise, and descriptive. Here are a few good examples:
git branch super-coverage # increases code coverage
git branch pdoc-mako # adds mako templates to pdoc
git branch docs-overhaul # recreates documentation
git branch patch-num # replace num with issue #
Now checkout your branch and you're ready to go! The next section will cover how to get ready to install epispot after you've cloned the repo.
The next thing you'll want to do after cloning the repository is set up a Python virtual environment. This will allow you to set up epispot's dependencies in a separate environment from your standard Python installation. The steps to create the virtual environment are listed below for
python -m venv epispot
# If the last command returns an error on Windows, run:
conda create -n epispot anaconda
source activate epispot
# When installing packages, use the below script
# to ensure that they are installed to the `epispot`
# virtual environment:
# conda install -n yourenvname [package]
Please note that
epispotis designed for Python 3, and it is ideal that you use a Python version greater than or equal to
3.6when creating these virtual environments.
pythoninto your shell and you should see an interactive shell similar to the one shown below pop up.
(epispot) $ python
Python 3.7.2 (default, May 6 2016, 10:59:36)
Make sure that the Python installation is greater than or equal to Python
3.6and that the
(epispot)virtual environment indicator shows up. Next, you're ready to build
epispotfrom the source.
First off, you'll need to install all package dependencies into your virtual environment. If you are using
pip, just navigate to the root repository directory and type:
pip install -r requirements.txt # Install package dependencies
pip install -r bin/requirements.txt # Install CLI dependencies
This will install
firefor the CLI. Finally, you can build
epispotfrom the source
python setup-nightly.py develop
This will create a symbolic link to the package that will prevent you from constantly re-installing
epispot. However, if you would like to reinstall
epispotevery time a change is made and keep a stable
epispotinstallation on your computer, you can run:
python setup-nightly.py install
each time you make a change. And that's all! Fire up a shell from anywhere within the repository and import
Python 3.7.2 (default, May 6 2016, 10:59:36)
>>> import epispot
Understanding any repository and package's structure is key to being able to effectively contribute to it. Luckily, epispot's structure (both internally and on a repository-scale) is quite simple and easy-to-learn.
This is probably the easiest structural element in epispot. As you can see from your local copy,
epispotis divided into five directories plus the root directory. First, let's go over the root directory (where all the dotfiles are located).
In the root directory, you'll find the following dotfiles:
The first two are for code coverage configuration.
coverage.py, epispot's code coverage analyzer tool, which directories to search and which to ignore.
.codecov.ymltells CodeCov, epispot's external code coverage reporting tool, when to fail depending on the percentage by which code coverage has decreased. The next two are for code analysis.
.deepsource.tomltells DeepSource, epispot's code quality analyzer, where the source files are.
.travis.ymlconfigures a Travis CI routine to run on push to any branch. Lastly, we make it to the
.gitignore. This is a pretty standard Python
.gitignorewhich will ignore the usual cache directories.
Apart from these dotfiles, epispot's root contains a few markdown documents, mainly intended for specific types of contributions that we'll cover in this document. It also contains a
README-nightly.mdwhere the latter is used for the
nightlypackage. The same suffix is used in
setup.py, too, where it indicates a different package version.
Finally, epispot's root directory contains the basic packaging documents, like
pyproject.toml, and various others.
The next directory is the
.githubdirectory which contains a collection of GitHub-related tools and files designed to optimize the repository. These contain automated workflow scripts that run (e.g. to create documentation), issue and pull request templates, and a
CODEOWNERSfile which is used to determine the owner of each part of the
epispotcodebase. This will be discussed later.
epispot/directories are where the source code is stored.
bin/is used for the CLI and
epispot/for the package itself. Lastly, we have the
tests/directory which contains epispot's testing suite and the
explorables/directory which contains a multitude of explorable examples.
epispot's internal structure is quite simple. Each unit of code has its own file and each subunit its own class. The main files are
__init__.py. The last, of course, initializes the package. The source code runs a relatively simple routine:
- Defines dependency check
- Imports built-in packages
- Runs dependency check
- Imports dependencies
- Imports modules
- Defines sanity check
- Defines global variables
- Runs sanity check
This routine runs every time epispot is initialized or imported. The next module we'll look at is the
models.pyfile. This will show you how to use the docstrings to understand what is going on inside the package. Epispot's code is well-documented and is optimized for additions, deletions, and modifications because it is self-explanatory. For example, if we open up the
Models.get_derivmethod, we can see its source code is simple and well-explained:
def get_deriv(self, time, system):
Return list of derivatives from each layer.
Used by `integrate()` for evaluating model predictions.
- time: Time to take derivative at
- system: System of state values (S, I, R, etc.) --> e.g [973, 12, 15]
- return: List of derivatives in the order that layers were added
derivatives = 
for layer in range(len(self.layers)):