Passed
Push — main ( ddff4b...7b3fbc )
by Douglas
04:33
created

mandos.model.apis.pubchem_support.pubchem_data   F

Complexity

Total Complexity 155

Size/Duplication

Total Lines 1066
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 851
dl 0
loc 1066
rs 1.749
c 0
b 0
f 0
wmc 155

101 Methods

Rating   Name   Duplication   Size   Complexity  
A PubchemData.biological_test_results() 0 3 1
A Classification.chembl_tree() 0 3 1
A Toxicity._whoami() 0 3 1
A SafetyAndHazards.ghs_codes() 0 19 1
A PharmacologyAndBiochemistry.moa_summary_hsdb_links() 0 3 1
A DrugAndMedicationInformation.mini() 0 3 1
A PharmacologyAndBiochemistry.summary_drugbank_text() 0 12 1
A PubchemData.drug_and_medication_information() 0 3 1
A NamesAndIdentifiers.descriptor() 0 15 1
A DrugAndMedicationInformation.dea_schedule() 0 15 1
A PubchemDataView._classifications() 0 3 1
A DrugAndMedicationInformation.clinical_trials() 0 19 2
A DrugAndMedicationInformation.livertox_classes() 0 11 1
A PubchemData.related_records() 0 3 1
A ChemicalAndPhysicalProperties.single_property() 0 3 1
A PharmacologyAndBiochemistry._whoami() 0 3 1
B ChemicalAndPhysicalProperties.computed() 0 21 6
A PubchemData.parent_or_self() 0 4 2
A PubchemData.associated_disorders_and_diseases() 0 3 1
A NamesAndIdentifiers.inchi() 0 3 1
A BiomolecularInteractionsAndPathways.chemical_gene_interactions() 0 18 1
C Literature.depositor_pubmed_articles() 0 70 9
A BiomolecularInteractionsAndPathways._whoami() 0 3 1
A BiomolecularInteractionsAndPathways.drugbank_ddis() 0 15 1
A DrugAndMedicationInformation.indication_summary_drugbank() 0 12 1
A PubchemData.toxicity() 0 3 1
A BiologicalTestResults._whoami() 0 3 1
A Classification.atc_tree() 0 3 1
A NamesAndIdentifiers.inchikey() 0 3 1
A Classification.chebi_tree() 0 3 1
A RelatedRecords._whoami() 0 3 1
A AssociatedDisordersAndDiseases._whoami() 0 3 1
A PharmacologyAndBiochemistry.moa_summary_drugbank_text() 0 3 1
A Literature.gene_cooccurrences() 0 3 1
A PharmacologyAndBiochemistry._get_moa_links() 0 16 1
A NamesAndIdentifiers.molecular_formula() 0 13 1
A PubchemMiniDataView._whoami() 0 3 1
A TitleAndSummary.safety() 0 12 1
A BiomolecularInteractionsAndPathways.drugbank_legal_groups() 0 7 3
A ChemicalAndPhysicalProperties._extract_kvr() 0 6 3
A PharmacologyAndBiochemistry.atc() 0 14 1
A PubchemDataView.to_json() 0 12 2
A PubchemData.pharmacology_and_biochemistry() 0 3 1
A DrugAndMedicationInformation.indication_summary_livertox() 0 12 1
A PubchemData.title_and_summary() 0 3 1
A Patents._whoami() 0 3 1
A PubchemDataView._has_ref() 0 2 2
A PharmacologyAndBiochemistry.biochem_reactions() 0 4 1
A PubchemMiniDataView._mini() 0 3 1
A ChemicalAndPhysicalProperties.xlogp3() 0 3 1
A Classification._whoami() 0 3 1
A PubchemData.literature() 0 3 1
A PubchemDataView._refs() 0 3 1
B Literature._get_cooccurrences() 0 41 3
A Literature.disease_cooccurrences() 0 3 1
A PubchemData.chemical_and_physical_properties() 0 3 1
A PharmacologyAndBiochemistry.summary_ncit_links() 0 18 1
A RelatedRecords.parent() 0 13 2
A DrugAndMedicationInformation.hsdb_uses() 0 13 2
A Classification.g2p_tree() 0 3 1
A PubchemDataView._toc() 0 3 1
A NamesAndIdentifiers.modify_date() 0 13 1
A PubchemData.biomolecular_interactions_and_pathways() 0 3 1
A DrugAndMedicationInformation.dea_class() 0 11 1
A PharmacologyAndBiochemistry.mesh() 0 9 1
A Classification.cpdat_tree() 0 3 1
A NamesAndIdentifiers._whoami() 0 3 1
A ChemicalAndPhysicalProperties.charge() 0 3 1
A Classification.mesh_tree() 0 3 1
A Toxicity.acute_effects() 0 16 1
A PubchemDataView.cid() 0 9 2
A PharmacologyAndBiochemistry.moa_summary_hsdb_text() 0 3 1
A Literature._whoami() 0 3 1
A PubchemData.name() 0 3 1
A PubchemData.safety_and_hazards() 0 3 1
A PharmacologyAndBiochemistry._get_moa_text() 0 11 1
A PubchemData.classification() 0 3 1
A PharmacologyAndBiochemistry.moa_summary_drugbank_links() 0 3 1
A ChemicalAndPhysicalProperties.mol_weight() 0 6 2
A ChemicalAndPhysicalProperties.tpsa() 0 6 2
A SafetyAndHazards._whoami() 0 3 1
A ChemicalAndPhysicalProperties.complexity_rating() 0 3 1
F ChemicalAndPhysicalProperties._extract_value_and_unit() 0 27 14
B Literature._guess_neighbor() 0 11 6
A ChemicalAndPhysicalProperties._whoami() 0 3 1
A Classification.dea() 0 3 1
A Classification.chemid() 0 3 1
B BiologicalTestResults.bioactivity() 0 25 6
A NamesAndIdentifiers.create_date() 0 13 1
A BiomolecularInteractionsAndPathways.drugbank_interactions() 0 21 4
A PubchemDataView._links() 0 3 1
A Patents.associated_disorders_and_diseases() 0 9 1
A PubchemDataView.__init__() 0 2 1
A PubchemData.names_and_identifiers() 0 3 1
A PubchemData.parent_or_none() 0 3 1
A AssociatedDisordersAndDiseases.associated_disorders_and_diseases() 0 15 1
A PharmacologyAndBiochemistry.summary_ncit_text() 0 13 1
A PubchemDataView._tables() 0 3 1
A Literature.chemical_cooccurrences() 0 3 1
A BiomolecularInteractionsAndPathways.drug_gene_interactions() 0 18 1
A PubchemDataView._nav() 0 3 1

