| 1 |  |  | from __future__ import annotations | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | import abc | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | import enum | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | import sre_compile | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | from pathlib import Path | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | from typing import Dict, Mapping, MutableMapping, Optional, Sequence, Set | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | from typing import Tuple as Tup | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | from typing import Type | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | import decorateme | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | import regex | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | from pocketutils.core.enums import CleverEnum | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | from pocketutils.core.exceptions import ParsingError | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  | from pocketutils.tools.reflection_tools import ReflectionTools | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  | from mandos.model.apis.chembl_api import ChemblApi | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  | from mandos.model.apis.chembl_support.chembl_target_graphs import ( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     ChemblTargetGraph, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |     TargetEdgeReqs, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |     TargetNode, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |     TargetRelType, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  | ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  | from mandos.model.apis.chembl_support.chembl_targets import ChemblTarget, TargetType | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  | from mandos.model.utils.setup import MandosResources, logger | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  | class Acceptance(CleverEnum): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |     always = enum.auto() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |     never = enum.auto() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |     at_start = enum.auto() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |     at_end = enum.auto() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  | class TargetTraversalStrategy(metaclass=abc.ABCMeta): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |     """ """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |     def api(cls) -> ChemblApi: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |         raise NotImplementedError() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |     def traverse(self, target: ChemblTargetGraph) -> Sequence[ChemblTargetGraph]: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |         return self.__call__(target) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |     def __call__(self, target: ChemblTargetGraph) -> Sequence[ChemblTargetGraph]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |         Run the strategy. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         raise NotImplementedError() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |     def __repr__(self) -> str: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |         return self.__class__.__name__ + "(" + str(self.api()) + ")" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |     def __str__(self) -> str: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |         return repr(self) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  | class NullTargetTraversalStrategy(TargetTraversalStrategy, metaclass=abc.ABCMeta): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     """ """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |     def api(cls) -> ChemblApi: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         raise NotImplementedError() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |     def traverse(self, target: ChemblTargetGraph) -> Sequence[ChemblTargetGraph]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |         return self.__call__(target) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |     def __call__(self, target: ChemblTargetGraph) -> Sequence[ChemblTargetGraph]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |         return [target] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  | class StandardTargetTraversalStrategy(TargetTraversalStrategy, metaclass=abc.ABCMeta): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |     """ """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |     def edges(cls) -> Set[TargetEdgeReqs]: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |         raise NotImplementedError() | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 78 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 79 |  |  |     @classmethod | 
            
                                                                        
                            
            
                                    
            
            
                | 80 |  |  |     def acceptance(cls) -> Mapping[TargetEdgeReqs, Acceptance]: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                        
                            
            
                                    
            
            
                | 81 |  |  |         raise NotImplementedError() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |     def __call__(self, target: ChemblTargetGraph) -> Sequence[ChemblTarget]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |         logger.debug(f"Starting {self} on {target.target}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |         found = target.traverse(self.edges()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |         return [f.target for f in found if self.accept(f)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |     def accept(self, target: TargetNode) -> bool: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |         if target.link_reqs is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |             # typically for root nodes -- we'll have a self-loop to check, too | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |             logger.trace(f"Rejected probable root: {target}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |             return False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |         acceptance_type = self.acceptance()[target.link_reqs] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |         b = ( | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |             acceptance_type is Acceptance.always | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |             or (acceptance_type is Acceptance.at_start and target.is_start) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |             or (acceptance_type is Acceptance.at_end and target.is_end) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |         ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |         x = "accepted" if b else "rejected" | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |         logger.trace(f"{x.capitalize()}: {target}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |         return b | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  | class StandardStrategyParser: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |     def read_lines(cls, path: Path) -> Sequence[str]: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |         return [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |             line | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |             for line in path.read_text(encoding="utf8").splitlines() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |             if not line.startswith("#") and len(line.strip()) > 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |         ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |     def parse( | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |         cls, lines: Sequence[str] | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |     ) -> Tup[Set[TargetEdgeReqs], Mapping[TargetEdgeReqs, Acceptance]]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |         pat_type = r"(@?[a-z_]+)" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |         pat_rel = r"([<>~=.*])" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |         pat_accept = r"(?:accept:([\-*^$]))?" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |         pat_src_words = r"(?:src:'''(.+?)''')?" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |         pat_dest_words = r"(?:dest:'''(.+?)''')?" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |         comment = r"(?:#(.*))?" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |         pat = f"^ *{pat_type} *{pat_rel} *{pat_type} *{pat_accept} *{pat_src_words} *{pat_dest_words} *{comment} *$" | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |         pat = regex.compile(pat, flags=regex.V1) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |         to_rel = { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |             ">": TargetRelType.superset_of, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |             "<": TargetRelType.subset_of, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |             "~": TargetRelType.overlaps_with, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |             "=": TargetRelType.equivalent_to, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |             "*": TargetRelType.any_link, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |             ".": TargetRelType.self_link, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |         to_accept = { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |             "*": Acceptance.always, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |             "-": Acceptance.never, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |             "^": Acceptance.at_start, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |             "$": Acceptance.at_end, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |         edges = set() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |         edge_to_acceptance: MutableMapping[TargetEdgeReqs, Acceptance] = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |         for line in lines: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |             match = pat.fullmatch(line) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |             if match is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |                 raise ParsingError(f"Could not parse line '{line}'") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |             try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |                 sources = TargetType.resolve(match.group(1)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |                 rel = to_rel[match.group(2)] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |                 dests = TargetType.resolve(match.group(3)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |                 accept = to_accept[match.group(4).lower()] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 |  |  |                 src_pat = ( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |                     None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |                     if match.group(5) is None or match.group(5) == "" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |                     else regex.compile(match.group(5), flags=regex.V1) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |                 ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |                 dest_pat = ( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |                     None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |                     if match.group(6) is None or match.group(6) == "" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |                     else regex.compile(match.group(6), flags=regex.V1) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |                 ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |             except (KeyError, TypeError, sre_compile.error): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |                 raise AssertionError(f"Could not parse line '{line}'") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |             for source in sources: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |                 for dest in dests: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |                     edge = TargetEdgeReqs( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |                         src_type=source, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |                         src_pattern=src_pat, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |                         rel_type=rel, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |                         dest_type=dest, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |                         dest_pattern=dest_pat, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |                     ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 |  |  |                     edges.add(edge) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |                     edge_to_acceptance[edge] = accept | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |         return edges, edge_to_acceptance | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  | class TargetTraversalStrategies: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  |     Factory. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |     def standard_strategies(cls) -> Set[str]: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |         return {p.stem for p in MandosResources.dir("strategies").iterdir() if p.suffix == ".strat"} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 |  |  |     def by_name(cls, name: str, api: ChemblApi) -> TargetTraversalStrategy: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 |  |  |         if name == "@null":  # just slightly more efficient | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 |  |  |             return cls.null(api) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 189 |  |  |         if MandosResources.contains("strategies", name, suffix=".strat"): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 190 |  |  |             return cls.from_resource(name, api) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 191 |  |  |         elif name.endswith(".strat"): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 192 |  |  |             return cls.from_file(Path(name), api) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 |  |  |         return cls.by_classname(name, api) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 |  |  |     def by_classname(cls, fully_qualified: str, api: ChemblApi) -> TargetTraversalStrategy: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  |         clazz = ReflectionTools.injection(fully_qualified, TargetTraversalStrategy) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 |  |  |         logger.info(f"Loaded strategy {clazz} by injection: {fully_qualified}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  |         return cls.create(clazz, api) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 202 |  |  |     def from_resource(cls, name: str, api: ChemblApi) -> TargetTraversalStrategy: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 203 |  |  |         path = MandosResources.file("strategies", name, suffix=".strat") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 204 |  |  |         return cls.from_file(path, api) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 205 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 206 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 207 |  |  |     def from_file(cls, path: Path, api: ChemblApi) -> TargetTraversalStrategy: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 208 |  |  |         lines = StandardStrategyParser.read_lines(path) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 209 |  |  |         logger.debug(f"Loaded strategy from {path} with {len(lines)} lines") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 210 |  |  |         return cls._from_lines(lines, api, name="TraversalStrategy" + path.stem.capitalize()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 211 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 212 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 213 |  |  |     def from_lines( | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 214 |  |  |         cls, lines: Sequence[str], api: ChemblApi, *, name: str | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 215 |  |  |     ) -> TargetTraversalStrategy: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 216 |  |  |         return cls._from_lines(lines, api, name=name) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 217 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 218 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 219 |  |  |     def _from_lines( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 220 |  |  |         cls, lines: Sequence[str], api: ChemblApi, *, name: str | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 221 |  |  |     ) -> TargetTraversalStrategy: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 222 |  |  |         edges, accept = StandardStrategyParser.parse(lines) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 223 |  |  |         logger.info(f"Loaded strategy {name} with {len(edges)} edge types") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 224 |  |  |         for edge in edges: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 225 |  |  |             logger.trace(f"Edge: {edge} ({accept[edge]})") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 226 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 227 |  |  |         class Strategy(StandardTargetTraversalStrategy): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 228 |  |  |             @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 229 |  |  |             def edges(cls) -> Set[TargetEdgeReqs]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 230 |  |  |                 return edges | 
            
                                                                                                            
                            
            
                                    
            
            
                | 231 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 232 |  |  |             @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 233 |  |  |             def acceptance(cls) -> Mapping[TargetEdgeReqs, Acceptance]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 234 |  |  |                 return accept | 
            
                                                                                                            
                            
            
                                    
            
            
                | 235 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 236 |  |  |             @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 237 |  |  |             def api(cls) -> ChemblApi: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 238 |  |  |                 return api | 
            
                                                                                                            
                            
            
                                    
            
            
                | 239 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 240 |  |  |         Strategy.__name__ = name | 
            
                                                                                                            
                            
            
                                    
            
            
                | 241 |  |  |         return Strategy() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 242 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 243 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 244 |  |  |     def null(cls, api: ChemblApi) -> TargetTraversalStrategy: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 245 |  |  |         class NullStrategy(NullTargetTraversalStrategy): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 246 |  |  |             @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 247 |  |  |             def api(cls) -> ChemblApi: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 248 |  |  |                 return api | 
            
                                                                                                            
                            
            
                                    
            
            
                | 249 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 250 |  |  |         NullStrategy.__name__ = "NullStrategy" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 251 |  |  |         return NullStrategy() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 252 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 253 |  |  |     # noinspection PyAbstractClass | 
            
                                                                                                            
                            
            
                                    
            
            
                | 254 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 255 |  |  |     def create(cls, clz: Type[TargetTraversalStrategy], api: ChemblApi) -> TargetTraversalStrategy: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 256 |  |  |         @decorateme.auto_utils() | 
                            
                    |  |  |  | 
                                                                                        
                                                                                            
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 257 |  |  |         class X(clz): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 258 |  |  |             @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 259 |  |  |             def api(cls) -> ChemblApi: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 260 |  |  |                 return api | 
            
                                                                                                            
                            
            
                                    
            
            
                | 261 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 262 |  |  |         X.__name__ = clz.__name__ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 263 |  |  |         return X() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 264 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 265 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 266 |  |  | __all__ = ["TargetTraversalStrategy", "TargetTraversalStrategies"] | 
            
                                                        
            
                                    
            
            
                | 267 |  |  |  |