Coverage for biobb_haddock/utils/anarcii.py: 96%
50 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-13 14:55 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-13 14:55 +0000
1#!/usr/bin/env python3
3"""Module containing the Anarcii class and the command line interface."""
5import contextlib
6import io
7import logging
8from pathlib import Path
9from typing import Optional, Union
11from biobb_common.generic.biobb_object import BiobbObject
12from biobb_common.tools import file_utils as fu
13from biobb_common.tools.file_utils import launchlogger
14from anarcii import Anarcii as AnarciiModel
17class Anarcii(BiobbObject):
18 """
19 | biobb_haddock Anarcii
20 | Wrapper class for the `ANARCII <https://github.com/oxpig/ANARCII>`_ antibody numbering tool.
21 | ANARCII numbers antibody, TCR, and other immune receptor sequences. Given an input PDB structure it renumbers it (IMGT scheme by default) and writes the renumbered PDB structure.
23 Args:
24 input_pdb_path (str): Path to the input PDB structure file. File type: input. `Sample file <https://raw.githubusercontent.com/bioexcel/biobb_haddock/master/biobb_haddock/test/data/haddock_restraints/4G6K_clean.pdb>`_. Accepted formats: pdb (edam:format_1476).
25 output_pdb_path (str): Path to the output renumbered PDB structure file. File type: output. `Sample file <https://raw.githubusercontent.com/bioexcel/biobb_haddock/master/biobb_haddock/test/data/utils/4G6K_anarcii_imgt.pdb>`_. Accepted formats: pdb (edam:format_1476).
26 properties (dict - Python dictionary object containing the tool parameters, not input/output files):
27 * **seq_type** (*str*) - ("antibody") Type of sequence to number. Values: antibody, tcr, vhh, sabdab.
28 * **mode** (*str*) - ("accuracy") Numbering mode. Values: accuracy, speed.
29 * **verbose** (*bool*) - (True) Print verbose output during numbering.
30 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files.
31 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist.
32 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory.
34 Examples:
35 This is a use example of how to use the building block from Python::
37 from biobb_haddock.utils.anarcii import anarcii
38 prop = { 'seq_type': 'antibody',
39 'mode': 'accuracy' }
40 anarcii(input_pdb_path='/path/to/structure.pdb',
41 output_pdb_path='/path/to/renumbered.pdb',
42 properties=prop)
44 Info:
45 * wrapped_software:
46 * name: ANARCII
47 * version: 2.0.0
48 * license: BSD-3-Clause
49 * ontology:
50 * name: EDAM
51 * schema: http://edamontology.org/EDAM.owl
52 """
54 def __init__(
55 self,
56 input_pdb_path: Union[str, Path],
57 output_pdb_path: Union[str, Path],
58 properties: Optional[dict] = None,
59 **kwargs,
60 ) -> None:
61 properties = properties or {}
63 # Call parent class constructor
64 super().__init__(properties)
65 self.locals_var_dict = locals().copy()
67 # Input/Output files
68 self.io_dict = {
69 "in": {"input_pdb_path": input_pdb_path},
70 "out": {"output_pdb_path": output_pdb_path},
71 }
73 # Properties specific for BB
74 self.seq_type = properties.get("seq_type", "antibody")
75 self.mode = properties.get("mode", "accuracy")
76 self.verbose = properties.get("verbose", True)
78 # Check the properties
79 self.check_properties(properties)
80 self.check_arguments()
82 @launchlogger
83 def launch(self) -> int:
84 """Execute the :class:`Anarcii <utils.anarcii.Anarcii>` object."""
86 # Setup Biobb
87 if self.check_restart():
88 return 0
89 self.stage_files()
91 # ANARCII appends the '.pdb' suffix to the output stem
92 output_pdb_path = self.stage_io_dict["out"]["output_pdb_path"]
93 pdb_out_stem = str(Path(output_pdb_path).with_suffix(""))
95 fu.log(
96 "Numbering %s with ANARCII (seq_type=%s, mode=%s)"
97 % (self.stage_io_dict["in"]["input_pdb_path"], self.seq_type, self.mode),
98 self.out_log,
99 self.global_log,
100 )
102 # Capture ANARCII output (stdout/stderr prints and logging) into the Biobb log
103 log_capture = io.StringIO()
104 log_handler = logging.StreamHandler(log_capture)
105 root_logger = logging.getLogger()
106 root_logger.addHandler(log_handler)
107 try:
108 with contextlib.redirect_stdout(log_capture), contextlib.redirect_stderr(log_capture):
109 model = AnarciiModel(
110 seq_type=self.seq_type, mode=self.mode, verbose=self.verbose
111 )
112 # number() renumbers the structure and returns the numbering
113 self.results = model.number(
114 self.stage_io_dict["in"]["input_pdb_path"], pdb_out_stem=pdb_out_stem
115 )
116 finally:
117 root_logger.removeHandler(log_handler)
119 captured = log_capture.getvalue().strip()
120 if captured:
121 fu.log("ANARCII output:\n%s" % captured, self.out_log, self.global_log)
123 # Copy files to host
124 self.copy_to_host()
126 # Remove temporal files
127 self.remove_tmp_files()
129 self.check_arguments(output_files_created=True, raise_exception=True)
130 return self.return_code
133def anarcii(
134 input_pdb_path: Union[str, Path],
135 output_pdb_path: Union[str, Path],
136 properties: Optional[dict] = None,
137 **kwargs,
138) -> int:
139 """Create :class:`Anarcii <utils.anarcii.Anarcii>` class and
140 execute the :meth:`launch() <utils.anarcii.Anarcii.launch>` method."""
141 return Anarcii(**dict(locals())).launch()
144anarcii.__doc__ = Anarcii.__doc__
145main = Anarcii.get_main(anarcii, "Wrapper for the ANARCII antibody numbering tool.")
148if __name__ == "__main__":
149 main()