How to Set Up Your Environment For PINT Development

See also How to Contribute to PINT

Working on PINT code requires a few more tools than simply running PINT, and there are a few settings that can make it much easier. Some of what follows will depend on your editor, but most of it is possible in any modern programmer’s editor, including Sublime Text, Atom, Visual Studio Code, PyCharm, vim/neovim, and emacs. (Okay those last two are only arguably modern but they are extensible enough that they can be made to do most of the things described here.) Some of these tools may also be available in more basic editing environments like the Jupyter notebook, the JupyterLab text editor, and Spyder.

What you should expect your editor to do

It may take some configuration, but once set up any modern editor should be able to do the following:

  • Highlight python syntax.

  • Flag syntax or style errors (line length, unused/undefined variables, dubious exception handling) visually as you edit.

  • Offer completions for any identifier (keyword, function, variable, et cetera) you start typing.

  • Reformat text into the black code style with a keypress.

  • Sort your imports into the standard arrangement with a keypress.

  • Jump to the definition of a function, class, or method with a keypress.

  • Obey .editorconfig settings.

A little Googling should reveal how to get all this working in your favorite editor, but if you have some helpful links for a particular editor feel free to add them to the documentation right here.

Command-line tools and automation

PINT is developed with git and on GitHub. Some operations are presented graphically in the web interface, but in many cases you will want to do something direct on your local machine. Having the right tools available and configured should make this easy.

In your development virtualenv, install the development requirements:

pip install -Ur requirements_dev.txt

Set up a few tools to make the git repository behave better. pre-commit runs various things, like check the text formatting, making sure you didn’t accidentally include some huge binary file, and so on, when you go to commit something to git:

pre-commit install

Configure git so git blame ignores large-scale reformatting commits in favour of changes to the actual contents:

git config blame.ignoreRevsFile .git-blame-ignore-revs

How To Build and Test From the Command Line

To run the whole test suite (on all the cores of your machine):

pytest -n auto

To run tests on just one file:

pytest tests/test_my_new_thing.py

To run just one test:

pytest tests/test_my_new_thing.py::test_specific

To test everything but start with tests that failed last time, stopping when something goes wrong (this is great when you’re trying to fix that one bug; if you haven’t you’ll get new error messages, if you have, it’ll continue on to run all the tests):

pytest --ff -x

To drop into the python debugger at the point where a test fails so you can investigate, for example go up and down the call history and inspect local variables:

pytest --pdb -x

The python debugger also allows you to step through your code, put in breakpoints, and many other things. It can save a ton of time compared to putting print statements in and rerunning your code, especially if the code takes a while and you don’t know exactly what you want to inspect.

To run the whole test suite in fresh installs on several python versions, and also rebuilt the notebooks and documentation as well as compute combined code coverage for all the versions:

tox

To run tests on multiple python versions and build the documentation in parallel:

tox --parallel=auto

If this finds a problem in just one python environment that doesn’t appear in your development environment, you can run just the problem environment:

tox -e py27

You can also run other things in the environments tox uses, including interactive python sessions (though these will include only PINT’s installation requirements, so no IPython):

tox -e py27 -- pytest --ff --pdb -x
tox -e py27 -- pytest tests/test_my_new_thing.py
tox -e py27 -- python

To automatically run black on all of PINT’s code:

black src/ tests/

Under examples/ there are a few Jupyter notebooks. These actually get incorporated into the online documentation (you may have seen them). To avoid headaches, we don’t store these as notebooks on github but as special markdown files. If you are using jupyter or jupyter-lab, it should be smart enough to synchronize these between the storage format and normal notebooks, but if there is any confusion, try make notebooks, which synchronizes the two formats and runs all the notebooks to fill in the outputs. If something goes wrong, try jupytext --sync, which synchronizes the code between the notebooks and the storage format but doesn’t run the notebooks.

Coping with git

To import any changes that have been made to the PINT distribution:

git fetch --all
git checkout master
git merge upstream/master
git push

To switch between branches:

git checkout a-branch
git checkout another-branch
git checkout master

