Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,11 @@ needed. Write comments that explain why you do stuff, and not how you do
stuff. Use the `TODO:` flag in your comments to note something for the
future. If needed, raise an issue.

### 1.6 Creating a new module

To develop a new HADDOCK3 module follow our guidelines and templates
under `src/haddock/modules/_template_cat/_template_mod/`.

## 2. Contributing with documentation

HADDOCK3 has (will have) two sources of documentation: 1) the library
Expand Down
2 changes: 2 additions & 0 deletions devtools/build_defaults_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ def main():

# create RST pages for all modules' configuration files.
for config in configs:
if "_template" in str(config):
continue

module_name = config.parents[0].name
category = config.parents[1].name
Expand Down
30 changes: 30 additions & 0 deletions src/haddock/modules/_template_cat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Welcome!

To develop your own HADDOCK3 module follow the patterns used in other modules.

1. If your module belongs to a new category, create a folder for that category
under the `modules` folder.
1. Else, create a folder for your module inside its relevant category.
The name of that folder is the name of the module, i.e., the name used to call
the module in the haddock3 configuration files and used throughout the code base.
1. Copy the `__init__.py` file here to the new module's folder and edit it accordingly
to the instructions there.
1. Do the same for the `defaults.yaml` file.
1. You can then add any extra files needed inside your module's folder in order to
develop your module fully.
1. If your module requires any extra libraries, describe how to install those libraries
in the `docs/INSTALL.md` file. Unless approved by the Haddock Team, do not add
those dependencies to the `requirements.*` files.
1. HADDOCK3 has already many features related to IO, subprocess run, sending jobs,
etc. Please, look around the `libs` folder for pertinent functions, but, above all,
feel welcomed to reach out to us with any doubts.
1. Please write also tests for your module. Our testing machinery already
tests for the common patterns, for example, inspecting the `defaults.yaml` file.
But you should write any additional tests to ensure that your module works properly.
See other examples in the `tests/` folder.
1. Finally, add an example of how to use your module in the `examples/` folder.
The example should have a short sampling scheme. Name the config file ending with
`-test.cfg`.

Thanks, and we are happy to help you! :-)
@ The Haddock Team
140 changes: 140 additions & 0 deletions src/haddock/modules/_template_cat/_template_mod/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"""
Template module
===============

Use this template to implement your own HADDOCK3 module.

In this docstring, please write the documentation explaining what the module
does technically, scientifically, and its purpose.

Anything you want to write to describe the module, also do it here.
You should use restructureText syntax:

https://docutils.sourceforge.io/docs/user/rst/quickstart.html
"""
# Import here what you need
from pathlib import Path

# In case you need to import a Python library that is a run-time dependency,
# you should import it inside the `_run` method to avoid import errors for those
# users not using the new module, thus not having its dependencies installed.

# If your module does not use CNS, import the following
from haddock.modules import BaseHaddockModule

# If your module uses CNS import
from haddock.modules.base_cns_module import BaseCNSModule


# this is mandatory, don't erase nor edit these lines
RECIPE_PATH = Path(__file__).resolve().parent
DEFAULT_CONFIG = Path(RECIPE_PATH, "defaults.yaml")


# this is the main class of the module. It should be named exactly as this.
class HaddockModule(BaseHaddockModule):
# inherit from BaseCNSModule in case the module uses CNS
"""
Here you can write any extra documentation you wish about the class.

Use numpydoc syntax:

https://numpydoc.readthedocs.io/en/latest/format.html
"""

# this is mandatory
name = RECIPE_PATH.name

# this __init__ structure is mandatory, but you can extend it to the
# module's needs as long as you keep the main structure. Surely,
# *ignore and **everything can be edited to fit your needs.
def __init__(
self,
order,
path,
*ignore,
init_params=DEFAULT_CONFIG,
**everything,
):

# if your module uses CNS you might need to define where the main CNS
# script is localted. See examples in `topoaa`, `emref`.
# else leave it out.
# cns_script = Path(RECIPE_PATH, "cns", "main.cns")

# use one of the following:
# if the module does not use CNS:
super().__init__(order, path, init_params)

# if the module uses CNS:
super().__init__(order, path, initial_params, cns_script=cns_script)

@classmethod
def confirm_installation(cls):
"""Confirm if the module is ready to use."""
# here, you should write any code needed to confirm that all the
# dependencies required by your module are installed.
# this class method will be executed when HADDOCK3 starts.

