python-terminusgps 25.1.0__py3-none-any.whl → 27.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of python-terminusgps might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-terminusgps
3
- Version: 25.1.0
3
+ Version: 27.0.0
4
4
  Summary: Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more.
5
5
  Project-URL: Documentation, https://app.terminusgps.com/docs/apps/python-terminusgps/index.html
6
6
  Project-URL: Repository, https://github.com/terminusgps/python-terminusgps
@@ -13,25 +13,24 @@ terminusgps/authorizenet/subscriptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
13
13
  terminusgps/authorizenet/subscriptions/subscriptions.py,sha256=yg0rZw0Zzm3v7daLPR0PsdfCWBU6RyoE_gNPDBMkCjM,1621
14
14
  terminusgps/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  terminusgps/aws/secrets.py,sha256=MxQEmmBLpMUQ2tYAsHdCYf-7RZ84LiogdKcTsACX5dw,361
16
- terminusgps/aws/ses.py,sha256=sDca2GjMaZvUt3kUPtGCpcqHiOkij9lMV1ogZofgYUU,2372
17
16
  terminusgps/twilio/__init__.py,sha256=dYo41F2jft_eHDWSUtSpKGSRG1bewq_qClqilUJZkYM,33
18
17
  terminusgps/twilio/caller.py,sha256=TiQ4f0TDDC35he1M1iSsBM2vutdGriwtV4pc17T--6I,3552
19
- terminusgps/twilio/validators.py,sha256=NVQKppG_kjjc-etjyeQoK_W-m_HSVWF-9Ouo3qBsQnU,894
18
+ terminusgps/twilio/validators.py,sha256=nn7CCBTktNjcln6M4MR0ACxEsClgioSu89LRLgIiBZk,1112
20
19
  terminusgps/wialon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
20
  terminusgps/wialon/constants.py,sha256=n1ux68oWYWnzeZdN811Iw_Lk78KBM0YMJMoonn67uZY,1723
22
21
  terminusgps/wialon/flags.py,sha256=_NIL3mrEGhvI5YISVjimjYtUatdgOqhZPJX368MtKSU,13959
23
22
  terminusgps/wialon/logger.py,sha256=nUBsaLMaffSaAHGHAM6mFXDzix9hbNecVtA3INVtii8,968
24
- terminusgps/wialon/session.py,sha256=t3d7trBQRxnXFnex73alSSD5n2LDTZQ9VAtzUKIERto,9670
25
- terminusgps/wialon/utils.py,sha256=Y7fo9a81w84b3N39h1AmVLS-AnC3aRT5R137hIsqCHU,6723
23
+ terminusgps/wialon/session.py,sha256=THl88yfVBfRH8daKh1lmLSR8ro8TbyOokHx1Cev-En8,9638
24
+ terminusgps/wialon/utils.py,sha256=QXBksDJlC0_khuJ6n9HEYlUQB9ArM-Pvh-K0xHORvDs,6917
26
25
  terminusgps/wialon/items/__init__.py,sha256=3BVthghekMvhMQSzQgBMlD_phxmKSmp3Zvmo-z0O8Bs,211