How to fix   Complexity   

Complexity

Complex classes like mandos.model.apis.pubchem_support.pubchem_data often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""
0 ignored issues
show
coding-style introduced by
Too many lines in module (1066/1000)
Loading history...
2
PubChem data views and processors.
3
"""
4
from __future__ import annotations
5
6
import abc
7
import re
8
from datetime import date, datetime
9
from typing import Mapping, Optional, Sequence, Union, FrozenSet, Any, Dict
10
from typing import Tuple as Tup
11
from urllib.parse import unquote as url_unescape
12
13
import orjson
0 ignored issues
show
introduced by
Unable to import 'orjson'
Loading history...
14
from pocketutils.core.dot_dict import NestedDotDict
0 ignored issues
show
introduced by
Unable to import 'pocketutils.core.dot_dict'
Loading history...
15
from pocketutils.tools.common_tools import CommonTools
0 ignored issues
show
introduced by
Unable to import 'pocketutils.tools.common_tools'
Loading history...
16
from pocketutils.tools.string_tools import StringTools
0 ignored issues
show
introduced by
Unable to import 'pocketutils.tools.string_tools'
Loading history...
17
18
from mandos import logger
19
20
# noinspection PyProtectedMember
21
from mandos.model import MultipleMatchesError
22
from mandos.model.apis.pubchem_support._nav_fns import Filter, Mapx, Flatmap
23
24
# noinspection PyProtectedMember
25
from mandos.model.apis.pubchem_support._nav_model import FilterFn
26
27
# noinspection PyProtectedMember
28
from mandos.model.apis.pubchem_support._nav import JsonNavigator
29
from mandos.model.apis.pubchem_support.pubchem_models import (
30
    ComputedProperty,
31
    Codes,
32
    CoOccurrenceType,
33
    ClinicalTrial,
34
    GhsCode,
35
    AssociatedDisorder,
36
    AtcCode,
37
    DrugbankInteraction,
38
    DrugbankDdi,
39
    PubmedEntry,
40
    Publication,
41
    Activity,
42
    CoOccurrence,
43
    DrugGeneInteraction,
44
    ChemicalGeneInteraction,
45
    Bioactivity,
46
    AcuteEffectEntry,
47
    DrugbankTargetType,
48
)
49
50
51
class Misc:
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
52
    empty_frozenset = frozenset([])
53
54
55
class Patterns:
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
56
    ghs_code = re.compile(r"((?:H\d+)(?:\+H\d+)*)")
57
    ghs_code_singles = re.compile(r"(H\d+)")
58
    pubchem_compound_url = re.compile(r"^https:\/\/pubchem\.ncbi\.nlm\.nih\.gov\/compound\/(.+)$")
59
    atc_codes = re.compile(r"([A-Z])([0-9]{2})?([A-Z])?([A-Z])?([A-Z])?")
60
    mesh_codes = re.compile(r"[A-Z]")
61
62
63
class PubchemDataView(metaclass=abc.ABCMeta):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
64
    """ """
65
66
    def __init__(self, data: NestedDotDict):
67
        self._data = data
68
69
    def to_json(self) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
70
        def default(obj: Any) -> Any:
0 ignored issues
show
Unused Code introduced by
Either all return statements in a function should return an expression, or none of them should.
Loading history...
71
            if isinstance(obj, NestedDotDict):
72
                # noinspection PyProtectedMember
73
                return dict(obj._x)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _x was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
74
75
        # noinspection PyProtectedMember
76
        data = dict(self._data._x)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _x was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
77
        encoded = orjson.dumps(data, default=default, option=orjson.OPT_INDENT_2)
78
        encoded = encoded.decode(encoding="utf8")
79
        encoded = StringTools.retab(encoded, 2)
80
        return encoded
81
82
    @property
83
    def cid(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
84
        if self._data["record.RecordType"] != "CID":
85
            raise ValueError(
86
                "RecordType for {} is {}".format(
87
                    self._data["record.RecordNumber"], self._data["record.RecordType"]
88
                )
89
            )
90
        return self._data["record.RecordNumber"]
91
92
    @property
93
    def _toc(self) -> JsonNavigator:
94
        return self._nav / "Section" % "TOCHeading"
95
96
    @property
97
    def _tables(self) -> JsonNavigator:
98
        return JsonNavigator.create(self._data) / "external_tables"
99
100
    @property
101
    def _links(self) -> JsonNavigator:
102
        return JsonNavigator.create(self._data) / "link_sets"
103
104
    @property
105
    def _classifications(self) -> JsonNavigator:
106
        return self._nav / "classifications"
107
108
    @property
109
    def _nav(self) -> JsonNavigator:
110
        return JsonNavigator.create(self._data) / "record"
111
112
    @property
113
    def _refs(self) -> Mapping[int, str]:
114
        return {z["ReferenceNumber"]: z["SourceName"] for z in (self._nav / "Reference").contents}
115
116
    def _has_ref(self, name: str) -> FilterFn:
117
        return FilterFn(lambda dot: self._refs.get(dot.get_as("ReferenceNumber", int)) == name)
118
119
120
class PubchemMiniDataView(PubchemDataView, metaclass=abc.ABCMeta):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
121
    """ """
122
123
    @property
124
    def _whoami(self) -> str:
125
        raise NotImplementedError()
126
127
    @property
128
    def _mini(self) -> JsonNavigator:
129
        return self._toc / self._whoami / "Section" % "TOCHeading"
130
131
132
class TitleAndSummary(PubchemDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
133
    """ """
134
135
    @property
136
    def safety(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
137
        return (
138
            self._toc
139
            / "Chemical Safety"
140
            / "Information"
141
            / self._has_ref("PubChem")
142
            / "Value"
143
            / "StringWithMarkup"
144
            / "Markup"
145
            >> "Extra"
146
        ).to_set
147
148
149
class RelatedRecords(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
150
    """ """
151
152
    @property
153
    def _whoami(self) -> str:
154
        return "Related Records"
155
156
    @property
157
    def parent(self) -> Optional[int]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
158
        parent = (
159
            self._mini
160
            / "Parent Compound"
161
            / "Information"
162
            / "Value"
163
            / "StringWithMarkup"
164
            // ["String"]
165
            // Flatmap.require_only()
166
        )
167
        parent = parent / Mapx.extract_group_1(r"CID (\d+) +.*") // Flatmap.request_only()
168
        return self.cid if parent.get is None else int(parent.get)
169
170
171
class NamesAndIdentifiers(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
172
    """ """
173
174
    @property
175
    def _whoami(self) -> str:
176
        return "Names and Identifiers"
177
178
    @property
179
    def inchikey(self) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
180
        return self.descriptor("InChI Key")
181
182
    @property
183
    def inchi(self) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
184
        return self.descriptor("InChI")
185
186
    @property
187
    def molecular_formula(self) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
188
        return (
189
            self._mini
190
            / "Molecular Formula"
191
            / "Information"
192
            / self._has_ref("PubChem")
193
            / "Value"
194
            / "StringWithMarkup"
195
            // ["String"]
196
            // Flatmap.require_only()
197
            // Flatmap.require_only()
198
        ).get
199
200
    def descriptor(self, key: str) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
201
        return (
202
            self._mini
203
            / "Computed Descriptors"
204
            / "Section"
205
            % "TOCHeading"
206
            / key
207
            / "Information"
208
            / self._has_ref("PubChem")
209
            / "Value"
210
            / "StringWithMarkup"
211
            // ["String"]
212
            // Flatmap.require_only()
213
            // Flatmap.require_only()
214
        ).get
215
216
    @property
217
    def create_date(self) -> date:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
218
        return (
219
            self._toc
220
            / "Create Date"
221
            / "Information"
222
            / self._has_ref("PubChem")
223
            / "Value"
224
            // ["DateISO8601"]
225
            // Flatmap.require_only()
226
            / date.fromisoformat
227
            // Flatmap.require_only()
228
        ).get
229
230
    @property
231
    def modify_date(self) -> date:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
232
        return (
233
            self._toc
234
            / "Modify Date"
235
            / "Information"
236
            / self._has_ref("PubChem")
237
            / "Value"
238
            // ["DateISO8601"]
239
            // Flatmap.require_only()
240
            / date.fromisoformat
241
            // Flatmap.require_only()
242
        ).get
243
244
245
class ChemicalAndPhysicalProperties(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
246
    """ """
247
248
    @property
249
    def _whoami(self) -> str:
250
        return "Chemical and Physical Properties"
251
252
    @property
253
    def xlogp3(self) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
254
        return self.single_property("XLogP3").req_is(float)
255
256
    @property
257
    def mol_weight(self) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
258
        weight = self.single_property("Molecular Weight")
259
        if weight.unit != "g/mol":
260
            raise ValueError(f"Expected g/mol for weight; got {weight.unit}")
261
        return weight.req_is(float)
262
263
    @property
264
    def tpsa(self) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
265
        weight = self.single_property("Topological Polar Surface Area")
266
        if weight.unit != "Ų":
267
            raise ValueError(f"Expected Ų for weight; got {weight.unit}")
268
        return weight.req_is(float)
269
270
    @property
271
    def charge(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
272
        return self.single_property("Formal Charge", "PubChem").value
273
274
    @property
275
    def complexity_rating(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
276
        return self.single_property("Complexity", "PubChem").value
277
278
    def single_property(self, key: str, ref: Optional[str] = "PubChem") -> ComputedProperty:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
279
        return CommonTools.only(
280
            [kvr for kvr in self.computed if kvr.key == key and (ref is None or kvr.ref == ref)]
281
        )
282
283
    @property
284
    def computed(self) -> FrozenSet[ComputedProperty]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
285
        cid = self.cid
286
        props = {
287
            dot["TOCHeading"]: dot["Information"]
288
            for dot in (self._mini / "Computed Properties" / "Section").get
289
        }
290
        results: Dict[Tup[str, str], ComputedProperty] = {}
291
        for heading, info in props.items():
292
            for dot in info:
293
                try:
294
                    dot = NestedDotDict(dot)
295
                    kvr = self._extract_kvr(heading, dot)
296
                    if kvr is not None:
297
                        if (kvr.key, kvr.ref) in results:
298
                            raise MultipleMatchesError(f"Multiple matches for {kvr} on {cid}")
299
                        results[(kvr.key, kvr.ref)] = kvr
300
                except (KeyError, ValueError):
301
                    logger.debug(f"Failed on {dot} for cid {cid}")
302
                    raise
303
        return frozenset(results.values())
304
305
    def _extract_kvr(self, heading: str, dot: NestedDotDict) -> Optional[ComputedProperty]:
306
        if "Value" not in dot or "Reference" not in dot:
307
            return None
308
        ref = ", ".join(dot["Reference"])
309
        value, unit = self._extract_value_and_unit(dot["Value"])
310
        return ComputedProperty(heading, value, unit, ref)
311
312
    def _extract_value_and_unit(
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
313
        self, dot: NestedDotDict
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
314
    ) -> Tup[Union[None, int, str, float, bool], str]:
315
        value, unit = None, None
316
        if "Number" in dot and len(["Number"]) == 1:
317
            value = dot["Number"][0]
318
        elif "Number" in dot and len(["Number"]) > 1:
319
            value = ", ".join([str(s) for s in dot["Number"]])
320
        elif (
321
            "StringWithMarkup" in dot
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
322
            and len(dot["StringWithMarkup"]) == 1
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
323
            and "String" in dot["StringWithMarkup"][0]
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
324
        ):
325
            value = dot["StringWithMarkup"][0]["String"]
326
        elif (
327
            "StringWithMarkup" in dot
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
328
            and len(dot["StringWithMarkup"]) > 1
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
329
            and all(["String" in swump for swump in dot["StringWithMarkup"]])
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
330
        ):
331
            value = ", ".join([str(s) for s in dot["StringWithMarkup"]])
332
        else:
333
            value = None
334
        if "Unit" in dot and value is not None:
335
            unit = dot["Unit"]
336
        if isinstance(value, str):
337
            value = value.strip().replace("\n", "").replace("\r", "").strip()
338
        return value, unit
339
340
341
class DrugAndMedicationInformation(PubchemDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
342
    """ """
343
344
    @property
345
    def mini(self) -> JsonNavigator:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
346
        return self._toc / "Drug and Medication Information" / "Section" % "TOCHeading"
347
348
    @property
349
    def indication_summary_drugbank(self) -> Optional[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
350
        return (
351
            self.mini
352
            / "Drug Indication"
353
            / "Information"
354
            / self._has_ref("DrugBank")
355
            / "Value"
356
            / "StringWithMarkup"
357
            >> "String"
358
            >> Flatmap.join_nonnulls()
359
        ).get
360
361
    @property
362
    def indication_summary_livertox(self) -> Optional[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
363
        return (
364
            self.mini
365
            / "LiverTox Summary"
366
            / "Information"
367
            / self._has_ref("LiverTox")
368
            / "Value"
369
            / "StringWithMarkup"
370
            >> "String"
371
            >> Flatmap.join_nonnulls()
372
        ).get
373
374
    @property
375
    def livertox_classes(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
376
        return (
377
            self.mini
378
            / "Drug Classes"
379
            / "Information"
380
            / self._has_ref("LiverTox")
381
            / "Value"
382
            / "StringWithMarkup"
383
            >> "String"
384
        ).to_set
385
386
    @property
387
    def dea_class(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
388
        return (
389
            self.mini
390
            / "DEA Drug Facts"
391
            / "Information"
392
            / self._has_ref("Drug Enforcement Administration (DEA)")
393
            / "Value"
394
            / "StringWithMarkup"
395
            >> "String"
396
        ).to_set
397
398
    @property
399
    def dea_schedule(self) -> Optional[Codes.DeaSchedule]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
400
        return (
401
            self.mini
402
            / "DEA Controlled Substances"
403
            / "Information"
404
            / self._has_ref("Drug Enforcement Administration (DEA)")
405
            / "Value"
406
            / "StringWithMarkup"
407
            // ["String"]
408
            // Flatmap.require_only()
409
            / Mapx.extract_group_1(r" *Schedule ([IV]+).*")
410
            / Codes.DeaSchedule
411
            // Flatmap.request_only()
412
        ).get
413
414
    @property
415
    def hsdb_uses(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
416
        mesh = "National Library of Medicine's Medical Subject Headings"
417
        return (
418
            self.mini
419
            / "Therapeutic Uses"
420
            / "Information"
421
            / self._has_ref("Hazardous Substances Data Bank (HSDB)")
422
            / FilterFn(lambda dot: dot.req_as("Reference", str).startswith(mesh))
423
            / "Value"
424
            / "StringWithMarkup"
425
            >> "String"
426
        ).to_set
427
428
    @property
429
    def clinical_trials(self) -> FrozenSet[ClinicalTrial]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
430
        trials = (self._tables / "clinicaltrials").get
431
        objs = []
432
        for trial in trials:
433
            source = self._refs[int(trial["srcid"])]
434
            obj = ClinicalTrial(
435
                Codes.ClinicaltrialId.of(trial["ctid"]),
436
                trial["title"],
437
                frozenset([Codes.GenericDiseaseCode.of(z) for z in trial["diseaseids"].split("|")]),
438
                frozenset(trial["conditions"].split("|")),
439
                trial["phase"],
440
                trial["status"],
441
                frozenset(trial["interventions"].split("|")),
442
                frozenset([Codes.PubchemCompoundId.of(z) for z in trial["cids"].split("|")]),
443
                source,
444
            )
445
            objs.append(obj)
446
        return frozenset(objs)
447
448
449
class PharmacologyAndBiochemistry(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
450
    """ """
451
452
    @property
453
    def _whoami(self) -> str:
454
        return "Pharmacology and Biochemistry"
455
456
    @property
457
    def summary_drugbank_text(self) -> Optional[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
458
        return (
459
            self._mini
460
            / "Pharmacology"
461
            / "Information"
462
            / self._has_ref("DrugBank")
463
            / "Value"
464
            / "StringWithMarkup"
465
            >> "String"
466
            >> Flatmap.join_nonnulls()
467
        ).get
468
469
    @property
470
    def summary_ncit_text(self) -> Optional[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
471
        return (
472
            self._mini
473
            / "Pharmacology"
474
            / "Information"
475
            / self._has_ref("NCI Thesaurus (NCIt)")
476
            / Filter.key_equals("Name", "Pharmacology")
477
            / "Value"
478
            / "StringWithMarkup"
479
            >> "String"
480
            >> Flatmap.join_nonnulls()
481
        ).get
482
483
    @property
484
    def summary_ncit_links(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
485
        return (
486
            self._mini
487
            / "Pharmacology"
488
            / "Information"
489
            / self._has_ref("NCI Thesaurus (NCIt)")
490
            / Filter.key_equals("Name", "Pharmacology")
491
            / "Value"
492
            / "StringWithMarkup"
493
            / "Markup"
494
            / Filter.key_equals("Type", "PubChem Internal Link")
495
            // ["URL"]
496
            // Flatmap.require_only()
497
            / Mapx.extract_group_1(Patterns.pubchem_compound_url)
498
            / url_unescape
499
            / Mapx.lowercase_unless_acronym()  # TODO necessary but unfortunate -- cocaine and Cocaine
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...
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
500
        ).to_set
501
502
    @property
503
    def mesh(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
504
        return (
505
            self._mini
506
            / "MeSH Pharmacological Classification"
507
            / "Information"
508
            / self._has_ref("MeSH")
509
            >> "Name"
510
        ).to_set
511
512
    @property
513
    def atc(self) -> FrozenSet[AtcCode]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
514
        strs = (
515
            self._mini
516
            / "ATC Code"
517
            / "Information"
518
            / self._has_ref("WHO Anatomical Therapeutic Chemical (ATC) Classification")
519
            / Filter.key_equals("Name", "ATC Code")
520
            / "Value"
521
            / "StringWithMarkup"
522
            >> "String"
523
        ).to_set
524
        return frozenset(
525
            [AtcCode(s.split(" - ")[0].strip(), s.split(" - ")[1].strip()) for s in strs]
526
        )
527
528
    @property
529
    def moa_summary_drugbank_links(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
530
        return self._get_moa_links("DrugBank")
531
532
    @property
533
    def moa_summary_drugbank_text(self) -> Optional[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
534
        return self._get_moa_text("DrugBank")
535
536
    @property
537
    def moa_summary_hsdb_links(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
538
        return self._get_moa_links("Hazardous Substances Data Bank (HSDB)")
539
540
    @property
541
    def moa_summary_hsdb_text(self) -> Optional[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
542
        return self._get_moa_text("Hazardous Substances Data Bank (HSDB)")
543
544
    def _get_moa_text(self, ref: str) -> Optional[str]:
545
        return (
546
            self._mini
547
            / "Mechanism of Action"
548
            / "Information"
549
            / self._has_ref(ref)
550
            / "Value"
551
            / "StringWithMarkup"
552
            >> "String"
553
            >> Flatmap.join_nonnulls(sep=" /// ")
554
        ).get
555
556
    def _get_moa_links(self, ref: str) -> FrozenSet[str]:
557
        return (
558
            self._mini
559
            / "Mechanism of Action"
560
            / "Information"
561
            / self._has_ref(ref)
562
            / "Value"
563
            / "StringWithMarkup"
564
            / "Markup"
565
            / Filter.key_equals("Type", "PubChem Internal Link")
566
            // ["URL"]
567
            // Flatmap.require_only()
568
            / Mapx.extract_group_1(Patterns.pubchem_compound_url)
569
            / url_unescape
570
            / Mapx.lowercase_unless_acronym()  # TODO necessary but unfortunate -- cocaine and Cocaine
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...
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
571
        ).to_set
572
573
    @property
574
    def biochem_reactions(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
575
        # TODO from multiple sources
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
576
        return frozenset({s.strip() for s in (self._tables / "pathwayreaction" >> "name").to_set})
577
578
579
class SafetyAndHazards(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
580
    """ """
581
582
    @property
583
    def _whoami(self) -> str:
584
        return "Safety and Hazards"
585
586
    @property
587
    def ghs_codes(self) -> FrozenSet[GhsCode]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
588
        codes = (
589
            self._mini
590
            / "Hazards Identification"
591
            / "Section"
592
            % "TOCHeading"
593
            / "GHS Classification"
594
            / "Information"
595
            / self._has_ref("European Chemicals Agency (ECHA)")
596
            / Filter.key_equals("Name", "GHS Hazard Statements")
597
            / "Value"
598
            / "StringWithMarkup"
599
            // ["String"]
600
            // Flatmap.require_only()
601
            / Mapx.extract_group_1(r"^(H\d+)[ :].*$")
602
            // Mapx.split_and_flatten_nonnulls("+")  # TODO: how is this being used to flatten?
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
603
        ).get
604
        return frozenset([GhsCode.find(code) for code in codes])
605
606
607
class Toxicity(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
608
    """ """
609
610
    @property
611
    def _whoami(self) -> str:
612
        return "Toxicity"
613
614
    @property
615
    def acute_effects(self) -> FrozenSet[AcuteEffectEntry]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
616
        return (
617
            self._tables
618
            / "chemidplus"
619
            // ["gid", "effect", "organism", "testtype", "route", "dose"]
620
            / [
621
                Mapx.get_int(nullable=True),
622
                Mapx.split_to(Codes.ChemIdPlusEffect.of, ";", nullable=True),
623
                Codes.ChemIdPlusOrganism.of,
624
                str,
625
                str,
626
                str,
627
            ]
628
            // Flatmap.construct(AcuteEffectEntry)
629
        ).to_set
630
631
632
class AssociatedDisordersAndDiseases(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
633
    """ """
634
635
    @property
636
    def _whoami(self) -> str:
637
        return "Associated Disorders and Diseases"
638
639
    @property
640
    def associated_disorders_and_diseases(self) -> FrozenSet[AssociatedDisorder]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
641
        return (
642
            self._tables
643
            / "ctd_chemical_disease"
644
            // ["gid", "diseaseextid", "diseasename", "directevidence", "dois"]
645
            / [
646
                str,
647
                Codes.MeshCode.of,
648
                Mapx.req_is(str),
649
                Mapx.req_is(str),
650
                Mapx.n_bar_items(null_is_zero=True),
651
            ]
652
            // Flatmap.construct(AssociatedDisorder)
653
        ).to_set
654
655
656
class Literature(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
657
    """ """
658
659
    @property
660
    def _whoami(self) -> str:
661
        return "Literature"
662
663
    @property
664
    def depositor_pubmed_articles(self) -> FrozenSet[PubmedEntry]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
665
        def split_mesh_headings(s: str) -> FrozenSet[Codes.MeshHeading]:
0 ignored issues
show
Coding Style Naming introduced by
Argument 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...
666
            # this is a nightmare
667
            # these fields are comma-delimited strings, but there are commas within each
668
            # all of the examples I've seen with this are for chem name cis/trans
669
            # we can fix those
670
            # however, there may be some left incorrectly split
671
            # and it's possible that we join some when we shouldn't
672
            # ex: 6-Cyano-7-nitroquinoxaline-2,3-dione,Animals,Anticonvulsants,Cocaine,Death, [...]
673
            # ex: 2,3,4,5-Tetrahydro-7,8-dihydroxy-1-phenyl-1H-3-benzazepine,Animals,Benzazepines, [...]
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (104/100).

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

Loading history...
674
            if s is None:
675
                return Misc.empty_frozenset
676
            bits = []
677
            current_bit = " "
678
            for bit in s.split(","):
679
                if current_bit[-1].isdigit() and bit[0].isdigit():
680
                    current_bit += bit
681
                else:
682
                    bits.append(current_bit.strip())
683
                    current_bit = bit
684
            # get the one at the end
685
            bits.append(current_bit)
686
            return frozenset({b.strip() for b in bits if b.strip() != ""})
687
688
        def split_mesh_subheadings(s: Optional[str]) -> FrozenSet[Codes.MeshSubheading]:
0 ignored issues
show
Coding Style Naming introduced by
Argument 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...
689
            if s is None:
690
                return Misc.empty_frozenset
691
            return frozenset({k.strip() for k in s.split(",") if k.strip() != ""})
692
693
        def split_mesh_codes(s: Optional[str]) -> FrozenSet[Codes.MeshCode]:
0 ignored issues
show
Coding Style Naming introduced by
Argument 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...
694
            if s is None:
695
                return Misc.empty_frozenset
696
            z = [bit.split(" ")[0] for bit in s.split(",")]
0 ignored issues
show
Coding Style Naming introduced by
Variable name "z" 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...
697
            return frozenset({b.strip() for b in z if b.strip() != ""})
698
699
        def split_sources(s: Optional[str]) -> FrozenSet[str]:
0 ignored issues
show
Coding Style Naming introduced by
Argument 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...
700
            return frozenset(s.split(","))
701
702
        def split_cids(s: Optional[str]) -> FrozenSet[int]:
0 ignored issues
show
Coding Style Naming introduced by
Argument 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...
703
            if s is None:
704
                return Misc.empty_frozenset
705
            return frozenset([int(q) for q in s.split(",")])
706
707
        def get_text(s: Optional[str]) -> Optional[str]:
0 ignored issues
show
Coding Style Naming introduced by
Argument 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...
708
            if s is None:
709
                return None
710
            return StringTools.strip_brackets_and_quotes(s.strip()).strip()
711
712
        keys = {
713
            "pmid": Codes.PubmedId.of,
714
            "articletype": Mapx.req_is(str),
715
            "pmidsrcs": split_sources,
716
            "meshheadings": split_mesh_headings,
717
            "meshsubheadings": split_mesh_subheadings,
718
            "meshcodes": split_mesh_codes,
719
            "cids": split_cids,
720
            "articletitle": get_text,
721
            "articleabstract": get_text,
722
            "articlejourname": get_text,
723
            "articlepubdate": Mapx.int_date(),
724
        }
725
        entries = (
726
            self._tables
727
            / "pubmed"
728
            // list(keys.keys())
729
            / list(keys.values())
730
            // Flatmap.construct(PubmedEntry)
731
        ).to_set
732
        return entries
733
734
    @property
735
    def chemical_cooccurrences(self) -> FrozenSet[CoOccurrence]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
736
        return self._get_cooccurrences(CoOccurrenceType.chemical)
737
738
    @property
739
    def gene_cooccurrences(self) -> FrozenSet[CoOccurrence]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
740
        return self._get_cooccurrences(CoOccurrenceType.gene)
741
742
    @property
743
    def disease_cooccurrences(self) -> FrozenSet[CoOccurrence]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
744
        return self._get_cooccurrences(CoOccurrenceType.disease)
745
746
    def _get_cooccurrences(self, kind: CoOccurrenceType) -> FrozenSet[CoOccurrence]:
747
        links = (self._links / kind.x_name / "LinkDataSet" / "LinkData").get
748
        results = set()
749
        for link in links:
750
            link = NestedDotDict(link)
751
            try:
752
                neighbor_id = str(link["ID_2"][kind.id_name])
753
            except KeyError:
754
                raise KeyError(f"Could not find ${kind.id_name} in ${link['ID_2']}")
755
            neighbor_id = self._guess_neighbor(kind, neighbor_id)
756
            evidence = link["Evidence"][kind.x_name]
757
            neighbor_name = evidence["NeighborName"]
758
            ac = evidence["ArticleCount"]
0 ignored issues
show
Coding Style Naming introduced by
Variable name "ac" 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...
759
            nac = evidence["NeighborArticleCount"]
760
            qac = evidence["QueryArticleCount"]
761
            score = evidence["CooccurrenceScore"]
762
            articles = [NestedDotDict(k) for k in evidence["Article"]]
763
            pubs = {
764
                Publication(
765
                    pmid=Codes.PubmedId.of(pub["PMID"]),
766
                    pub_date=datetime.strptime(pub["PublicationDate"].strip(), "%Y-%m-%d").date(),
767
                    is_review=bool(pub["IsReview"]),
768
                    title=pub["Title"].strip(),
769
                    journal=pub["Journal"].strip(),
770
                    relevance_score=pub.req_as("RelevanceScore", int),
771
                )
772
                for pub in articles
773
            }
774
            results.add(
775
                CoOccurrence(
776
                    neighbor_id=neighbor_id,
777
                    neighbor_name=neighbor_name,
778
                    kind=kind,
779
                    article_count=ac,
780
                    query_article_count=qac,
781
                    neighbor_article_count=nac,
782
                    score=score,
783
                    publications=frozenset(pubs),
784
                )
785
            )
786
        return frozenset(results)
787
788
    def _guess_neighbor(self, kind: CoOccurrenceType, neighbor_id: str) -> str:
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
789
        if kind is CoOccurrenceType.chemical:
0 ignored issues
show
unused-code introduced by
Unnecessary "elif" after "return"
Loading history...
790
            return Codes.PubchemCompoundId(neighbor_id)
791
        elif kind is CoOccurrenceType.gene and neighbor_id.startswith("EC:"):
792
            return Codes.EcNumber(neighbor_id)
793
        elif kind is CoOccurrenceType.gene:
794
            return Codes.GeneId(neighbor_id)
795
        elif kind is CoOccurrenceType.disease:
796
            return Codes.MeshCode(neighbor_id)
797
        else:
798
            raise ValueError(f"Could not find ID type for {kind} ID {neighbor_id}")
799
800
801
class Patents(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
802
    """ """
803
804
    @property
805
    def _whoami(self) -> str:
806
        return "Patents"
807
808
    @property
809
    def associated_disorders_and_diseases(self) -> FrozenSet[AssociatedDisorder]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
810
        return (
811
            self._tables
812
            / "patent"
813
            // ["diseasename", "directevidence", "dois"]
814
            / [Mapx.req_is(str), Mapx.req_is(str), Mapx.n_bar_items()]
815
            // Flatmap.construct(AssociatedDisorder)
816
        ).to_set
817
818
819
class BiomolecularInteractionsAndPathways(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
820
    """ """
821
822
    @property
823
    def _whoami(self) -> str:
824
        return "Biomolecular Interactions and Pathways"
825
826
    @property
827
    def drug_gene_interactions(self) -> FrozenSet[DrugGeneInteraction]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
828
        # the order of this dict is crucial
829
        keys = {
830
            "genename": Mapx.req_is(str, nullable=True),
831
            "geneclaimname": Mapx.get_str(nullable=True),
832
            "interactionclaimsource": Mapx.req_is(str, nullable=True),
833
            "interactiontypes": Mapx.split("|", nullable=True),
834
            "pmids": Mapx.split(",", nullable=True),
835
            "dois": Mapx.split("|", nullable=True),
836
        }
837
        return (
838
            self._tables
839
            / "dgidb"
840
            // list(keys.keys())
841
            / list(keys.values())
842
            // Flatmap.construct(DrugGeneInteraction)
843
        ).to_set
844
845
    @property
846
    def chemical_gene_interactions(self) -> FrozenSet[ChemicalGeneInteraction]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
847
        # the order of this dict is crucial
848
        # YES, the | used in pmids really is different from the , used in DrugGeneInteraction
849
        keys = {
850
            "genesymbol": Codes.GenecardSymbol.of_nullable,
851
            "interaction": Mapx.split("|", nullable=True),
852
            "taxid": Mapx.get_int(nullable=True),
853
            "taxname": Mapx.req_is(str, True),
854
            "pmids": Mapx.split("|", nullable=True),
855
        }
856
        return (
857
            self._tables
858
            / "ctdchemicalgene"
859
            // list(keys.keys())
860
            / list(keys.values())
861
            // Flatmap.construct(ChemicalGeneInteraction)
862
        ).to_set
863
864
    @property
865
    def drugbank_interactions(self) -> FrozenSet[DrugbankInteraction]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
866
        keys = {
867
            "gid": (lambda f: None if f is None else str(int(f))),
868
            "genesymbol": Codes.GenecardSymbol.of,
869
            "drugaction": Mapx.req_is(str, nullable=True),
870
            "targetcomponentname": Mapx.req_is(str),
871
            "targettype": (lambda s: DrugbankTargetType[s.lower()]),
872
            "targetname": Mapx.req_is(str),
873
            "generalfunc": Mapx.req_is(str, nullable=True),
874
            "specificfunc": Mapx.req_is(str, nullable=True),
875
            "pmids": Mapx.split(",", nullable=True),
876
            "dois": Mapx.split("|", nullable=True),
877
        }
878
        return (
879
            self._tables
880
            / "drugbank"
881
            // list(keys.keys())
882
            / list(keys.values())
883
            // Flatmap.construct(DrugbankInteraction)
884
        ).to_set
885
886
    @property
887
    def drugbank_legal_groups(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
888
        q = set()
0 ignored issues
show
Coding Style Naming introduced by
Variable name "q" 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...
889
        for x in (self._tables / "drugbank" // ["druggroup"] // Flatmap.require_only()).to_set:
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...
890
            for y in x.split(";"):
0 ignored issues
show
Coding Style Naming introduced by
Variable name "y" 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...
891
                q.add(y.strip())
892
        return frozenset(q)
893
894
    @property
895
    def drugbank_ddis(self) -> FrozenSet[DrugbankDdi]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
896
        keys = {
897
            "dbid2": Codes.DrugbankCompoundId,
898
            "cid2": Codes.PubchemCompoundId,
899
            "name": Mapx.req_is(str),
900
            "descr": Mapx.req_is(str),
901
        }
902
        return (
903
            self._tables
904
            / "drugbankddi"
905
            // list(keys.keys())
906
            / list(keys.values())
907
            // Flatmap.construct(DrugbankDdi)
908
        ).to_set
909
910
911
class BiologicalTestResults(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
912
    """ """
913
914
    @property
915
    def _whoami(self) -> str:
916
        return "Biological Test Results"
917
918
    @property
919
    def bioactivity(self) -> FrozenSet[Bioactivity]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
920
        keys = {
921
            "aid": Mapx.get_int,
922
            "aidtype": Mapx.req_is(str, nullable=False),
923
            "aidsrcname": Mapx.req_is(str, nullable=True),
924
            "aidname": Mapx.req_is(str, nullable=True),
925
            "aidmdate": Mapx.int_date(nullable=True),
926
            "geneid": Codes.GeneId.of_nullable,
927
            "taxid": Mapx.str_to(str, flex_type=True, nullable=True),
928
            "pmid": Codes.PubmedId.of_nullable,
929
            "activity": (lambda s: None if s is None else Activity[s.lower()]),
930
            "acname": Mapx.str_to(str, nullable=True),
931
            "acvalue": (lambda x: None if x is None else float(x)),
932
            "targetname": Mapx.req_is(str, nullable=True),
933
            "cmpdname": Mapx.req_is(str, nullable=False),
934
        }
935
        return (
936
            self._tables
937
            / "bioactivity"
938
            // list(keys.keys())
939
            / FilterFn(lambda lst: lst[11] is not None)
940
            / list(keys.values())
941
            // Flatmap.construct(Bioactivity)
942
        ).to_set
943
944
945
class Classification(PubchemMiniDataView):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
946
    """ """
947
948
    @property
949
    def _whoami(self) -> str:
950
        return "Classification"
951
952
    @property
953
    def mesh_tree(self) -> Sequence[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
954
        raise NotImplementedError()
955
956
    @property
957
    def chebi_tree(self) -> Sequence[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
958
        raise NotImplementedError()
959
960
    @property
961
    def atc_tree(self) -> FrozenSet[Sequence[str]]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
962
        raise NotImplementedError()
963
964
    @property
965
    def chemid(self) -> FrozenSet[Sequence[str]]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
966
        raise NotImplementedError()
967
968
    @property
969
    def g2p_tree(self) -> FrozenSet[Sequence[str]]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
970
        raise NotImplementedError()
971
972
    @property
973
    def chembl_tree(self) -> FrozenSet[Sequence[str]]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
974
        raise NotImplementedError()
975
976
    @property
977
    def cpdat_tree(self) -> FrozenSet[Sequence[str]]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
978
        raise NotImplementedError()
979
980
    @property
981
    def dea(self) -> FrozenSet[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
982
        raise NotImplementedError()
983
984
985
class PubchemData(PubchemDataView):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
986
    @property
987
    def name(self) -> Optional[str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
988
        return self._data.get("record.RecordTitle")
989
990
    @property
991
    def title_and_summary(self) -> TitleAndSummary:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
992
        return TitleAndSummary(self._data)
993
994
    @property
995
    def names_and_identifiers(self) -> NamesAndIdentifiers:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
996
        return NamesAndIdentifiers(self._data)
997
998
    @property
999
    def chemical_and_physical_properties(self) -> ChemicalAndPhysicalProperties:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1000
        return ChemicalAndPhysicalProperties(self._data)
1001
1002
    @property
1003
    def related_records(self) -> RelatedRecords:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1004
        return RelatedRecords(self._data)
1005
1006
    @property
1007
    def drug_and_medication_information(self) -> DrugAndMedicationInformation:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1008
        return DrugAndMedicationInformation(self._data)
1009
1010
    @property
1011
    def pharmacology_and_biochemistry(self) -> PharmacologyAndBiochemistry:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1012
        return PharmacologyAndBiochemistry(self._data)
1013
1014
    @property
1015
    def safety_and_hazards(self) -> SafetyAndHazards:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1016
        return SafetyAndHazards(self._data)
1017
1018
    @property
1019
    def toxicity(self) -> Toxicity:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1020
        return Toxicity(self._data)
1021
1022
    @property
1023
    def literature(self) -> Literature:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1024
        return Literature(self._data)
1025
1026
    @property
1027
    def associated_disorders_and_diseases(self) -> AssociatedDisordersAndDiseases:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1028
        return AssociatedDisordersAndDiseases(self._data)
1029
1030
    @property
1031
    def biomolecular_interactions_and_pathways(self) -> BiomolecularInteractionsAndPathways:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1032
        return BiomolecularInteractionsAndPathways(self._data)
1033
1034
    @property
1035
    def biological_test_results(self) -> BiologicalTestResults:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1036
        return BiologicalTestResults(self._data)
1037
1038
    @property
1039
    def classification(self) -> Classification:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1040
        return Classification(self._data)
1041
1042
    @property
1043
    def parent_or_none(self) -> Optional[int]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1044
        return self.related_records.parent
1045
1046
    @property
1047
    def parent_or_self(self) -> int:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
1048
        parent = self.related_records.parent
1049
        return self.cid if parent is None else parent
1050
1051
1052
__all__ = [
1053
    "PubchemData",
1054
    "TitleAndSummary",
1055
    "RelatedRecords",
1056
    "ChemicalAndPhysicalProperties",
1057
    "DrugAndMedicationInformation",
1058
    "PharmacologyAndBiochemistry",
1059
    "SafetyAndHazards",
1060
    "Toxicity",
1061
    "AssociatedDisordersAndDiseases",
1062
    "Literature",
1063
    "NamesAndIdentifiers",
1064
    "BiomolecularInteractionsAndPathways",
1065
    "Classification",
1066
]
1067