# if you module does not import any run-time dependency, just leave
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if you put an import here that tries to import a dependency that is not installed, will it handle the error?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed, thanks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the chek @rvhonorato implemented in the optint PR #515 . Maybe we can copy it here? commented out of course

# this method blank
return

# here is where the module magic will happen
def _run(self):
# Import here any Python run-time dependencies that your module needs.

# you can refer to other modules as examples to see how they perform.
# Likely, the new module will need to load the output from the previous
# module. For example:
models_to_use = self.previous_io.retrieve_models()

# once the module loads, you can access its parameters in
# `self.params`. See more in the BaseHaddockModule class.
# `self.params` is a dictionary that contains both the general
# parameters such as the number of processors
# `self.params['ncores']` parameters as well as those
# defined in your `defaults.yml`

# Add here all the magic that your module does. You can split this part
# into many functions, classes, or add any extra files or subfolders to
# the module's folder as you may need. You can even import other modules
# if needed.

# If you module creates models, the line below is almost mandatory.
# see other modules, such as topoaa or mdref, emref to see how they
# handle `output_models`.
# the PDB references in `list_of_created_models` below must be instances
# of the `libs.libontology.PDBFile` class.

output_model_list = your_function(models_to_use, self.params)
# output_model_list = [(pdb, psf, score), ...]

list_of_created_models = []
for element in output_model_list:
pdb, psf, score = element
# IMPORTANT: pass `file_name=Path.name`

# alternatively to the strategy below, you can use the
# `libs.libcns.prepare_expected_pdb` function if it better fits
# your case. See `emref` and `mdref` for examples.
pdb_object = PDBFile(
Path(pdb).name,
topology=TopologyFile(Path(psf).name, path="."),
path=".")

pdb_object.score = score
list_of_created_models.append(pdb_object)

# final section
self.output_models = list_of_created_models
self.export_output_models()
# in case your module considers possible tolerance for generated models,
# you can use:
# self.export_output_models(faulty_tolerance=self.params["tolerance"])


# Finally, the haddock module's class inherit from BaseHaddockModule. It is
# important that you go through the BaseHaddockModule interface to understand
# it's functionalities. If you find any spots of missing documentation, let us
# know. Thanks! @ The Haddock Team
105 changes: 105 additions & 0 deletions src/haddock/modules/_template_cat/_template_mod/defaults.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# this is an example of the default parameters
# add here the parameters of your module. You can follow examples
# in other default config files. Each parameter type has it's own specific extra
# fields. Below an example of parameters of different types:
# explevel can only be easy, expert, guru

# You may wish to read our functionalities in "extended parameters":
# https://github.com/haddocking/haddock3/blob/main/src/haddock/gear/expandable_parameters.py#L1-L73

# INTEGER parameter
random_seed:
default: 42
type: integer
min: 0
max: 999
title:
short:
long:
group: ""
explevel: easy

# FLOAT parameter
indpb:
default: 0.2
type: float
min: 0
max: 1
precision: 2
title:
short:
long:
group: ""
explevel: expert

# LIST parameter
region:
default: []
type: list
minitems: 0
maxitems: 1000
title:
short:
long:
group: ""
explevel: guru

# STRING parameter with CHOICES
initial_mutation:
default: keep
type: string
minchars: 0
maxchars: 7
choices:
- alanine
- random
- keep
title:
short:
long:
group: ""
explevel: guru

# STRING parameter without CHOICES
target_chain:
default: "A"
type: string
minchars: 1
maxchars: 1
title:
short:
long:
group: ""
explevel: hidden

# a DICTIONARY parameter
# these parameter are tricky to maintain, use them only if strickly needed.
dict_like_par:
explevel: easy
title: Example of a dictionary mdule
short: Some short explanation on dick_like_par
long: Some long explanationon dick_like_par
group: "the group it belongs"
# here are the parameters belonging to the `dict_like_par` key
somepar:
default: 0.2
type: float
min: 0
max: 1
precision: 2
title:
short:
long:
group: ""
explevel: expert

otherpar:
default: []
type: list
minitems: 0
maxitems: 1000
title:
short:
long:
group: ""
explevel: guru
4 changes: 4 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ per-file-ignores =
tests/*.py:D103
tests/test_gear_preprocessing.py:E501,D103,W291
src/haddock/modules/*/*/__init__.py:D205,D400
exclude =
src/haddock/modules/_template_cat/_template_mod/__init__.py
docstring-convention = numpy


Expand All @@ -152,3 +154,5 @@ known_third_party =
pytest
pdbtools
yaml
skip =
src/haddock/modules/_template_cat/_template_mod/__init__.py