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

mandos.model.apis._Source.cached_from_url()   F

Complexity

Conditions 14

Size

Total Lines 29
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 24
nop 5
dl 0
loc 29
rs 3.6
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like mandos.model.apis._Source.cached_from_url() 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
import abc
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
from pathlib import Path
3
from typing import Callable, Sequence, Optional, Mapping, Any
4
5
import orjson
0 ignored issues
show
introduced by
Unable to import 'orjson'
Loading history...
6
import defusedxml.ElementTree as Xml
0 ignored issues
show
introduced by
Unable to import 'defusedxml.ElementTree'
Loading history...
7
8
from pocketutils.core.dot_dict import NestedDotDict
0 ignored issues
show
introduced by
Unable to import 'pocketutils.core.dot_dict'
Loading history...
9
from pocketutils.core.query_utils import QueryExecutor
0 ignored issues
show
introduced by
Unable to import 'pocketutils.core.query_utils'
Loading history...
10
11
12
class _Source:
13
    def __init__(self, *getters: Callable[[], Optional[str]], name: str = "unknown"):
14
        self._getters = getters
15
        self._name = name
16
17
    def _get_txt(self) -> str:
18
        for getter in self._getters:
19
            txt = getter()
20
            if txt is not None:
21
                return txt
22
            raise ValueError(f"Nothing found for {self._name} {self.__class__.__name__} source")
23
24
    @classmethod
25
    def cached_from_url(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
26
        cls,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
27
        path: Optional[Path],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
28
        url: Optional[str],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
29
        query: QueryExecutor,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
30
        query_args: Optional[Mapping[str, Any]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
31
    ):
32
        if path is not None and url is None and query is None:
0 ignored issues
show
unused-code introduced by
Unnecessary "elif" after "return"
Loading history...
33
            return cls.from_path(path)
34
        elif path is None and url is not None and query is not None:
35
            return cls.from_query(url, query, query_args)
36
        elif path is not None and url is not None and query is not None:
37
            path = Path(path)
38
            query_args = {} if query_args is None else query_args
39
40
            def load():
41
                return path.read_text(encoding="utf8") if path.exists() else None
42
43
            def save():
44
                data = query(url, encoding="utf8", **query_args)
45
                if data is not None:
46
                    if not path.exists():
47
                        path.write_text(data, encoding="utf8")
48
                return data
49
50
            # noinspection PyArgumentList
51
            return cls(load, save, name=f"Cache({path}, {url})")
52
        raise ValueError(f"Cannot create source from path {path}, url {url}, and query {query}")
53
54
    @classmethod
55
    def from_path(cls, path: Path):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
56
        path = Path(path)
57
58
        def one():
59
            return path.read_text(encoding="utf8") if path.exists() else None
60
61
        # noinspection PyArgumentList
62
        return cls(one, name=f"Cache({path})")
63
64
    @classmethod
65
    def from_query(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
66
        cls, url: str, query: QueryExecutor, query_args: Optional[Mapping[str, Any]] = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
67
    ):
68
        def two():
69
            return query(url, encoding="utf8", **query_args)
70
71
        # noinspection PyArgumentList
72
        return cls(two, name=f"Cache({url})")
73
74
75
class TextSource(_Source):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
76
    def get(self) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
77
        return self._get_txt()
78
79
80
class XmlSource(_Source):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
81
    """ """
82
83
    def get(self) -> Xml:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
84
        return Xml.fromstring(self._get_txt())
85
86
87
class JsonSource(_Source):
0 ignored issues
show
Documentation introduced by
Empty class docstring
Loading history...
88
    """ """
89
90
    def get(self) -> NestedDotDict:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
91
        return NestedDotDict(orjson.loads(self._get_txt()))
92
93
94
__all__ = ["TextSource", "XmlSource", "JsonSource"]
95