Developer Notes

We welcome contributions to E3FP! These notes are designed to help developers contribute code

Authoring Code

Code Formatting

E3FP’s code should be readable. To ensure this, we rigorously follow the PEP8 style conventions and PEP257 docstring conventions, which maximize readability of the code and ease of future development. You may check your code for conformation to these conventions with the pycodestyle and pydocstyle utilities, respectively. Where the code is necessarily complicated, inline comments should reorient the reader.

Utility Methods and Classes

Three sets of utility methods and classes are provided: e3fp.util, e3fp.conformer.util, and e3fp.fingerprint.util. These provide general and often-used functionality in their corresponding packages. Additionally, they provide E3FP-specific errors and exceptions.

Warnings and Errors

By default, warnings in Python are silent. We therefore provide a warning base class e3fp.util.E3FPWarning that is not silent by default. We provide several general warnings:

E3FPDeprecationWarning

warns when a deprecated method is called or class is instantiated.

See also

Deprecation

E3FPEfficiencyWarning

warns when a method, module version, or combination of parameters is known to be inefficient.

Note

If possible, the warning message should advise on a more efficient approach.

E3FP-specific errors should inherit e3fp.util.E3FPError base class. Several fingerprinting-specific errors are defined in e3fp.fingerprint.util.

Deprecation

Whenever changing the interface or behavior of a user-facing method or class, it is proper to deprecate it for at least one release, so that the users have time to update their scripts accordingly. A deprecated method should providing an e3fp.util.E3FPDeprecationWarning, notifying the user in which release to expect the method or class to be removed, and updating the documentation accordingly. This functionality is automated with the e3fp.util.deprecated decorator, as shown in this example:

>>> import sys
>>> sys.stderr = sys.stdout
>>> from e3fp.util import deprecated
>>> @deprecated("1.1", remove_version="1.3", msg="Function no longer needed.")
... def deprecated_method():
...     """A method to demonstrate method deprecation."""
...     pass
>>> deprecated_method()
...: E3FPDeprecationWarning: Function `my_function` was deprecated in 1.1 and will be removed in 1.3. Function no longer needed.

In the api documentation, the method will appear as:

deprecated_method()

Note

Deprecated in e3fp 1.1. deprecated_method will be removed in e3fp 1.3. Function no longer needed.

A method to demonstrate method deprecation.

Note

If no remove_version is specified, then the remove version defaults to the next release after deprecation. For example, if the method was deprecated in 1.1, it is by default marked for removal in 1.2.

Contributing Code

Before contributing code to E3FP, it is advisable for major modifications to submit an issue to the issue tracker to enable other developers to contribute to the design of the code and to reduce the amount of work necessary to conform the code to E3FP’s standards. After writing the code, create a pull request. This is best even if you have push access to the E3FP repo, as it enables the test suite to be run on the new code prior to merging it with the remaining code base.

Writing Tests

The standard in E3FP is to commit a test for new functionality simultaneously with the new functionality or within the same pull request. While this slows development, it prevents building a large backlog of untested methods and classes.

These should ideally be unit tests, though for some complicated functionalities, such as fingerprinting, integration tests are also necessary. For these complicated functions, specific units may still be tested using unittest.mock. For example, unittest.mock.patch() may be used to force a high level method to produce a specific output. For examples, see the fingeprinting tests.

Continuous Integration

E3FP uses GitHub Actions for continuous integration. This ensures that each commit and pull request passes all tests on a variety of a systems and for all supported versions of Python. Additionally, GitHub Actions updates code coverage on Codecov and tests all usage examples in the documentation using doctest.

Documentation

In general, it is best to document the rationale and basic usage of a module, class, or method in its docstring instead of in a separate documentation file. See, for example, the docstring for e3fp.fingerprint.db.FingerprintDatabase. We use a variety of tools to ensure that our documentation is always up-to-date. The official documentation is hosted on ReadtheDocs and is automatically generated when new code is committed to the repository.

Documenting Code

E3FP uses NumPy’s docstring conventions for all docstrings. These are parsed by Sphinx using Napoleon. All usage examples must be fully functional, as these are tested using doctest.

The purpose of a docstring is to explain the purpose of a class/method, any relevant implementation details, its parameters, its attributes, its outputs, and its usage. The goal is clarity. For self-evident methods with descriptive variables, a simple one- ine summary is all that is needed. For complicated use cases, often involving other methods/classes, it is better to document the usage elsewhere in the documentation.

Documentation Usage

Coming soon.

Releasing Code