27
- terminusgps/wialon/items/base.py,sha256=zINd7NWeq4EGQgRhq6bNfEymeyq3uojn8HD71HvhJaQ,6998
28
- terminusgps/wialon/items/resource.py,sha256=qmQKEakJa9LH5YkI9-iBDA0hsotc5ctcwdb7kZuXdfQ,14549
29
- terminusgps/wialon/items/retranslator.py,sha256=8q9EDc92w92MElnHIeEzH3Ra4kiPXrx4t9V5nPDZuRU,3728
30
- terminusgps/wialon/items/route.py,sha256=PTJx1gmT_PGz7nlSSUS2VzjYD-aAuvkEOIdIFneUSSQ,1148
31
- terminusgps/wialon/items/unit.py,sha256=uHQrauVkh2556kZp0Dh3WLZvQ6WJIWkibGgPYW1ljPE,9177
32
- terminusgps/wialon/items/unit_group.py,sha256=Stp-WfCGbOqcnxV6FU1AKtV7KIxIwCHa0NwhNJfgRoM,5032
33
- terminusgps/wialon/items/user.py,sha256=INwAibQVmjNNelepQXMfDevgJqMvIjHHgEjAMLRvhB0,7082
34
- python_terminusgps-25.1.0.dist-info/METADATA,sha256=bv2UTsbtSyVsyWHrhD2LFs_iz1MID6Nyn_CrMLGJpw8,946
35
- python_terminusgps-25.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
36
- python_terminusgps-25.1.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
37
- python_terminusgps-25.1.0.dist-info/RECORD,,
26
+ terminusgps/wialon/items/base.py,sha256=GCSzhDc3bk-jltWYNL60BEYCeSNRsPWos5aeFvgye8Y,7208
27
+ terminusgps/wialon/items/resource.py,sha256=vNR6hJmf23RxsqXpDhM0dODbQB8KKTKcy6ncjpEZty8,14610
28
+ terminusgps/wialon/items/retranslator.py,sha256=vauuaLoEdKQF0FnOvJfksmLKsIlxvGZxt80dLTh3SVs,3789
29
+ terminusgps/wialon/items/route.py,sha256=8SzlqNmpYVdt-ZAY--B_KHoDIHgN0Zb7KBsBWAzoz3s,1209
30
+ terminusgps/wialon/items/unit.py,sha256=i7sQiRu3N0XxyTHVN2RnmjYy9X48KdnZLSB18ic37w8,9363
31
+ terminusgps/wialon/items/unit_group.py,sha256=YsYh34l2DjSKcv5SIZkEVi5FSjveGB1gxU2fwdLyvl4,4101
32
+ terminusgps/wialon/items/user.py,sha256=PFYBie04F16YE2B5364PLxkmlTmQr4sZXpItvRBxsDc,7143
33
+ python_terminusgps-27.0.0.dist-info/METADATA,sha256=z36oD2rqxZYskS3SuUT3pqdXzt8ZWmIjVL3MUOBhmZs,946
34
+ python_terminusgps-27.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
35
+ python_terminusgps-27.0.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
36
+ python_terminusgps-27.0.0.dist-info/RECORD,,
@@ -11,6 +11,12 @@ def validate_phone_number(value: str) -> None:
11
11
  code="invalid",
12
12
  params={"value": value},
13
13
  )
14
+ if not value[1:].isdigit():
15
+ raise ValidationError(
16
+ _("Phone number must be '+' followed by a digit, got '%(value)s'"),
17
+ code="invalid",
18
+ params={"value": value},
19
+ )
14
20
  if len(value) < min_length:
