Passed
Push — main ( b62157...75b58f )
by Douglas
01:42
created

SystemTools.traceback_to_dict()   A

Complexity

Conditions 5

Size

Total Lines 18
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 17
nop 2
dl 0
loc 18
rs 9.0833
c 0
b 0
f 0
1
"""
2
Low-level tools (e.g. memory management).
3
"""
4
import atexit
5
import signal
6
import sys
7
import traceback
8
from collections import Callable
0 ignored issues
show
Bug introduced by
The name Callable does not seem to exist in module collections.
Loading history...
9
from dataclasses import dataclass
10
from typing import Any, Union, Sequence, Mapping
11
12
from pocketutils.core.input_output import Writeable
0 ignored issues
show
Bug introduced by
The name core does not seem to exist in module pocketutils.
Loading history...
13
14
from pocketutils.tools.base_tools import BaseTools
15
16
17
@dataclass(frozen=True, repr=True)
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
18
class SignalHandler:
19
    name: str
20
    code: int
21
    desc: str
22
    sink: Union[Writeable, Callable[[str], Any]]
23
24
    def __call__(self):
25
        sys.stderr.write(f"~~{self.name}[{self.code}] ({self.desc})~~")
26
        traceback.print_stack(file=sys.stderr)
27
        for line in traceback.format_stack():
28
            sys.stderr.write(line)
29
30
31
@dataclass(frozen=True, repr=True)
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
32
class ExitHandler:
33
    sink: Writeable
34
35
    def __call__(self):
36
        self.sink.write(f"~~EXIT~~")
0 ignored issues
show
introduced by
Using an f-string that does not have any interpolated variables
Loading history...
37
        traceback.print_stack(file=sys.stderr)
38
        for line in traceback.format_stack():
39
            self.sink.write(line)
40
41
42
class SystemTools(BaseTools):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
43
    @classmethod
44
    def traceback_to_dict(cls, e: BaseException) -> Sequence[Mapping[str, Union[str, int]]]:
0 ignored issues
show
Coding Style Naming introduced by
Argument name "e" 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...
introduced by
Missing function or method docstring
Loading history...
45
        tb = []
0 ignored issues
show
Coding Style Naming introduced by
Variable name "tb" 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...
46
        current = None
47
        tbe = traceback.TracebackException.from_exception(e)
48
        last, count = None, 0
49
        for i, s in enumerate(tbe.stack):
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...
50
            current = dict(depth=i, filename=s.filename, line=s.line, name=s.name, repeats=None)
51
            if current == last:
52
                count += 1
53
            else:
54
                current.repeats = count
55
                tb.append(current)
56
                count = 0
57
            last = current
58
        if current is not None and current == last:
59
            tb.append(current)
60
        return tb
61
62
    @classmethod
63
    def trace_signals(cls, sink: Writeable = sys.stderr) -> None:
64
        """
65
        Registers signal handlers for all signals that log the traceback.
66
        Uses ``signal.signal``.
67
        """
68
        for sig in signal.valid_signals():
0 ignored issues
show
Bug introduced by
The Module signal does not seem to have a member named valid_signals.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
69
            handler = SignalHandler(sig.name, sig.value, signal.strsignal(sig), sink)
0 ignored issues
show
Bug introduced by
The Module signal does not seem to have a member named strsignal.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
70
            signal.signal(sig.value, handler)
71
72
    @classmethod
73
    def trace_exit(cls, sink: Writeable = sys.stderr) -> None:
74
        """
75
        Registers an exit handler via ``atexit.register`` that logs the traceback.
76
        """
77
        atexit.register(ExitHandler(sink))
78
79
80
__all__ = ["SignalHandler", "ExitHandler", "SystemTools"]
81