.. _hacking:

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
<http://pypi.python.org/pypi/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 <https://github.com/mgedmin/objgraph/issues>`_
for each proposed change, be it a bug or a feature request.


Supported Python versions
-------------------------

Python 2.4 through 2.7, as well as 3.x.

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

  make test-all-pythons

or with `detox <http://pypi.python.org/pypi/detox>`_ (which will be faster,
since it runs the tests in parallel).

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 Pythons 2.4 through 2.7 (and 3.x) on Ubuntu is to use Felix
Krull's "`deadsnakes <https://launchpad.net/~fkrull/+archive/deadsnakes>`_"
PPA::

  sudo add-apt-repository ppa:fkrull/deadsnakes
  sudo apt-get update
  sudo apt-get install python2.{4,5,6,7} python3.{1,2,3}


Test coverage
-------------

As I mentioned, the tests are mostly smoke tests, and even then they're
incomplete.  Install `coverage <http://pypi.python.org/pypi/coverage>`_
to see how incomplete they are with ::

  make coverage

I use a `vim plugin <http://mg.pov.lt/vim/plugin/py-coverage-highlight.vim>`_
to higlight lines not covered by tests while I edit ::

  mkdir -p ~/.vim/plugin
  cd ~/.vim/plugin
  wget http://mg.pov.lt/vim/plugin/py-coverage-highlight.vim
  cd ...
  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 <http://pypi.python.org/pypi/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
<http://www.python.org/dev/peps/pep-0257/>`_-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 <http://pypi.python.org/pypi/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
<http://docs.python.org/distutils/sourcedist.html#manifest-template>`_ 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
<https://pypi.python.org/pypi/check-manifest>`_ that can do this check for
every Python package.)