15
21
  raise ValidationError(
16
22
  _("Phone number cannot be less than %(min)s characters, got %(len)s."),
@@ -75,131 +75,119 @@ class WialonBase:
75
75
 
76
76
  :param new_name: A new name.
77
77
  :type new_name: :py:obj:`str`
78
+ :raises WialonError: If something goes wrong with Wialon.
78
79
  :returns: Nothing.
79
80
  :rtype: :py:obj:`None`
80
81
 
81
82
  """
82
-
83
83
  self.session.wialon_api.item_update_name(
84
84
  **{"itemId": self.id, "name": new_name}
85
85
  )
86
86
 
87
- def add_afield(self, field: tuple[str, str]) -> None:
87
+ def add_afield(self, key: str, value: str) -> None:
88
88
  """
89
89
  Adds an admin field to the Wialon object.
90
90
 
91
- :param field: A tuple containing the name of the field and the value of the field.
92
- :type field: :py:obj:`tuple`
91
+ :param key: A key (name) for the admin field.
92
+ :type key: :py:obj:`str`
93
+ :param value: A value for the admin field.
94
+ :type value: :py:obj:`str`
95
+ :raises WialonError: If something goes wrong with Wialon.
93
96
  :returns: Nothing.
94
97
  :rtype: :py:obj:`None`
95
98
 
96
99
  """
97
-
98
100
  self.session.wialon_api.item_update_admin_field(
99
- **{
100
- "itemId": self.id,
101
- "id": 0,
102
- "callMode": "create",
103
- "n": field[0],
104
- "v": field[1],
105
- }
101
+ **{"itemId": self.id, "id": 0, "callMode": "create", "n": key, "v": value}
106
102
  )
107
103
 
108
- def update_afield(self, field_id: int, field: tuple[str, str]) -> None:
104
+ def update_afield(self, id: int, key: str, value: str) -> None:
109
105
  """
110
- Updates an admin field by id to the Wialon object.
106
+ Updates an admin field by id.
111
107
 
112
- :param field_id: The admin field id.
113
- :type field_id: :py:obj:`int`
114
- :param field: A tuple containing the name of the field and the value of the field.
115
- :type field: :py:obj:`tuple`
108
+ :param id: The admin field id.
109
+ :type id: :py:obj:`int`
110
+ :param key: A key (name) for the admin field.
111
+ :type key: :py:obj:`str`
112
+ :param value: A value for the admin field.
113
+ :type value: :py:obj:`str`
114
+ :raises WialonError: If something goes wrong with Wialon.
116
115
  :returns: Nothing.
117
116
  :rtype: :py:obj:`None`
118
117
 
119
118
  """
120
-
121
119
  self.session.wialon_api.item_update_admin_field(
122
- **{
123
- "itemId": self.id,
124
- "id": field_id,
125
- "callMode": "update",
126
- "n": field[0],
127
- "v": field[1],
128
- }
120
+ **{"itemId": self.id, "id": id, "callMode": "update", "n": key, "v": value}
129
121
  )
130
122
 
131
- def add_cfield(self, field: tuple[str, str]) -> None:
123
+ def add_cfield(self, key: str, value: str) -> None:
132
124
  """
133
125
  Adds a custom field to the Wialon object.
134
126
 
135
- :param field: A tuple containing the name of the field and the value of the field.
136
- :type field: :py:obj:`tuple`
127
+ :param key: A key (name) for the custom field.
128
+ :type key: :py:obj:`str`
129
+ :param value: A value for the custom field.
130
+ :type value: :py:obj:`str`
131
+ :raises WialonError: If something goes wrong with Wialon.
137
132
  :returns: Nothing.
138
133
  :rtype: :py:obj:`None`
139
134
 
140
135
  """
141
-
142
136
  self.session.wialon_api.item_update_custom_field(
143
- **{
144
- "itemId": self.id,
145
- "id": 0,
146
- "callMode": "create",
147
- "n": field[0],
148
- "v": field[1],
149
- }
137
+ **{"itemId": self.id, "id": 0, "callMode": "create", "n": key, "v": value}
150
138
  )
151
139
 
152
- def update_cfield(self, field_id: int, field: tuple[str, str]) -> None:
140
+ def update_cfield(self, id: int, key: str, value: str) -> None:
153
141
  """
154
142
  Updates a custom field by id.
155
143
 
156
- :param field_id: The admin field id.
157
- :type field_id: :py:obj:`int`
158
- :param field: A tuple containing the name of the field and the value of the field.
159
- :type field: :py:obj:`tuple`
144
+ :param id: The admin field id.
145
+ :type id: :py:obj:`int`
146
+ :param field: A key (name) for the custom field.
147
+ :type field: :py:obj:`str`
148
+ :param field: A value for the custom field.
149
+ :type field: :py:obj:`str`
150
+ :raises WialonError: If something goes wrong with Wialon.
160
151
  :returns: Nothing.
161
152
  :rtype: :py:obj:`None`
162
153
 
163
154
  """
164
-
165
155
  self.session.wialon_api.item_update_custom_field(
166
- **{
167
- "itemId": self.id,
168
- "id": field_id,
169
- "callMode": "update",
170
- "n": field[0],
171
- "v": field[1],
172
- }
156
+ **{"itemId": self.id, "id": id, "callMode": "update", "n": key, "v": value}
173
157
  )
174
158
 
175
- def add_cproperty(self, property: tuple[str, str]) -> None:
159
+ def add_cproperty(self, key: str, value: str) -> None:
176
160
  """
177
161
  Adds a custom property to the Wialon object.
178
162
 
179
- :param property: A tuple containing the name of the property and the value of the property.
180
- :type property: :py:obj:`tuple`
163
+ :param key: A key (name) for the custom property.
164
+ :type key: :py:obj:`str`
165
+ :param value: A value for the custom property.
166
+ :type value: :py:obj:`str`
167
+ :raises WialonError: If something goes wrong with Wialon.
181
168
  :returns: Nothing.
182
169
  :rtype: :py:obj:`None`
183
170
 
184
171
  """
185
-
186
172
  self.session.wialon_api.item_update_custom_property(
187
- **{"itemId": self.id, "name": property[0], "value": property[1]}
173
+ **{"itemId": self.id, "name": key, "value": value}
188
174
  )
189
175
 
190
- def add_profile_field(self, field: tuple[str, str]) -> None:
176
+ def add_profile_field(self, key: str, value: str) -> None:
191
177
  """
192
178
  Adds a profile field to the Wialon object.
193
179
 
194
- :param field: A tuple containing the name of the field and the value of the field.
195
- :type field: :py:obj:`tuple`
180
+ :param key: A key (name) for the profile field.
181
+ :type key: :py:obj:`str`
182
+ :param value: A value for the profile field.
183
+ :type value: :py:obj:`str`
184
+ :raises WialonError: If something goes wrong with Wialon.
196
185
  :returns: Nothing.
197
186
  :rtype: :py:obj:`None`
198
187
 
199
188
  """
200
-
201
189
  self.session.wialon_api.item_update_profile_field(
202
- **{"itemId": self.id, "n": field[0], "v": field[1]}
190
+ **{"itemId": self.id, "n": key, "v": value}
203
191
  )
204
192
 
205
193
  def delete(self) -> None:
@@ -211,12 +199,11 @@ class WialonBase:
211
199
  :rtype: :py:obj:`None`
212
200
 
213
201
  """
214
-
215
202
  self.session.wialon_api.item_delete_item(**{"itemId": self.id})
216
203
 
217
204
  @property
218
- def cfields(self) -> dict:
219
- """Custom fields associated with the Wialon object."""
205
+ def cfields(self) -> dict[str, str]:
206
+ """Custom fields for the Wialon object."""
220
207
  response = self.session.wialon_api.core_search_item(
221
208
  **{"id": self.id, "flags": flags.DATAFLAG_UNIT_CUSTOM_FIELDS}
222
209
  )
@@ -224,8 +211,8 @@ class WialonBase:
224
211
  return {field["n"]: field["v"] for field in fields.values()} if fields else {}
225
212
 
226
213
  @property
227
- def afields(self) -> dict:
228
- """Admin fields associated with the Wialon object."""
214
+ def afields(self) -> dict[str, str]:
215
+ """Admin fields for the Wialon object."""
229
216
  response = self.session.wialon_api.core_search_item(
230
217
  **{"id": self.id, "flags": flags.DATAFLAG_UNIT_ADMIN_FIELDS}
231
218
  )
@@ -34,7 +34,11 @@ class WialonResource(WialonBase):
34
34
  "skipCreatorCheck": int(skip_creator_check),
35
35
  }
