Passed
Push — main ( e0f181...a5d2a4 )
by Douglas
01:37
created

pocketutils.misc.resources   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 102
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 73
dl 0
loc 102
rs 10
c 0
b 0
f 0
wmc 19

8 Methods

Rating   Name   Duplication   Size   Complexity  
A MandosResources.path() 0 9 4
A MandosResources.check_expired() 0 19 4
A MandosResources.a_file() 0 12 2
A MandosResources.file() 0 8 3
A MandosResources.json_dict() 0 5 1
A MandosResources.json() 0 5 1
A MandosResources.contains() 0 3 1
A MandosResources.dir() 0 6 3
1
import logging
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
import os
3
import typing
4
from dataclasses import dataclass
5
from datetime import datetime, timedelta
6
from pathlib import Path
7
from typing import MutableMapping, Optional, Any, Union
8
9
import orjson
0 ignored issues
show
introduced by
Unable to import 'orjson'
Loading history...
10
from pocketutils.core.chars import Chars
11
from pocketutils.core.dot_dict import NestedDotDict
12
from pocketutils.core.exceptions import FileDoesNotExistError, MissingResourceError, PathExistsError
13
from pocketutils.tools.common_tools import CommonTools
14
from pocketutils.tools.unit_tools import UnitTools
15
16
17
logger = logging.getLogger("pocketutils")
18
19
20
@dataclass(frozen=True, repr=True)
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
21
class MandosResources:
22
    resource_dir: Path
23
    logger: Any = logger
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable logger does not seem to be defined.
Loading history...
24
25
    def contains(self, *nodes: Union[Path, str], suffix: Optional[str] = None) -> bool:
26
        """Returns whether a resource file (or dir) exists."""
27
        return self.path(*nodes, suffix=suffix).exists()
28
29
    def path(
30
        self, *nodes: Union[Path, str], suffix: Optional[str] = None, exists: bool = False
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
31
    ) -> Path:
32
        """Gets a path of a test resource file under ``resources/``."""
33
        path = Path(self.resource_dir, "resources", *nodes)
34
        path = path.with_suffix(path.suffix if suffix is None else suffix)
35
        if exists and not path.exists():
36
            raise MissingResourceError(f"Resource {path} missing")
37
        return path
38
39
    def file(self, *nodes: Union[Path, str], suffix: Optional[str] = None) -> Path:
40
        """Gets a path of a test resource file under ``resources/``."""
41
        path = self.path(*nodes, suffix=suffix)
42
        if not path.is_file():
43
            raise PathExistsError(f"Resource {path} is not a file!")
44
        if not os.access(path, os.R_OK):
45
            raise FileDoesNotExistError(f"Resource {path} is not readable")
46
        return path
47
48
    def dir(self, *nodes: Union[Path, str]) -> Path:
49
        """Gets a path of a test resource file under ``resources/``."""
50
        path = self.path(*nodes)
51
        if not path.is_dir() and not path.is_mount():
52
            raise PathExistsError(f"Resource {path} is not a directory!")
53
        return path
54
55
    def a_file(self, *nodes: Union[Path, str], suffixes: Optional[typing.Set[str]] = None) -> Path:
56
        """Gets a path of a test resource file under ``resources/``, ignoring suffix."""
57
        path = Path(self.resource_dir, "resources", *nodes)
58
        options = [
59
            p
60
            for p in path.parent.glob(path.stem + "*")
61
            if p.is_file() and (suffixes is None or p.suffix in suffixes)
62
        ]
63
        try:
64
            return CommonTools.only(options)
65
        except LookupError:
66
            raise MissingResourceError(f"Resource {path} missing") from None
67
68
    def json(self, *nodes: Union[Path, str], suffix: Optional[str] = None) -> NestedDotDict:
69
        """Reads a JSON file under ``resources/``."""
70
        path = self.path(*nodes, suffix=suffix)
71
        data = orjson.loads(Path(path).read_text(encoding="utf8"))
72
        return NestedDotDict(data)
73
74
    def json_dict(self, *nodes: Union[Path, str], suffix: Optional[str] = None) -> MutableMapping:
75
        """Reads a JSON file under ``resources/``."""
76
        path = self.path(*nodes, suffix=suffix)
77
        data = orjson.loads(Path(path).read_text(encoding="utf8"))
78
        return data
79
80
    def check_expired(self, path: Path, max_sec: Union[timedelta, int], what: str) -> bool:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
81
        if isinstance(max_sec, timedelta):
82
            max_sec = max_sec.total_seconds()
83
        # getting the mod date because creation dates are iffy cross-platform
84
        # (in fact the Linux kernel doesn't bother to expose them)
85
        when = datetime.fromtimestamp(path.stat().st_mtime)
86
        delta_sec = (datetime.now() - when).total_seconds()
87
        if delta_sec > max_sec:
88
            delta_str = UnitTools.delta_time_to_str(Chars.narrownbsp)
89
            if delta_sec > 60 * 60 * 24 * 2:
90
                self.logger.warning(
91
                    f"{what} may be {delta_str} out of date. [downloaded: {when.strftime('%Y-%m-%d')}]"
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...
92
                )
93
            else:
94
                self.logger.warning(
95
                    f"{what} may be {delta_str} out of date. [downloaded: {when.strftime('%Y-%m-%d %H:%M:%s')}]"
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (112/100).

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

Loading history...
96
                )
97
            return True
98
        return False
99
100
101
__all__ = ["MandosResources"]
102