These are very fast but they do change all the source code files to reflect what they look like in the branch you’re switching to. If you have them open in editor windows your editor may give you surprised messages as the files change under it.

To start a new branch for a thing:

git checkout master
git checkout -b a-thing

To send your changes to the current branch to your fork of the PINT repository:

git push

If this is the first time you’ve done this with a new branch git will refuse because it doesn’t exist in your fork on GitHub. It will print out a command to create the branch on your GitHub. Just paste that. It will look like:

git push --set-upstream origin a-thing

If you now go to GitHub and poke around a bit, say on the Issues or Pull Requests page, GitHub will have a button that says essentially “you just pushed a new branch, do you want to make it into a pull request?” If your branch was meant to go into PINT, this is what you want to do, so click that button. GitHub will allow you to enter a more detailed description and then create a Pull Request that can be seen on the main PINT pages. People can then comment on the pull request (“PR”) in general or specific lines of code you have changed in particular.

If you are working on a pull request and the main PINT development has changed in a way that conflicts with it (itHub will tell you on the pull request page), you want to rebase your pull request. There are more details you can look up, but in short, update master as above, then:

git checkout a-thing
git rebase master

This will attempt to take your branch, a-thing, look at how it differs from where you created it from, and then apply those same changes to the new master. This will sometimes run into trouble, which you have to resolve before you can continue normal work. Once you have finished the rebase, you will need to push it to your GitHub. This is a little more complicated than usual because you are changing not just the current state of the code but the history that led to the current state of the code in your branch. This may mess up comments that people have attached to particular lines of your pull request, so pick a quiet moment to do this. You will need to tell git that yes, you really mean to change the public history:

git push -f

If you are digging through the source code and see something strange in a file, and if you think “who thought that was a good idea?”, you can ask git who last modified each line in a file, and when:

git blame src/pint/utils.py

To track and checkout another user’s branch (pull request):

git remote add other-user-username https://github.com/other-user-username/pint.git
git fetch other-user-username
git checkout --track -b branch-name other-user-username/branch-name

If you make a mistake and get git into a strange or awkward state. Don’t panic, and try Googling the specific error message. git is quite thorough about keeping history around, so you can probably undo whatever has happened, especially if you have been pushing your changes to GitHub. If it helps, there is Dang it, git! (there is a ruder version which may feel more appropriate in the moment), or the git choose-your-own-adventure (which is extremely useful as well as amusing).

Tagging and Releasing versions

This portion is only for developers with permission to modify the master NANOGrav repository!

Tagging

The current version string is available as pint.__version__

PINT uses MAJOR.MINOR.PATCH versioning inspired by, but not strictly following, Semantic Versioning. PINT uses versioneer.py to make sure that pint.__version__ is available in the code for version checking. This constructs the version string from git using tags and commit hashes.

To create a new tagged version of PINT (assuming you are going from 0.5.0 to 0.5.1):

You can see what tags already exist like this:

git tag --list

First make sure you are on the PINT master branch in the nanograv/PINT repository and your working copy is clean (git status), then:

git push origin

Now wait 15 minutes and check that travis-ci says that the build is OK, before tagging! If needed, push any bug fixes.

Next, check the unreleased CHANGELOG (CHANGELOG-unreleased.md) and make sure all the significant changes from PRs since the last release have been documented. Move these entries to the released CHANGELOG (CHANGELOG.md), and change title of the newly moved entries from “Unreleased” to the version number you are about to tag and commit. But don’t yet push.

When tagging, always use “annotated tags” by specifying -a, so do these commands to tag and push:

git tag -a 0.5.1 -m "PINT version 0.5.1"
git push origin --tags

Releasing

To release, you need to have your PyPI API token in ~/.pypirc. You must be on a clean, tagged, version of the nanograv/master branch. Then you can just:

make release

This will build the distribution source and wheel packages and use twine to upload to PyPI.

Doing this will also trigger conda-forge to create a new PR for this release. Once this passes tests, it will need to be merged.

As a last step, go to the Releases tab on github and Draft a new release.