36
36
  )
37
- return int(response.get("item", {}).get("id")) if response.get("item") else None
37
+ return (
38
+ int(response.get("item", {}).get("id"))
39
+ if response and response.get("item")
40
+ else None
41
+ )
38
42
 
39
43
  def delete(self) -> None:
40
44
  """
@@ -30,7 +30,11 @@ class WialonRetranslator(WialonBase):
30
30
  "dataFlags": flags.DATAFLAG_UNIT_BASE,
31
31
  }
32
32
  )
33
- return int(response.get("item", {}).get("id")) if response.get("item") else None
33
+ return (
34
+ int(response.get("item", {}).get("id"))
35
+ if response and response.get("item")
36
+ else None
37
+ )
34
38
 
35
39
  def update_config(self, new_config: dict) -> None:
36
40
  """
@@ -27,4 +27,8 @@ class WialonRoute(WialonBase):
27
27
  "dataFlags": flags.DATAFLAG_UNIT_BASE,
28
28
  }
29
29
  )
30
- return int(response.get("item", {}).get("id")) if response.get("item") else None
30
+ return (
31
+ int(response.get("item", {}).get("id"))
32
+ if response and response.get("item")
33
+ else None
34
+ )
@@ -36,7 +36,11 @@ class WialonUnit(WialonBase):
36
36
  "dataFlags": flags.DATAFLAG_UNIT_BASE,
