We welcome contributions to E3FP! These notes are designed to help developers
contribute code
Authoring Code
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.
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.