File: source.py

package info (click to toggle)
python-asusrouter 1.21.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,856 kB
  • sloc: python: 20,497; makefile: 3
file content (137 lines) | stat: -rw-r--r-- 3,647 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
"""Source module."""

from __future__ import annotations

from datetime import UTC, datetime, timedelta
from enum import StrEnum
from typing import Any

from asusrouter.const import UNKNOWN_MEMBER_STR
from asusrouter.tools.enum import FromStrMixin
from asusrouter.tools.types import ARCallbackType


class ARDataSource:
    """AsusRouter data source.

    This is a universal class representing a data source
    within the AsusRouter ecosystem.
    """

    def __init__(self) -> None:
        """Initialize the data source."""


class ARDataType(FromStrMixin, StrEnum):
    """AsusRouter static data types."""

    UNKNOWN = UNKNOWN_MEMBER_STR


class ARDataState:
    """AsusRouter data state class.

    Instances of this class hold information on the data
    and time of the last update.
    """

    def __init__(self, source: ARDataSource | ARDataType) -> None:
        """Initialize the data state."""

        if not isinstance(source, ARDataSource | ARDataType):
            raise TypeError(
                "A valid `ARDataSource` or `ARDataType` is required "
                "to initialize an <ARDataState>. "
                f"Received: {type(source)}."
            )

        self._source: ARDataSource | ARDataType = source
        self._content: Any | None = None
        self._last_update: datetime | None = None
        self._callback: ARCallbackType | None = None

    def update(self, content: Any) -> None:
        """Update the last update timestamp to the current time."""

        self._content = content
        self._last_update = datetime.now(UTC)

    def is_fresh(self, threshold: timedelta) -> bool:
        """Check if the data is fresh based on the given threshold."""

        if not isinstance(threshold, timedelta):
            raise TypeError(
                "A valid `timedelta` is required to define if the data "
                "is fresh."
            )

        if self._last_update is None:
            return False

        return self._last_update + threshold > datetime.now(UTC)

    @property
    def content(self) -> Any | None:
        """Get the content."""

        return self._content

    @property
    def last_update(self) -> datetime | None:
        """Get the last update timestamp."""

        return self._last_update

    @property
    def callback(self) -> ARCallbackType | None:
        """Get the callback function."""

        return self._callback

    @callback.setter
    def callback(self, value: ARCallbackType | None) -> None:
        """Set the callback function."""

        self._callback = value


class ARDataStateStatic(ARDataState):
    """AsusRouter static data state class.

    This class represents a static data, meaning it can be directly
    fetched without providing any additional context.
    """

    def __init__(self, source: ARDataType) -> None:
        """Initialize the static data state."""

        super().__init__(source)

    @property
    def source(self) -> ARDataType:
        """Get the static data source."""

        return ARDataType.from_value(self._source)


class ARDataStateDynamic(ARDataState):
    """AsusRouter dynamic data state class.

    This class represents a dynamic data state that can change
    over time and requires context to be fetched.
    """

    def __init__(self, source: ARDataSource) -> None:
        """Initialize the dynamic data state."""

        super().__init__(source)

    @property
    def source(self) -> ARDataSource:
        """Get the dynamic data source."""

        return (
            self._source
            if isinstance(self._source, ARDataSource)
            else ARDataSource()
        )