37
37
  }
38
38
  )
39
- return int(response.get("item", {}).get("id")) if response.get("item") else None
39
+ return (
40
+ int(response.get("item", {}).get("id"))
41
+ if response and response.get("item")
42
+ else None
43
+ )
40
44
 
41
45
  def populate(self) -> None:
42
46
  super().populate()
@@ -48,17 +52,22 @@ class WialonUnit(WialonBase):
48
52
  ),
49
53
  }
50
54
  )
51
- if response is not None:
55
+ if response:
52
56
  item = response.get("item", {})
53
57
  self._imei_number = item.get("uid")
54
58
  self._active = item.get("act", False)
55
59
  self._image_uri = item.get("uri")
56
60
 
57
- def get_position(self) -> dict:
61
+ def get_position(self) -> dict | None:
58
62
  return self.session.wialon_api.core_search_item(
59
63
  **{"id": self.id, "flags": flags.DATAFLAG_UNIT_POSITION}
60
64
  )
61
65
 
66
+ @property
67
+ def position(self) -> dict | None:
68
+ """Current GPS position of the unit."""
69
+ return self.get_position()
70
+
62
71
  @property
63
72
  def exists(self) -> bool:
64
73
  """Whether or not the unit exists in Wialon."""
@@ -118,7 +127,6 @@ class WialonUnit(WialonBase):
118
127
  :rtype: :py:obj:`None`
119
128
 
120
129
  """
121
-
122
130
  self.session.wialon_api.unit_exec_cmd(
123
131
  **{
124
132
  "itemId": self.id,
@@ -141,7 +149,6 @@ class WialonUnit(WialonBase):
141
149
  :rtype: :py:obj:`None`
142
150
 
143
151
  """
144
-
145
152
  self.session.wialon_api.unit_update_access_password(
146
153
  **{"itemId": self.id, "accessPassword": password}
147
154
  )
@@ -155,7 +162,6 @@ class WialonUnit(WialonBase):
155
162
  :rtype: :py:obj:`None`
156
163
 
157
164
  """
158
-
159
165
  self.session.wialon_api.unit_set_active(
160
166
  **{"itemId": self.id, "active": int(True)}
161
167
  )
@@ -169,7 +175,6 @@ class WialonUnit(WialonBase):
169
175
  :rtype: :py:obj:`None`
170
176
 
171
177
  """
172
-
173
178
  self.session.wialon_api.unit_set_active(
174
179
  **{"itemId": self.id, "active": int(False)}
175
180
  )
@@ -185,7 +190,6 @@ class WialonUnit(WialonBase):
185
190
  :rtype: :py:obj:`None`
186
191
 
187
192
  """
188
-
189
193
  self.session.wialon_api.unit_update_phone(
190
194
  **{"itemId": self.id, "phoneNumber": quote_plus(phone)}
191
195
  )
@@ -194,14 +198,13 @@ class WialonUnit(WialonBase):
194
198
  """
195
199
  Retrieves all phone numbers assigned to the unit.
196
200
 
197
- This includes any attached drivers, custom/admin fields, or otherwise assigned phone numbers.
201
+ This includes any attached drivers, custom/admin fields or otherwise assigned phone numbers.
198
202
 
199
203
  :raises WialonError: If something goes wrong with Wialon.
200
204
  :returns: A list of phone numbers.
201
205
  :rtype: :py:obj:`list`
202
206
 
