Passed
Push — main ( 6c03a0...9ee5db )
by Douglas
01:53
created

mandos.model.apis.chembl_api.ChemblApi.__str__()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
"""
2
An abstraction for the ChEMBL REST API.
3
Designed to facilitate testing, but also improves static type checking.
4
"""
5
from __future__ import annotations
6
7
import abc
8
from typing import Any, Callable, Iterator, Mapping, Optional, Sequence
9
10
import decorateme
0 ignored issues
show
introduced by
Unable to import 'decorateme'
Loading history...
11
from pocketutils.core.dot_dict import NestedDotDict
0 ignored issues
show
introduced by
Unable to import 'pocketutils.core.dot_dict'
Loading history...
12
13
14
@decorateme.auto_repr_str()
15
class ChemblFilterQuery(metaclass=abc.ABCMeta):
16
    """
17
    Wraps the result of calling ``filter`` on a ChEMBL query.
18
    Supports iterating over results (``__iter__`), getting a single item (``__getitem__`),
19
    and calling ``only(lst)``.
20
    """
21
22
    def only(self, items: Sequence[str]) -> ChemblFilterQuery:
23
        """
24
        Turns this into a query for a single record.
25
        """
26
        raise NotImplementedError()
27
28
    def __getitem__(self, item: int) -> NestedDotDict:
29
        raise NotImplementedError()
30
31
    def __len__(self) -> int:
32
        raise NotImplementedError()
33
34
    def __iter__(self) -> Iterator[NestedDotDict]:
35
        raise NotImplementedError()
36
37
    @classmethod
38
    def mock(cls, items: Sequence[dict]):
39
        """
40
        Mocks.
41
        """
42
43
        class F(ChemblFilterQuery):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
Coding Style Naming introduced by
Class name "F" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]+$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
44
            def only(self, _: Sequence[str]) -> ChemblFilterQuery:
45
                return self
46
47
            def __getitem__(self, item: int) -> NestedDotDict:
48
                return NestedDotDict(items[item])
49
50
            def __len__(self) -> int:
51
                return len(items)
52
53
            def __iter__(self) -> Iterator[NestedDotDict]:
54
                return iter([NestedDotDict(x) for x in items])
55
56
        return F()
57
58
    @classmethod
59
    def wrap(cls, query):
60
        """
61
        Wraps.
62
        """
63
64
        class F(ChemblFilterQuery):
0 ignored issues
show
Coding Style Naming introduced by
Class name "F" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]+$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
introduced by
Missing class docstring
Loading history...
65
            def only(self, items: Sequence[str]) -> ChemblFilterQuery:
66
                # TODO technically not returning this
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
67
                return getattr(query, "only")(items)
68
69
            def __getitem__(self, item: int) -> NestedDotDict:
70
                return NestedDotDict(query[item])
71
72
            def __len__(self) -> int:
73
                return len(query)
74
75
            def __iter__(self) -> Iterator[NestedDotDict]:
76
                return iter([NestedDotDict(x) for x in query])
77
78
        return F()
79
80
81
@decorateme.auto_repr_str()
82
class ChemblEntrypoint:
83
    """
84
    Wraps just part of a node in the ChEMBL REST API.
85
    Ex ``Chembl.target``.
86
    """
87
88
    def filter(self, **kwargs) -> ChemblFilterQuery:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
89
        raise NotImplementedError()
90
91
    def get(self, arg: str) -> Optional[NestedDotDict]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
92
        raise NotImplementedError()
93
94
    @classmethod
95
    def mock(
96
        cls,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
97
        get_items: Mapping[str, dict],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
98
        filter_items: Optional[Callable[[Mapping[str, Any]], Sequence[dict]]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
99
    ) -> ChemblEntrypoint:
100
        """
101
102
        Args:
103
            get_items: Map from single arg for calling ``get`` to the item to return
104
            filter_items: Map from kwarg-set for calling ``filter`` to the list of items to return;
105
                          If None, returns ``items`` in all cases
106
        """
107
108
        class X(ChemblEntrypoint):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
Coding Style Naming introduced by
Class name "X" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]+$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
109
            def filter(self, **kwargs) -> ChemblFilterQuery:
110
                if filter_items is None:
111
                    return ChemblFilterQuery.mock(list(get_items.values()))
112
                items = filter_items(kwargs)
113
                return ChemblFilterQuery.mock(items)
114
115
            def get(self, arg: str) -> Optional[NestedDotDict]:
116
                return NestedDotDict(get_items[arg])
117
118
        return X()
119
120
    @classmethod
121
    def wrap(cls, obj) -> ChemblEntrypoint:
122
        """
123
        Wraps.
124
        """
125
126
        class X(ChemblEntrypoint):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
Coding Style Naming introduced by
Class name "X" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]+$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
127
            def filter(self, **kwargs) -> ChemblFilterQuery:
128
                query = getattr(obj, "filter")(**kwargs)
129
                return ChemblFilterQuery.wrap(query)
130
131
            def get(self, arg: str) -> Optional[NestedDotDict]:
132
                return NestedDotDict(getattr(obj, "get")(arg))
133
134
        return X()
135
136
137
class ChemblApi(metaclass=abc.ABCMeta):
138
    """
139
    Wraps the whole ChEMBL API.
140
    """
141
142
    @property
143
    def activity(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
144
        return self.__dict__["activity"]
145
146
    @property
147
    def assay(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
148
        return self.__dict__["assay"]
149
150
    @property
151
    def atc_class(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
152
        return self.__dict__["atc_class"]
153
154
    @property
155
    def drug(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
156
        return self.__dict__["drug"]
157
158
    @property
159
    def drug_indication(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
160
        return self.__dict__["drug_indication"]
161
162
    @property
163
    def mechanism(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
164
        return self.__dict__["mechanism"]
165
166
    @property
167
    def molecule(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
168
        return self.__dict__["molecule"]
169
170
    @property
171
    def molecule_form(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
172
        return self.__dict__["molecule_form"]
173
174
    @property
175
    def organism(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
176
        return self.__dict__["mechanism"]
177
178
    @property
179
    def go_slim(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
180
        return self.__dict__["go_slim"]
181
182
    @property
183
    def target(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
184
        return self.__dict__["target"]
185
186
    @property
187
    def target_relation(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
188
        return self.__dict__["target_relation"]
189
190
    @property
191
    def protein_class(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
192
        return self.__dict__["protein_class"]
193
194
    @property
195
    def target_component(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
196
        return self.__dict__["target_component"]
197
198
    @property
199
    def target_prediction(self) -> ChemblEntrypoint:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
200
        return self.__dict__["target_prediction"]
201
202
    def __getattribute__(self, item: str) -> ChemblEntrypoint:
203
        raise NotImplementedError()
204
205
    @classmethod
206
    def mock(cls, entrypoints: Mapping[str, ChemblEntrypoint]) -> ChemblApi:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
207
        @decorateme.auto_repr_str()
0 ignored issues
show
Coding Style Naming introduced by
Class name "X" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]+$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
introduced by
Missing class docstring
Loading history...
208
        class X(ChemblApi):
209
            def __getattribute__(self, item: str) -> ChemblEntrypoint:
210
                return entrypoints[item]
211
212
        X.__name__ = f"MockedChemblApi({entrypoints})"
213
        return X()
214
215
    @classmethod
216
    def wrap(cls, obj) -> ChemblApi:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
217
        class X(ChemblApi):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
Coding Style Naming introduced by
Class name "X" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]+$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
218
            def __getattribute__(self, item: str) -> ChemblEntrypoint:
219
                return ChemblEntrypoint.wrap(getattr(obj, item))
220
221
            def __repr__(self):
222
                return f"ChemblApi(Wrapped: {obj})"
223
224
            def __str__(self):
225
                return repr(self)
226
227
        return X()
228
229
230
__all__ = [
231
    "ChemblApi",
232
    "ChemblEntrypoint",
233
    "ChemblFilterQuery",
234
]
235