TargetTraversalStrategy2.__call__()   C
last analyzed

Complexity

Conditions 8

Size

Total Lines 136
Code Lines 91

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 91
nop 2
dl 0
loc 136
rs 5.4278
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
import abc
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
import sys
3
from typing import Sequence, Type
4
5
from mandos.chembl_api import ChemblApi
6
from mandos.model.targets import DagTargetLinkType, Target, TargetRelationshipType, TargetType
7
8
9
class TargetTraversalStrategy(metaclass=abc.ABCMeta):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
10
    """"""
11
12
    @classmethod
13
    def api(cls) -> ChemblApi:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
14
        raise NotImplementedError()
15
16
    def traverse(self, target: Target) -> Sequence[Target]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
17
        return self.__call__(target)
18
19
    def __call__(self, target: Target) -> Sequence[Target]:
20
        """
21
22
        Returns:
23
24
        """
25
        raise NotImplementedError()
26
27
28
class TargetTraversalStrategy0(TargetTraversalStrategy, metaclass=abc.ABCMeta):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
29
    """"""
30
31
    def __call__(self, target: Target) -> Sequence[Target]:
32
        """
33
34
        Returns:
35
36
        """
37
        return [target]
38
39
40
class TargetTraversalStrategy1(TargetTraversalStrategy, metaclass=abc.ABCMeta):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
41
    """"""
42
43
    def __call__(self, target: Target) -> Sequence[Target]:
44
        """
45
        Returns:
46
47
        """
48
        edges = {
49
            DagTargetLinkType(
50
                TargetType.selectivity_group,
51
                TargetRelationshipType.superset_of,
52
                TargetType.protein_complex_group,
53
            ),
54
            DagTargetLinkType(
55
                TargetType.protein_complex_group,
56
                TargetRelationshipType.subset_of,
57
                TargetType.protein_complex_group,
58
            ),
59
            DagTargetLinkType(
60
                TargetType.selectivity_group,
61
                TargetRelationshipType.superset_of,
62
                TargetType.protein_family,
63
            ),
64
            DagTargetLinkType(
65
                TargetType.protein_family,
66
                TargetRelationshipType.subset_of,
67
                TargetType.protein_family,
68
            ),
69
        }
70
        found = target.traverse(edges)
71
        return [f.target for f in found if f.is_end]
72
73
74
class TargetTraversalStrategy2(TargetTraversalStrategy, metaclass=abc.ABCMeta):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
75
    """"""
76
77
    def __call__(self, target: Target) -> Sequence[Target]:
78
        """
79
80
        Returns:
81
82
        """
83
        # traverse the DAG up and down, following only desired links
84
        # some links from complex to complex group are "overlaps with"
85
        # ex: CHEMBL4296059
