Coverage for custom_components/supernotify/common.py: 98%
54 statements
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-28 14:21 +0000
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-28 14:21 +0000
1"""Miscellaneous helper functions.
3No dependencies permitted
4"""
6import time
7from dataclasses import dataclass, field
8from typing import Any
11def format_timestamp(v: float | None) -> str | None:
12 return time.strftime("%H:%M:%S", time.localtime(v)) if v else None
15def safe_get(probably_a_dict: dict | None, key: Any, default: Any = None) -> Any:
16 probably_a_dict = probably_a_dict or {}
17 return probably_a_dict.get(key, default)
20def safe_extend(target: list, extension: list | tuple | Any) -> list:
21 if isinstance(extension, list | tuple):
22 target.extend(extension)
23 elif extension:
24 target.append(extension)
25 return target
28def ensure_list(v: Any) -> list:
29 if v is None:
30 return []
31 if isinstance(v, list):
32 return v
33 if isinstance(v, tuple):
34 return list(v)
35 return [v]
38def ensure_dict(v: Any, default: Any = None) -> dict:
39 if v is None:
40 return {}
41 if isinstance(v, dict):
42 return v
43 if isinstance(v, set | list):
44 return dict.fromkeys(v, default)
45 return {v: default}
48def update_dict_list(target: list[dict[Any, Any]], to_add: list[dict], to_remove: list[dict]) -> list[dict]:
49 updated = [d for d in target if d not in to_remove]
50 updated.extend(to_add)
51 return updated
54@dataclass
55class CallRecord:
56 elapsed: float = field()
57 domain: str | None = field(default=None)
58 service: str | None = field(default=None)
59 action_data: dict | None = field(default=None)
60 exception: str | None = field(default=None)
62 def contents(self) -> tuple:
63 if self.exception:
64 return (self.domain, self.service, self.action_data, self.exception, self.elapsed)
65 return (self.domain, self.service, self.action_data, self.elapsed)
68@dataclass
69class DebugTrace:
70 message: str | None = field(default=None)
71 title: str | None = field(default=None)
72 data: dict | None = field(default_factory=lambda: {})
73 target: list | str | None = field(default=None)
74 resolved: dict[str, dict] = field(init=False, default_factory=lambda: {})
76 def contents(self) -> tuple:
77 return (self.message, self.title, self.data, self.target, self.resolved)