| 1 |  |  | from __future__ import annotations | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | import logging | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | from dataclasses import dataclass | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | from typing import Sequence, Set | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | from pocketutils.core.dot_dict import NestedDotDict | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | from mandos import logger | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | from mandos.model.chembl_api import ChemblApi | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | from mandos.model.chembl_support.chembl_utils import ChemblUtils | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | from mandos.model.chembl_support import ChemblCompound | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | from mandos.search.chembl import ChemblSearch, ChemblHit | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  | @dataclass(frozen=True, order=True, repr=True) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  | class AtcHit(ChemblHit): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     An ATC code found for a compound. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |     level: int | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  | class AtcSearch(ChemblSearch[AtcHit]): | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |     """""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |     def __init__(self, key: str, levels: Set[int], api: ChemblApi): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |         super().__init__(key, api) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |         self.levels = levels | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |     @property | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |     def data_source(self) -> str: | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |         return "ChEMBL :: ATC codes" | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 35 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 36 |  |  |     def find(self, lookup: str) -> Sequence[AtcHit]: | 
            
                                                                        
                            
            
                                    
            
            
                | 37 |  |  |         """ | 
            
                                                                        
                            
            
                                    
            
            
                | 38 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 39 |  |  |         Args: | 
            
                                                                        
                            
            
                                    
            
            
                | 40 |  |  |             lookup: | 
            
                                                                        
                            
            
                                    
            
            
                | 41 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 42 |  |  |         Returns: | 
            
                                                                        
                            
            
                                    
            
            
                | 43 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 44 |  |  |         """ | 
            
                                                                        
                            
            
                                    
            
            
                | 45 |  |  |         # 'atc_classifications': ['S01HA01', 'N01BC01', 'R02AD03', 'S02DA02'] | 
            
                                                                        
                            
            
                                    
            
            
                | 46 |  |  |         # 'indication_class': 'Anesthetic (topical)' | 
            
                                                                        
                            
            
                                    
            
            
                | 47 |  |  |         ch = ChemblUtils(self.api).get_compound_dot_dict(lookup) | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                        
                            
            
                                    
            
            
                | 48 |  |  |         compound = ChemblUtils(self.api).compound_dot_dict_to_obj(ch) | 
            
                                                                        
                            
            
                                    
            
            
                | 49 |  |  |         hits = [] | 
            
                                                                        
                            
            
                                    
            
            
                | 50 |  |  |         if "atc_classifications" in ch: | 
            
                                                                        
                            
            
                                    
            
            
                | 51 |  |  |             for atc in ch["atc_classifications"]: | 
            
                                                                        
                            
            
                                    
            
            
                | 52 |  |  |                 hits.extend(self.process(lookup, compound, atc)) | 
            
                                                                        
                            
            
                                    
            
            
                | 53 |  |  |         return hits | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |     def process(self, lookup: str, compound: ChemblCompound, atc: str) -> Sequence[AtcHit]: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |             lookup: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |             compound: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |             atc: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         Returns: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |         dots = NestedDotDict(self.api.atc_class.get(atc)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |         found = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         for level in sorted(self.levels): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |             found.append(self._code(lookup, compound, dots, level)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |         return found | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |     def _code(self, lookup: str, compound: ChemblCompound, dots: NestedDotDict, level: int): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |         # 'level1': 'N', 'level1_description': 'NERVOUS SYSTEM', 'level2': 'N05', ... | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |         # Unfortunately ChEMBL doesn't contain the exact compound names for ATC | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |         # TODO: These names do not exactly match what ATC uses | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |         if level == 5: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |             object_name = compound.name.lower() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |         else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |             object_name = dots.get(f"level{level}_description") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |         return AtcHit( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |             None, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |             origin_inchikey=lookup, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |             matched_inchikey=compound.inchikey, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |             compound_id=compound.chid, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |             compound_name=compound.name, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |             predicate=f"has ATC level {level} code", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |             object_id=dots.get(f"level{level}"), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |             object_name=object_name, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |             search_key=self.key, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |             search_class=self.search_class, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |             data_source=self.data_source, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |             level=level, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |         ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 96 |  |  | __all__ = ["AtcHit", "AtcSearch"] | 
            
                                                        
            
                                    
            
            
                | 97 |  |  |  |