86
        # it's also rare to need going from a selectivity group "down" to complex group / family / etc.
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (103/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
87
        # usually they have a link upwards
88
        # so...
89
        # If it's a single protein, it's too risk to traverse up into complexes
90
        # That's because lots of proteins *occasionally* make complexes, and there are some weird ones
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (102/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
91
        # BUT We want to catch some obvious cases like GABA A subunits
92
        # ChEMBL calls many of these "something subunit something"
93
        # This is the only time we'll allow going directly from protein to complex
94
        # In this case, we'll also disallow links form protein to family,
95
        # just because we're pretty sure it's a subunit
96
        # But we can go from single protein to complex to complex group to family
97
        if (
98
            target.type
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
99
            in [
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
100
                TargetType.single_protein,
101
                TargetType.protein_family,
102
                TargetType.protein_complex,
103
                TargetType.protein_complex_group,
104
            ]
105
            and ("subunit" in target.name.split(" ") or "chain" in target.name.split(" "))
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
106
        ):
107
            edges = {
108
                DagTargetLinkType(
109
                    TargetType.single_protein,
110
                    TargetRelationshipType.subset_of,
111
                    TargetType.protein_complex,
112
                ),
113
                DagTargetLinkType(
114
                    TargetType.protein_complex,
115
                    TargetRelationshipType.subset_of,
116
                    TargetType.protein_complex_group,
117
                ),
118
                DagTargetLinkType(
119
                    TargetType.protein_complex,
120
                    TargetRelationshipType.overlaps_with,
121
                    TargetType.protein_complex_group,
122
                ),
123
                DagTargetLinkType(
124
                    TargetType.protein_complex_group,
125
                    TargetRelationshipType.subset_of,
126
                    TargetType.protein_complex_group,
127
                ),
128
                DagTargetLinkType(
129
                    TargetType.protein_complex_group,
130
                    TargetRelationshipType.subset_of,
131
                    TargetType.protein_family,
132
                ),
133
                DagTargetLinkType(
134
                    TargetType.protein_family,
135
                    TargetRelationshipType.subset_of,
136
                    TargetType.protein_family,
137
                ),
138
            }
139
        elif target.type in [TargetType.single_protein, TargetType.protein_family]:
140
            edges = {
141
                DagTargetLinkType(
142
                    TargetType.single_protein,
143
                    TargetRelationshipType.subset_of,
144
                    TargetType.protein_family,
145
                ),
146
                DagTargetLinkType(
147
                    TargetType.protein_family,
148
                    TargetRelationshipType.subset_of,
149
                    TargetType.protein_family,
150
                ),
151
            }
152
        elif target.type in [TargetType.protein_complex, TargetType.protein_complex_group]:
153
            edges = {
154
                DagTargetLinkType(
155
                    TargetType.protein_complex,
156
                    TargetRelationshipType.subset_of,
157
                    TargetType.protein_complex_group,
158
                ),
159
                DagTargetLinkType(
160
                    TargetType.protein_complex,
161
                    TargetRelationshipType.overlaps_with,
162
                    TargetType.protein_complex_group,
163
                ),
164
                DagTargetLinkType(
165
                    TargetType.protein_complex_group,
166
                    TargetRelationshipType.subset_of,
167
                    TargetType.protein_complex_group,
168
                ),
169
                DagTargetLinkType(
170
                    TargetType.protein_complex_group,
171
                    TargetRelationshipType.subset_of,
172
                    TargetType.protein_family,
173
                ),
174
                DagTargetLinkType(
175
                    TargetType.protein_family,
176
                    TargetRelationshipType.subset_of,
177
                    TargetType.protein_family,
178
                ),
179
            }
180
        elif target.type == TargetType.selectivity_group:
181
            edges = {
182
                DagTargetLinkType(
183
                    TargetType.selectivity_group,
184
                    TargetRelationshipType.superset_of,
185
                    TargetType.protein_complex_group,
186
                ),
187
                DagTargetLinkType(
188
                    TargetType.protein_complex_group,
189
                    TargetRelationshipType.subset_of,
190
                    TargetType.protein_complex_group,
191
                ),
192
                DagTargetLinkType(
193
                    TargetType.selectivity_group,
194
                    TargetRelationshipType.superset_of,
195
                    TargetType.protein_family,
196
                ),
197
                DagTargetLinkType(
198
                    TargetType.protein_family,
199
                    TargetRelationshipType.subset_of,
200
                    TargetType.protein_family,
201
                ),
202
            }
203
        else:
204
            return [target]
205
        for edge in set(edges):
206
            edges.add(
207
                DagTargetLinkType(
208
                    edge.source_type, TargetRelationshipType.equivalent_to, edge.dest_type
209
                )
210
            )
211
        found = target.traverse(edges)
212
        return [f.target for f in found if f.is_end]
213
214
215
class TargetTraversalStrategies:
216
    """
217
    Factory.
218
    """
219
220
    @classmethod
221
    def by_name(cls, fully_qualified: str, api: ChemblApi) -> TargetTraversalStrategy:
222
        """
223
        For dependency injection.
224
225
        Args:
226
            fully_qualified:
227
            api:
228
229
        Returns:
230
231
        """
232
        s = fully_qualified
0 ignored issues
show
Coding Style Naming introduced by
Variable name "s" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' 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...
233
        mod = s[: s.rfind(".")]
234
        clz = s[s.rfind(".") :]
235
        x = getattr(sys.modules[mod], clz)
0 ignored issues
show
Coding Style Naming introduced by
Variable name "x" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' 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...
236
        return cls.create(x, api)
237
238
    @classmethod
239
    def strategy0(cls, api: ChemblApi) -> TargetTraversalStrategy:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
240
        return cls.create(TargetTraversalStrategy0, api)
241
242
    @classmethod
243
    def strategy1(cls, api: ChemblApi) -> TargetTraversalStrategy:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
244
        return cls.create(TargetTraversalStrategy1, api)
245
246
    @classmethod
247
    def strategy2(cls, api: ChemblApi) -> TargetTraversalStrategy:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
248
        return cls.create(TargetTraversalStrategy2, api)
249
250
    @classmethod
251
    def create(cls, clz: Type[TargetTraversalStrategy], api: ChemblApi) -> TargetTraversalStrategy:
252
        """
253
        Factory method.
254
255
        Args:
256
            clz:
257
            api:
258
259
        Returns:
260
261
        """
262
263
        class X(clz):
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...
264
            @classmethod
265
            def api(cls) -> ChemblApi:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
266
                return api
267
268
        X.__name__ = clz.__name__
269
        return X()
270
271
272
__all__ = ["TargetTraversalStrategy", "TargetTraversalStrategies"]
273