203
207
  """
204
-
205
208
  phone_numbers: list[str] = []
206
209
  phones_0: list[str] | None = self._get_driver_phone_numbers()
207
210
  phones_1: list[str] | None = self._get_cfield_phone_numbers()
@@ -17,7 +17,6 @@ class WialonUnitGroup(WialonBase):
17
17
  :rtype: :py:obj:`int` | :py:obj:`None`
18
18
 
19
19
  """
20
-
21
20
  if isinstance(creator_id, str) and not creator_id.isdigit():
22
21
  raise ValueError(f"'creator_id' must be a digit, got '{creator_id}'.")
23
22
 
@@ -28,7 +27,11 @@ class WialonUnitGroup(WialonBase):
28
27
  "dataFlags": flags.DATAFLAG_UNIT_BASE,
29
28
  }
30
29
  )
31
- return int(response.get("item", {}).get("id")) if response.get("item") else None
30
+ return (
31
+ int(response.get("item", {}).get("id"))
32
+ if response and response.get("item")
33
+ else None
34
+ )
32
35
 
33
36
  def set_items(self, new_items: list[str]) -> None:
34
37
  """
@@ -41,7 +44,6 @@ class WialonUnitGroup(WialonBase):
41
44
  :rtype: :py:obj:`None`
42
45
 
43
46
  """
44
-
45
47
  self.session.wialon_api.unit_group_update_units(
46
48
  **{"itemId": self.id, "units": new_items}
47
49
  )
@@ -115,39 +117,3 @@ class WialonUnitGroup(WialonBase):
115
117
  }
116
118
  )
117
119
  return [unit_id for unit_id in response.get("items")[0].get("u", [])]
118
-
119
-
120
- def main() -> None:
121
- import logging
122
-
123
- from django.conf import settings
124
- from django.utils import timezone
125
-
126
- from terminusgps.wialon.items import WialonUnit
127
- from terminusgps.wialon.session import WialonSession
128
- from terminusgps.wialon.utils import get_hw_type_id
129
-
130
- timestamp = f"{timezone.now():%Y_%m_%d_%H:%M:%S}"
131
- with WialonSession(log_level=logging.DEBUG) as session:
132
- unit = WialonUnit(
133
- id=None,
134
- session=session,
135
- creator_id=settings.WIALON_ADMIN_ID,
136
- name=f"test_unit_{timestamp}",
137
- hw_type_id=get_hw_type_id("Test HW", session=session),
138
- )
139
- group = WialonUnitGroup(
140
- id=None,
141
- session=session,
142
- creator_id=settings.WIALON_ADMIN_ID,
143
- name=f"test_group_{timestamp}",
144
- )
145
- group.add_item(unit)
146
- print(f"{group.items = }")
147
- unit.delete()
148
- group.delete()
149
- return
150
-
151
-
152
- if __name__ == "__main__":
153
- main()
@@ -32,7 +32,11 @@ class WialonUser(WialonBase):
32
32
  "dataFlags": flags.DATAFLAG_UNIT_BASE,
33
33
  }
34
34
  )
35
- return int(response.get("item", {}).get("id")) if response.get("item") else None
35
+ return (
36
+ int(response.get("item", {}).get("id"))
37
+ if response and response.get("item")
38
+ else None
39
+ )
36
40
 
37
41
  def _get_access_response(self, hw_type: str) -> dict:
38
42
  """
@@ -3,10 +3,9 @@ import datetime
3
3
  import logging
4
4
  import typing
5
5
 
6
+ import wialon.api
6
7
  from django.conf import settings
7
8
  from django.utils import timezone
8
- from wialon.api import Wialon as WialonBase
9
- from wialon.api import WialonError
10
9
 
11
10
  from terminusgps.wialon.logger import WialonLogger
12
11
 
@@ -21,7 +20,7 @@ class WialonAPICall:
21
20
  error: Exception | None = None
22
21
 
23
22
 
24
- class Wialon(WialonBase):
23
+ class Wialon(wialon.api.Wialon):
25
24
  def __init__(self, log_level: int = logging.INFO, *args, **kwargs) -> None:
26
25
  super().__init__(*args, **kwargs)
27
26
  self.call_history: list[WialonAPICall] = []
@@ -48,7 +47,7 @@ class Wialon(WialonBase):
48
47
  call_record.result = result
49
48
  self.logger.debug(f"Executed '{action_name}' successfully.")
50
49
  return result
51
- except WialonError as e:
50
+ except wialon.api.WialonError as e:
52
51
  call_record.error = e
53
52
  self.logger.warning(f"Failed to execute '{action_name}': '{e}'")
54
53
  return
@@ -275,7 +274,7 @@ class WialonSession:
275
274
  self._set_login_response(response)
276
275
  self.logger.debug(f"Logged into Wialon API session '{response.get('eid')}'")
277
276
  return response.get("eid")
278
- except (WialonError, AssertionError) as e:
277
+ except (wialon.api.WialonError, AssertionError) as e:
279
278
  self.logger.critical(f"Failed to login to Wialon API: '{e}'")
280
279
  raise
281
280
 
@@ -49,7 +49,7 @@ def get_id_from_imei(imei: str, session: WialonSession) -> str | None:
49
49
  if not imei.isdigit():
50
50
  raise ValueError(f"'imei' must be a digit, got '{imei}'.")
51
51
 
52
- results = session.wialon_api.core_search_items(
52
+ results: dict[str, typing.Any] | None = session.wialon_api.core_search_items(
53
53
  **{
54
54
  "spec": {
55
55
  "itemsType": "avl_unit",
@@ -66,7 +66,7 @@ def get_id_from_imei(imei: str, session: WialonSession) -> str | None:
66
66
  }
67
67
  )
68
68
 
69
- if results.get("totalItemsCount", 0) == 1:
69
+ if results and results.get("totalItemsCount", 0) == 1:
70
70
  return results["items"][0].get("id")
71
71
 
72
72
 
@@ -88,27 +88,25 @@ def get_id_from_iccid(iccid: str, session: WialonSession) -> str | None:
88
88
  return get_id_from_imei(imei=iccid, session=session)
89
89
 
90
90
 
91
- def get_wialon_cls(items_type: str) -> typing.Type[WialonBase]:
91
+ def get_wialon_cls(items_type: str) -> typing.Type[WialonBase] | None:
92
92
  """
93
- Returns a Wialon object class based on items_type.
93
+ Returns a Wialon object class based on ``items_type``.
94
+
95
+ Valid ``items_type`` are ``"user"``, ``"avl_unit"``, ``"avl_unit_group"`` and ``"avl_resource"``.
94
96
 
95
97
  :param items_type: A Wialon object type.
96
98
  :type items_type: :py:obj:`str`
97
99
  :returns: A subclass of :py:obj:`~terminusgps.wialon.items.base.WialonBase`.
98
- :rtype: :py:obj:`~terminusgps.wialon.items.base.WialonBase`
100
+ :rtype: :py:obj:`~terminusgps.wialon.items.base.WialonBase` | :py:obj:`None`
99
101
 
100
102
  """
101
- match items_type:
102
- case "user":
103
- return items.WialonUser
104
- case "avl_unit":
105
- return items.WialonUnit
106
- case "avl_unit_group":
107
- return items.WialonUnitGroup
108
- case "avl_resource":
109
- return items.WialonResource
110
- case _:
111
- raise ValueError(f"Invalid items_type, got '{items_type}'.")
103
+ items_map: dict[str, typing.Type[WialonBase]] = {
104
+ "user": items.WialonUser,
105
+ "avl_unit": items.WialonUnit,
106
+ "avl_unit_group": items.WialonUnitGroup,
107
+ "avl_resource": items.WialonResource,
108
+ }
109
+ return items_map.get(items_type)
112
110
 
113
111
 
114
112
  def get_vin_info(vin_number: str, session: WialonSession) -> dict:
@@ -123,15 +121,18 @@ def get_vin_info(vin_number: str, session: WialonSession) -> dict:
123
121
  :rtype: :py:obj:`dict`
124
122
 
125
123
  """
