Skip to content

Commit 6e49cfe

Browse files
committed
refactor: remove pydantic and standardize type hints with mypy CI
1 parent 1862c67 commit 6e49cfe

File tree

12 files changed

+262
-164
lines changed

12 files changed

+262
-164
lines changed

.github/workflows/type_check.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Type Check
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
type-check:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
- name: Set up Python
15+
uses: actions/setup-python@v5
16+
with:
17+
python-version: "3.10"
18+
- name: Install Dependencies
19+
run: |
20+
python -m pip install --upgrade pip
21+
pip install mypy
22+
pip install .
23+
- name: Run Mypy
24+
run: |
25+
mypy openpaygo

openpaygo/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ def decode_token(**kwargs):
1515

1616

1717
__all__ = [
18-
MetricsRequestHandler,
19-
MetricsResponseHandler,
20-
AuthMethod,
21-
OpenPAYGOTokenDecoder,
22-
OpenPAYGOTokenEncoder,
23-
TokenType,
18+
"MetricsRequestHandler",
19+
"MetricsResponseHandler",
20+
"AuthMethod",
21+
"OpenPAYGOTokenDecoder",
22+
"OpenPAYGOTokenEncoder",
23+
"TokenType",
2424
]

openpaygo/metrics_request.py

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,67 @@
11
import copy
2+
from typing import Any, Dict, List, Optional, Union
23

34
from .metrics_shared import OpenPAYGOMetricsShared
5+
from .models import MetricsDataFormat, MetricsHistoricalDataStep
46

57

68
class MetricsRequestHandler(object):
79
def __init__(
8-
self, serial_number, data_format=None, secret_key=None, auth_method=None
9-
):
10+
self,
11+
serial_number: str,
12+
data_format: Optional[Union[Dict[str, Any], MetricsDataFormat]] = None,
13+
secret_key: Optional[str] = None,
14+
auth_method: Optional[str] = None,
15+
) -> None:
1016
self.secret_key = secret_key
1117
self.auth_method = auth_method
12-
self.request_dict = {
18+
self.request_dict: Dict[str, Any] = {
1319
"serial_number": serial_number,
1420
}
15-
self.data_format = data_format
21+
if data_format is not None:
22+
self.data_format: Optional[Dict[str, Any]] = dict(data_format)
23+
else:
24+
self.data_format = None
25+
1626
if self.data_format:
1727
if self.data_format.get("id"):
18-
self.request_dict["data_format_id"] = data_format.get("id")
28+
self.request_dict["data_format_id"] = self.data_format.get("id")
1929
else:
20-
self.request_dict["data_format"] = data_format
21-
self.data = {}
22-
self.historical_data = {}
30+
self.request_dict["data_format"] = self.data_format
31+
self.data: Dict[str, Any] = {}
32+
self.historical_data: List[Dict[str, Any]] = []
2333

24-
def set_request_count(self, request_count):
34+
def set_request_count(self, request_count: int) -> None:
2535
self.request_dict["request_count"] = request_count
2636

27-
def set_timestamp(self, timestamp):
37+
def set_timestamp(self, timestamp: int) -> None:
2838
self.request_dict["timestamp"] = timestamp
2939

30-
def set_data(self, data):
40+
def set_data(self, data: Dict[str, Any]) -> None:
3141
self.data = data
3242

33-
def set_historical_data(self, historical_data):
34-
if not self.data_format.get("historical_data_interval"):
35-
for time_step in historical_data:
43+
def set_historical_data(
44+
self, historical_data: List[Union[Dict[str, Any], MetricsHistoricalDataStep]]
45+
) -> None:
46+
validated_historical_data = []
47+
for time_step in historical_data:
48+
step = dict(time_step)
49+
validated_historical_data.append(step)
50+
51+
if self.data_format and not self.data_format.get("historical_data_interval"):
52+
for time_step in validated_historical_data:
3653
if not time_step.get("timestamp"):
3754
raise ValueError(
3855
"Historical Data objects must have a time stamp if no "
3956
"historical_data_interval is defined."
4057
)
41-
self.historical_data = historical_data
58+
self.historical_data = validated_historical_data
4259

43-
def get_simple_request_payload(self):
60+
def get_simple_request_payload(self) -> str:
4461
payload = self.get_simple_request_dict()
4562
return OpenPAYGOMetricsShared.convert_to_metrics_json(payload)
4663

47-
def get_simple_request_dict(self):
64+
def get_simple_request_dict(self) -> Dict[str, Any]:
4865
simple_request = self.request_dict
4966
simple_request["data"] = self.data
5067
simple_request["historical_data"] = self.historical_data
@@ -57,17 +74,17 @@ def get_simple_request_dict(self):
5774
)
5875
return simple_request
5976

