Coverage for biobb_structure_utils/utils/structure_check.py: 76%

58 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-28 11:54 +0000

1#!/usr/bin/env python3 

2 

3"""Module containing the StructureCheck class and the command line interface.""" 

4 

5import argparse 

6from typing import Optional 

7 

8from biobb_common.configuration import settings 

9from biobb_common.generic.biobb_object import BiobbObject 

10from biobb_common.tools import file_utils as fu 

11from biobb_common.tools.file_utils import launchlogger 

12 

13from biobb_structure_utils.utils.common import ( 

14 _from_string_to_list, 

15 check_input_path, 

16 check_output_path_json, 

17) 

18 

19 

20class StructureCheck(BiobbObject): 

21 """ 

22 | biobb_structure_utils StructureCheck 

23 | This class is a wrapper of the Structure Checking tool to generate summary checking results on a json file. 

24 | Wrapper for the `Structure Checking <https://github.com/bioexcel/biobb_structure_checking>`_ tool to generate summary checking results on a json file from a given structure and a list of features. 

25 

26 Args: 

27 input_structure_path (str): Input structure file path. File type: input. `Sample file <https://github.com/bioexcel/biobb_structure_utils/raw/master/biobb_structure_utils/test/data/utils/2vgb.pdb>`_. Accepted formats: pdb (edam:format_1476), pdbqt (edam:format_1476). 

28 output_summary_path (str): Output summary checking results. File type: output. `Sample file <https://github.com/bioexcel/biobb_structure_utils/raw/master/biobb_structure_utils/test/reference/utils/summary.json>`_. Accepted formats: json (edam:format_3464). 

29 properties (dic - Python dictionary object containing the tool parameters, not input/output files): 

30 * **features** (*list*) - (None) Features to summarize. If None, all the features will be computed. Values: models (multiple molecules or coordinate sets in a single file), chains (multiple chains in a single file), altloc (atom alternative conformation given an alternate location indicator and occupancy), metals (metals present in the structure), ligands (heteroatoms present in the structure), chiral (to say that a structure is chiral is to say that its mirror image is not the same as it self), getss (detect SS bonds or disulfides), cistransbck (detact cis/trans backbone), backbone (detect backbone breaks), amide (detect too close amides), clashes (detect clashes). 

31 * **binary_path** (*string*) - ("check_structure") path to the check_structure application 

32 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files. 

33 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist. 

34 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory. 

35 

36 Examples: 

37 This is a use example of how to use the building block from Python:: 

38 

39 from biobb_structure_utils.utils.structure_check import structure_check 

40 prop = { 

41 'features': ['models', 'chains', 'ligands'] 

42 } 

43 structure_check(input_structure_path='/path/to/myInputStr.pdb', 

44 output_summary_path='/path/to/newSummary.json', 

45 properties=prop) 

46 

47 Info: 

48 * wrapped_software: 

49 * name: Structure Checking from MDWeb 

50 * version: >=3.0.3 

51 * license: Apache-2.0 

52 * ontology: 

53 * name: EDAM 

54 * schema: http://edamontology.org/EDAM.owl 

55 

56 """ 

57 

58 def __init__( 

59 self, input_structure_path, output_summary_path, properties=None, **kwargs 

60 ) -> None: 

61 properties = properties or {} 

62 

63 # Call parent class constructor 

64 super().__init__(properties) 

65 self.locals_var_dict = locals().copy() 

66 

67 # Input/Output files 

68 self.io_dict = { 

69 "in": {"input_structure_path": input_structure_path}, 

70 "out": {"output_summary_path": output_summary_path}, 

71 } 

72 

73 # Properties specific for BB 

74 self.binary_path = properties.get("binary_path", "check_structure") 

75 self.features = _from_string_to_list(properties.get("features", None)) 

76 self.properties = properties 

77 

78 # Check the properties 

79 self.check_properties(properties) 

80 self.check_arguments() 

81 

82 @launchlogger 

83 def launch(self) -> int: 

84 """Execute the :class:`StructureCheck <utils.structure_check.StructureCheck>` utils.structure_check.StructureCheck object.""" 

85 

86 self.io_dict["in"]["input_structure_path"] = check_input_path( 

87 self.io_dict["in"]["input_structure_path"], 

88 self.out_log, 

89 self.__class__.__name__, 

90 ) 

