Contributing ============ Basic workflow: - Fork the `repository `__ - Develop on a branch - Run tests - Submit a `merge request `__ Setting up your environment --------------------------- Set up and activate a virtualenv:: virtualenv gracedb-client-dev source gracedb-client-dev/bin/activate Install the package in `development mode `__. In the repository root, run:: python setup.py develop Then, install some additional tools which are useful for development:: pip install -r requirements-dev.txt Guidelines ---------- Unit tests ~~~~~~~~~~ New contributions should have 100% test coverage. If they include interactions with the server, corresponding integration tests should be included, as well. Unit and integration tests are required for the command-line client, too, not just the main Python modules! Code style ~~~~~~~~~~ All commits must pass linting checks. The CI configuration does this check after pushing a commit to the remote repository, but it's a good idea to catch issues locally first. To help with this, you can install a pre-commit hook for linting with ``flake8``:: flake8 --install-hook=git git config --bool flake8.strict true To run the linting process manually, you can do:: flake8 *.py ligo/ from the root of the repository. Command-line client ~~~~~~~~~~~~~~~~~~~ If you add some useful, non-private functionality to the client class, something similar should probably be added to the command-line client, as well. Running tests ------------- This package includes a set of unit tests which cover much of the available functionality. There is also a set of integration tests which can be used to test interactions with a GraceDB server. However, this requires superuser permissions on the server, so it will not be possible for most users. In the future, it may be possible to stand up a GraceDB instance on your local machine and run the integration tests that way, but that is not presently available. Basic testing ~~~~~~~~~~~~~ To run the unit tests with the current version of Python, do:: python setup.py test To run the integration tests, you can do:: python setup.py test --addopts "-m integration" A pytest mark is also used to distinguish tests of the command-line interface. If you want to run those tests specifically, you can do:: # All CLI-related tests python setup.py test --addopts "-m cli" # Only unit tests of CLI python setup.py test --addopts "-m 'cli and not integration'" Comprehensive testing ~~~~~~~~~~~~~~~~~~~~~ This package includes a `configuration `__ for using `tox `__ to automate testing with different versions of Python. The current configuration uses Python 2.7 and Python 3.5-3.7, if available on your system. ``tox`` should already be installed from the ``requirements-dev.txt`` file. However, if you still need to install it, you can do so with ``pip``:: pip install tox To run all combinations of unit and integration tests with all versions of Python, go into the root of the repository and do:: tox To run the unit tests only, with all Python versions:: tox -e $(tox -l | grep unit_test | paste -sd "," -) To run the client integration tests only, with all Python versions:: tox -e $(tox -l | grep integration_test | paste -sd "," -) To run all unit and integration tests with a specific Python version:: tox -e $(tox -l | grep py27 | paste -sd "," -) To run the unit tests with all compatible versions of Python, do:: tox -e $(tox -l | grep unit_test | paste -sd "," -) Any versions of Python which are included in the ``tox`` configuration but not available on your system will be skipped. Adding commands to the command-line client ------------------------------------------ The command-line client uses a custom metaclass to facilitate registration of new commands to the base command-line client class. This section gives a brief overview of how to add new commands to the command-line client. One-part commands ~~~~~~~~~~~~~~~~~ These commands are things like ``gracedb ping`` and ``gracedb show``, which only feature a verb and no noun in the base command (an exception is ``gracedb credentials``). These should inherit from :py:class:`ligo.gracedb.cli.commands.base.RegisteredSubCommandBase` and be put in ``ligo/gracedb/cli/commands/subcommands.py``. The ``name`` attribute defines how the command will be called (``gracedb [name]``). One-part commands need to be imported in ``ligo/gracedb/cli/commands/__init__.py`` to be registered. Use the existing one-part commands as examples. Two-part command bases ~~~~~~~~~~~~~~~~~~~~~~ These are commands like ``gracedb add`` and ``gracedb get``, which don't do anything on their own, but require an additional noun argument to specify what you are adding or getting to complete the command. Commands like this are typically defined in their own file in ``ligo/gracedb/cli/commands/``. A variable called ``registry`` should be defined as an empty list just below the imports in this file and assigned to the ``subcommands`` attribute of the new command class. A new command base should inherit from :py:class:`ligo.gracedb.cli.commands.base.RegisteredCommandBase`. The ``name`` attribute defines how the command will be called (``gracedb [name]``). Command bases need to be imported in ``ligo/gracedb/cli/commands/__init__.py`` to be registered. Use the existing command bases as examples. Two-part commands ~~~~~~~~~~~~~~~~~ These are commands like ``gracedb add event`` and ``gracedb get superevent`` and are associated with a two-part command base. For example, the class which defines ``gracedb add event`` (:py:class:`ligo.gracedb.cli.commands.add.AddEventCommand`) is defined in the same file as the class which defines ``gracedb add`` and is automatically registered in its ``subcommands`` attribute using a custom metaclass. The ``name`` attribute defines how the command will be called (``gracedb [base command name] [name]``). These commands should inherit from :py:class:`ligo.gracedb.cli.commands.base.RegisteredSubCommandBase` and have their ``_registry`` attribute set to be the ``registry`` variable declared at the top of the module. Use the existing two-part commands as examples.