60-
def get_condensed_request_payload(self):
77+
def get_condensed_request_payload(self) -> str:
6178
payload = self.get_condensed_request_dict()
6279
return OpenPAYGOMetricsShared.convert_to_metrics_json(payload)
6380

64-
def get_condensed_request_dict(self):
81+
def get_condensed_request_dict(self) -> Dict[str, Any]:
6582
if not self.data_format:
6683
raise ValueError("No Data Format provided for condensed request")
67-
data_order = self.data_format.get("data_order")
84+
data_order = self.data_format.get("data_order") or []
6885
if self.data and not data_order:
6986
raise ValueError("Data Format does not contain data_order")
70-
historical_data_order = self.data_format.get("historical_data_order")
87+
historical_data_order = self.data_format.get("historical_data_order") or []
7188
if self.historical_data and not historical_data_order:
7289
raise ValueError("Data Format does not contain historical_data_order")
7390
condensed_request = copy.deepcopy(self.request_dict)

openpaygo/metrics_response.py

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
import copy
22
import json
33
from datetime import datetime, timedelta
4+
from typing import Any, Dict, List, Optional, Union
45

56
from .metrics_shared import OpenPAYGOMetricsShared
7+
from .models import MetricsDataFormat
68

79

810
class MetricsResponseHandler(object):
911
def __init__(
1012
self,
11-
received_metrics,
12-
data_format=None,
13-
secret_key=None,
14-
last_request_count=None,
15-
last_request_timestamp=None,
16-
):
13+
received_metrics: str,
14+
data_format: Optional[Union[Dict[str, Any], MetricsDataFormat]] = None,
15+
secret_key: Optional[str] = None,
16+
last_request_count: Optional[int] = None,
17+
last_request_timestamp: Optional[int] = None,
18+
) -> None:
1719
self.received_metrics = received_metrics
1820
self.request_dict = json.loads(received_metrics)
1921
# We convert the base variable names to simple
@@ -26,40 +28,45 @@ def __init__(
2628
self.timestamp = int(datetime.now().timestamp())
2729
else:
2830
self.timestamp = self.request_dict.get("timestamp")
29-
self.response_dict = {}
31+
self.response_dict: Dict[str, Any] = {}
3032
self.secret_key = secret_key
31-
self.data_format = data_format
3233
self.last_request_count = last_request_count
3334
self.last_request_timestamp = last_request_timestamp
35+
36+
if data_format is not None:
37+
self.data_format: Optional[Dict[str, Any]] = dict(data_format)
38+
else:
39+
self.data_format = None
40+
3441
if not self.data_format and self.request_dict.get("data_format"):
3542
self.data_format = self.request_dict.get("data_format")
3643

37-
def get_device_serial(self):
44+
def get_device_serial(self) -> str:
3845
return self.request_dict.get("serial_number")
3946

40-
def get_data_format_id(self):
47+
def get_data_format_id(self) -> Optional[int]:
4148
return self.request_dict.get("data_format_id")
4249

43-
def data_format_available(self):
50+
def data_format_available(self) -> bool:
4451
return self.data_format is not None
4552

4653
def set_device_parameters(
4754
self,
48-
secret_key=None,
49-
data_format=None,
50-
last_request_count=None,
51-
last_request_timestamp=None,
52-
):
55+
secret_key: Optional[str] = None,
56+
data_format: Optional[Union[Dict[str, Any], MetricsDataFormat]] = None,
57+
last_request_count: Optional[int] = None,
58+
last_request_timestamp: Optional[int] = None,
59+
) -> None:
5360
if secret_key:
5461
self.secret_key = secret_key
55-
if data_format:
56-
self.data_format = data_format
62+
if data_format is not None:
63+
self.data_format = dict(data_format)
5764
if last_request_count:
5865
self.last_request_count = last_request_count
5966
if last_request_timestamp:
6067
self.last_request_timestamp = last_request_timestamp
6168

62-
def is_auth_valid(self):
69+
def is_auth_valid(self) -> bool:
6370
auth_string = self.request_dict.get("auth", None)
6471
if not auth_string:
6572
return False
@@ -89,7 +96,7 @@ def is_auth_valid(self):
8996
return True
9097
return False
9198

92-
def get_simple_metrics(self):
99+
def get_simple_metrics(self) -> Dict[str, Any]:
93100
# We start the process by making a copy of the dict to work with
94101
simple_dict = copy.deepcopy(self.request_dict)
95102
simple_dict.pop("auth") if "auth" in simple_dict else None # We remove the auth
@@ -103,40 +110,40 @@ def get_simple_metrics(self):
103110
)
104111
return simple_dict
105112