91 self.io_dict["out"]["output_summary_path"] = check_output_path_json( 

92 self.io_dict["out"]["output_summary_path"], 

93 self.out_log, 

94 self.__class__.__name__, 

95 ) 

96 

97 # Setup Biobb 

98 if self.check_restart(): 

99 return 0 

100 self.stage_files() 

101 

102 tmp_folder = None 

103 

104 if not self.features or self.features is None or self.features == "None": 

105 fu.log( 

106 "No features provided, all features will be computed: %s" 

107 % "models, chains, altloc, metals, ligands, chiral, getss, cistransbck, backbone, amide, clashes", 

108 self.out_log, 

109 ) 

110 

111 self.cmd = [ 

112 self.binary_path, 

113 "-i", 

114 self.stage_io_dict["in"]["input_structure_path"], 

115 "--json", 

116 self.stage_io_dict["out"]["output_summary_path"], 

117 "--check_only", 

118 "--non_interactive", 

119 "checkall", 

120 ] 

121 else: 

122 fu.log("Computing features: %s" % ", ".join(self.features), self.out_log) 

123 

124 # create temporary folder 

125 tmp_folder = fu.create_unique_dir() 

126 fu.log("Creating %s temporary folder" % tmp_folder, self.out_log) 

127 

128 command_list = tmp_folder + "/command_list.lst" 

129 

130 with open(command_list, "w") as f: 

131 for item in self.features: 

132 f.write("%s\n" % item) 

133 

134 self.cmd = [ 

135 self.binary_path, 

136 "-i", 

137 self.stage_io_dict["in"]["input_structure_path"], 

138 "--json", 

139 self.stage_io_dict["out"]["output_summary_path"], 

140 "--check_only", 

141 "--non_interactive", 

142 "command_list", 

143 "--list", 

144 command_list, 

145 ] 

146 

147 # Run Biobb block 

148 self.run_biobb() 

149 

150 # Copy files to host 

151 self.copy_to_host() 

152 

153 # Remove temporal files 

154 self.tmp_files.extend([ 

155 # self.stage_io_dict.get("unique_dir", ""), 

156 tmp_folder 

157 ]) 

158 self.remove_tmp_files() 

159 

160 self.check_arguments(output_files_created=True, raise_exception=False) 

161 

162 return self.return_code 

163 

164 

165def structure_check( 

166 input_structure_path: str, 

167 output_summary_path: str, 

168 properties: Optional[dict] = None, 

169 **kwargs, 

170) -> int: 

171 """Execute the :class:`StructureCheck <utils.structure_check.StructureCheck>` class and 

172 execute the :meth:`launch() <utils.structure_check.StructureCheck.launch>` method.""" 

173 

174 return StructureCheck( 

175 input_structure_path=input_structure_path, 

176 output_summary_path=output_summary_path, 

177 properties=properties, 

178 **kwargs, 

179 ).launch() 

180 

181 structure_check.__doc__ = StructureCheck.__doc__ 

182 

183 

184def main(): 

185 """Command line execution of this building block. Please check the command line documentation.""" 

186 parser = argparse.ArgumentParser( 

187 description="This class is a wrapper of the Structure Checking tool to generate summary checking results on a json file.", 

188 formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, width=99999), 

189 ) 

190 parser.add_argument( 

191 "-c", 

192 "--config", 

193 required=False, 

194 help="This file can be a YAML file, JSON file or JSON string", 

195 ) 

196 

197 # Specific args of each building block 

198 required_args = parser.add_argument_group("required arguments") 

199 required_args.add_argument( 

200 "-i", 

201 "--input_structure_path", 

202 required=True, 

203 help="Input structure file path. Accepted formats: pdb.", 

204 ) 

205 required_args.add_argument( 

206 "-o", 

207 "--output_summary_path", 

208 required=True, 

209 help="Output summary checking results. Accepted formats: json.", 

210 ) 

211 

212 args = parser.parse_args() 

213 config = args.config if args.config else None 

214 properties = settings.ConfReader(config=config).get_prop_dic() 

215 

216 # Specific call of each building block 

217 structure_check( 

218 input_structure_path=args.input_structure_path, 

219 output_summary_path=args.output_summary_path, 

220 properties=properties, 

221 ) 

222 

223 

224if __name__ == "__main__": 

225 main()