# Hacking on objgraph

Start by geting the latest source with

    git clone https://github.com/mgedmin/objgraph

Run the test suite with

    make test

The test suite is mostly smoke tests (i.e. crashes will be noticed, subtly wrong output will be missed). I hope to improve that in the future, but don’t hold your breath. Most of the testing is done manually or semi-automatically, e.g. by running `make images` and eyeballing the results (imgdiff is handy there).

## Sending me patches

GitHub pull requests are probably the best way to send me patches. Or just email them to <marius@gedmin.as>.

I’d appreciate issues in GitHub for each proposed change, be it a bug or a feature request.

## Supported Python versions

Python 2.7 and 3.5+.

You can run the test suite for all supported Python versions with

    tox -p auto

If a test fails, often the easiest way to debug is is to compare the output visually

    make images PYTHON=pythonX.Y
    git config diff.imgdiff.command 'f() { imgdiff --eog -H $1 $2; }; f'
    git diff docs/*.png
    git checkout -- docs/*.png docs/*.dot

An easy way to get multiple Pythons versions on Ubuntu is to use Felix Krull’s “deadsnakes” PPA:

    sudo add-apt-repository -y ppa:deadsnakes
    sudo apt-get update
    sudo apt-get install python3.{6,7,8,9}

## Test coverage

As I mentioned, the tests are mostly smoke tests, and even then they’re incomplete. Install coverage to see how incomplete they are with

    make coverage

I use a vim plugin to higlight lines not covered by tests while I edit

    make coverage
    vim objgraph.py
      :HighlightCoverage

If you prefer HTML reports, run

    make coverage
    coverage html

and then browse `htmlcov/index.html`.

## Documentation

To fully rebuild the documentation, run

    make clean images docs

Please `git checkout --` the png files that haven’t changed significantly. (Many of the images include things like memory addresses which tend to change from run to run.)

imgdiff is useful for comparing the images with their older versions:

    git config diff.imgdiff.command 'f() { imgdiff $1 $2; }; f'
    git diff docs/*.png

It has a few options that may make the changes easier to see. I personally like:

    git config diff.imgdiff.command 'f() { imgdiff --eog -H $1 $2; }; f'
    git diff docs/*.png

When you add a new doctest file, remember to include it in `docs/index.txt`.

When you add a new function, make sure it has a PEP-257-compliant docstring and add the appropriate autodoc directive to `objgraph.txt`.

I insist on one departure from PEP-257: the closing `"""` should not be preceded by a blank line. Example:

    def do_something():
        """Do something.

        Return something valuable.
        """

If Emacs is broken, fix emacs, do not make my docstrings ugly.

On the other hand, if the last thing in a docstring is an indented block quote or a doctest section, it should be surrounded by blank lines. Like this:

    def do_something():
        """Do something.

        Return something valuable.

        Example:

            >>> do_something()
            42

        """

I find restview very handy for documentation writing: it lets me see how the text looks by pressing Ctrl-R in a browser window, without having to re-run any documentation building commands. The downside is that `restview` doesn’t support Sphinx extensions to ReStructuredText, so you end up with error messages all over the place. Then again this is useful for bits that can’t use Sphinx extensions, like the PyPI long description.

To preview the PyPI long description (which is generated by concatenating `README.rst` and `CHANGES.rst`) with `restview`, use this handy command:

    make preview-pypi-description

because typing

    restview -e "python setup.py --long-description"

is tedious, and bash has tab-completion for makefile rules.

## Making releases

You need write access to the PyPI package and to the Git branch on GitHub. At the moment of this writing, this means you must be me.

Run `make release` and follow the instructions. It is safe to run this command at any time: it never commits/pushes/uploads to PyPI, it just tells you what to do.

## Avoiding incomplete releases

It is important to keep MANIFEST.in up to date so that source tarballs generated with `python setup.py sdist` aren’t missing any files, even if you don’t have the right setuptools version control plugins installed. You can run

    make distcheck

to be sure this is so, but it’s not necessary – `make release` will do this every time.

(I’ve later written a standalone tool, check-manifest that can do this check for every Python package.)