106-
def get_data_timestamp(self):
113+
def get_data_timestamp(self) -> int:
107114
return self.request_dict.get("data_collection_timestamp", self.timestamp)
108115

109-
def get_request_timestamp(self):
116+
def get_request_timestamp(self) -> Optional[int]:
110117
return self.request_timestamp
111118

112-
def get_request_count(self):
119+
def get_request_count(self) -> Optional[int]:
113120
return self.request_dict.get("request_count")
114121

115-
def get_token_count(self):
122+
def get_token_count(self) -> Optional[int]:
116123
data = self._get_simple_data()
117124
return data.get("token_count")
118125

119-
def expects_token_answer(self):
126+
def expects_token_answer(self) -> bool:
120127
return self.get_token_count() is not None
121128

122-
def add_tokens_to_answer(self, token_list):
129+
def add_tokens_to_answer(self, token_list: List[str]) -> None:
123130
self.response_dict["token_list"] = token_list
124131

125-
def expects_time_answer(self):
132+
def expects_time_answer(self) -> bool:
126133
data = self._get_simple_data()
127134
if data.get("active_until_timestamp_requested", False) or data.get(
128135
"active_seconds_left_requested", False
129136
):
130137
return True
131138
return False
132139

133-
def add_time_to_answer(self, target_datetime):
140+
def add_time_to_answer(self, target_datetime: datetime) -> None:
134141
data = self._get_simple_data()
135142
if data.get("active_until_timestamp_requested", False):
136143
target_timestamp = 0
137144
if target_datetime:
138145
if target_datetime.year > 1970:
139-
target_timestamp = target_datetime.timestamp()
146+
target_timestamp = int(target_datetime.timestamp())
140147
self.response_dict["active_until_timestamp"] = target_timestamp
141148
elif data.get("active_seconds_left_requested", False):
142149
seconds_left = (
@@ -150,24 +157,24 @@ def add_time_to_answer(self, target_datetime):
150157
else:
151158
raise ValueError("No time requested")
152159

153-
def add_new_base_url_to_answer(self, new_base_url):
160+
def add_new_base_url_to_answer(self, new_base_url: str) -> None:
154161
self.add_settings_to_answer({"base_url": new_base_url})
155162

156-
def add_settings_to_answer(self, settings_dict):
163+
def add_settings_to_answer(self, settings_dict: Dict[str, Any]) -> None:
157164
if not self.response_dict.get("settings"):
158165
self.response_dict["settings"] = {}
159166
self.response_dict["settings"].update(settings_dict)
160167

161-
def add_extra_data_to_answer(self, extra_data_dict):
168+
def add_extra_data_to_answer(self, extra_data_dict: Dict[str, Any]) -> None:
162169
if not self.response_dict.get("extra_data"):
163170
self.response_dict["extra_data"] = {}
164171
self.response_dict["extra_data"].update(extra_data_dict)
165172

166-
def get_answer_payload(self):
173+
def get_answer_payload(self) -> str:
167174
payload = self.get_answer_dict()
168175
return OpenPAYGOMetricsShared.convert_to_metrics_json(payload)
169176

170-
def get_answer_dict(self):
177+
def get_answer_dict(self) -> Dict[str, Any]:
171178
# If there is not data format, we just return the full response
172179
condensed_answer = copy.deepcopy(self.response_dict)
173180
if self.secret_key:

openpaygo/models.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import Any, Dict, List, Optional
2+
try:
3+
from typing import TypedDict
4+
except ImportError:
5+
from typing_extensions import TypedDict
6+
7+
8+
class MetricsDataFormat(TypedDict, total=False):
9+
id: Optional[int]
10+
data_order: Optional[List[str]]
11+
historical_data_order: Optional[List[str]]
12+
historical_data_interval: Optional[int]
13+
14+
15+
class MetricsHistoricalDataStep(TypedDict, total=False):
16+
timestamp: Optional[int]
17+
relative_time: Optional[int]
18+
19+
20+
class MetricsRequestData(TypedDict, total=False):
21+
serial_number: str
22+
data_format_id: Optional[int]
23+
data_format: Optional[MetricsDataFormat]
24+
data: Optional[Dict[str, Any]]
25+
historical_data: Optional[List[Any]]
26+
request_count: Optional[int]
27+
timestamp: Optional[int]
28+
auth: Optional[str]

0 commit comments

Comments
 (0)