126
- response = session.wialon_api.unit_get_vin_info(**{"vin": vin_number}).get(
127
- "vin_lookup_result"
128
- )
129
- return (
130
- {field.get("n"): field.get("v") for field in response.get("pflds")}
131
- if "error" not in response.keys()
132
- else {}
124
+ response: dict[str, typing.Any] | None = session.wialon_api.unit_get_vin_info(
125
+ **{"vin": vin_number}
133
126
  )
134
127
 
128
+ if response is None or "error" in response.get("vin_lookup_result", {}).keys():
129
+ return {}
130
+
131
+ return {
132
+ field.get("n"): field.get("v")
133
+ for field in response.get("vin_lookup_result", {}).get("pflds")
134
+ }
135
+
135
136
 
136
137
  def is_unique(value: str, session: WialonSession, items_type: str = "avl_unit") -> bool:
137
138
  """
@@ -148,12 +149,14 @@ def is_unique(value: str, session: WialonSession, items_type: str = "avl_unit")
148
149
  :rtype: :py:obj:`bool`
149
150
 
150
151
  """
151
- return not bool(
152
- session.wialon_api.core_check_unique(
153
- **{"type": items_type, "value": value.strip()}
154
- ).get("result")
152
+ response = session.wialon_api.core_check_unique(
153
+ **{"type": items_type, "value": value.strip()}
155
154
  )
156
155
 
156
+ if not response:
157
+ return False
158
+ return bool(response.get("result"))
159
+
157
160
 
158
161
  def generate_wialon_password(length: int = 32) -> str:
159
162
  """
terminusgps/aws/ses.py DELETED
@@ -1,72 +0,0 @@
1
- import boto3
2
- import json
3
-
4
-
5
- class SESEmailTemplate:
6
- def __init__(self, template_name: str, region_name: str = "us-east-1") -> None:
7
- self.name = template_name
8
- self.region = region_name
9
- self.client = boto3.Session().client(service_name="ses")
10
-
11
- def send(
12
- self,
13
- from_addr: str,
14
- recipients: list[str],
15
- replyto_list: list[str],
16
- data: dict[str, str],
17
- cc_list: list[str] | None = None,
18
- bcc_list: list[str] | None = None,
19
- ) -> None:
20
- destination = self._get_destination(recipients, cc_list, bcc_list)
21
- self.client.send_templated_email(
22
- **{
23
- "Source": from_addr,
24
- "Destination": destination,
25
- "ReplyToAddresses": replyto_list,
26
- "Template": self.name,
27
- "TemplateData": json.dumps(data),
28
- }
29
- )
30
-
31
- def create(self, subject: str, text_content: str, html_content: str) -> None:
32
- self.client.create_template(
33
- **{
34
- "Template": {
35
- "TemplateName": self.name,
36
- "SubjectPart": subject,
37
- "TextPart": text_content,
38
- "HtmlPart": html_content,
39
- }
40
- }
41
- )
42
-
43
- def update(self, subject: str, text_content: str, html_content: str) -> None:
44
- self.client.update_template(
45
- **{
46
- "Template": {
47
- "TemplateName": self.name,
48
- "SubjectPart": subject,
49
- "TextPart": text_content,
50
- "HtmlPart": html_content,
51
- }
52
- }
53
- )
54
-
55
- def test_render(self, data: dict[str, str]) -> str:
56
- response = self.client.test_render_template(
57
- **{"TemplateName": self.name, "TemplateData": json.dumps(data)}
58
- )
59
- return response.get("RenderedTemplate")
60
-
61
- def _get_destination(
62
- self,
63
- recipients: list[str],
64
- cc_list: list[str] | None,
65
- bcc_list: list[str] | None,
66
- ) -> dict[str, list[str]]:
67
- destination: dict[str, list[str]] = {"ToAddresses": recipients}
68
- if cc_list is not None:
69
- destination.update({"CcAddresses": cc_list})
70
- if bcc_list is not None:
71
- destination.update({"BccAddresses": bcc_list})
72
- return destination