python-terminusgps 19.3.0__py3-none-any.whl → 20.1.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-terminusgps
3
- Version: 19.3.0
3
+ Version: 20.1.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
@@ -15,9 +15,9 @@ terminusgps/twilio/__init__.py,sha256=dYo41F2jft_eHDWSUtSpKGSRG1bewq_qClqilUJZkY
15
15
  terminusgps/twilio/caller.py,sha256=nHCIwUulo-C_v2orsp6OY0nuJA6YetSkxpMTwrRQ-uA,1831
16
16
  terminusgps/wialon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  terminusgps/wialon/constants.py,sha256=u7y9MsA5LYvjPjxJnCMQdprTF3QhPPR9j4MvzoSNBaw,1628
18
- terminusgps/wialon/errors.py,sha256=Fl8A0peF5HpDdR3y0r3g86-iQ4kQgye3FYQZKGe3T7Y,984
19
18
  terminusgps/wialon/flags.py,sha256=-OoH-eZM54yjRqxsAXL8VImdQu_7C0OAxCrFqaCEuko,13510
20
- terminusgps/wialon/session.py,sha256=IPt9Q4CmzQ5AU27z6LoUaPO1PkAX_H0nIwCSCAOHNdY,11243
19
+ terminusgps/wialon/logger.py,sha256=nUBsaLMaffSaAHGHAM6mFXDzix9hbNecVtA3INVtii8,968
20
+ terminusgps/wialon/session.py,sha256=47Cq3cM4sF-lySPtafzizKHeHbfuDuK1CnR0Jrmwk-Q,10634
21
21
  terminusgps/wialon/utils.py,sha256=KeZmV-MEdGOHXrsyn6IIoyX0EgVYiWYjvacXyZVr1u8,6501
22
22
  terminusgps/wialon/items/__init__.py,sha256=cfUC5sfVsTwmpgsR-w9wA4ay6_EZYAPgEeuw2k06RJM,256
23
23
  terminusgps/wialon/items/base.py,sha256=EAtzlnCvB7WTu3iX1bV1-S9TvwXc-Eez7e0X4TMiK9U,6943
@@ -27,9 +27,9 @@ terminusgps/wialon/items/resource.py,sha256=79SwbCyE1zlaoeBfU0erEqvqBAYUC4KAKs8A
27
27
  terminusgps/wialon/items/retranslator.py,sha256=8q9EDc92w92MElnHIeEzH3Ra4kiPXrx4t9V5nPDZuRU,3728
28
28
  terminusgps/wialon/items/route.py,sha256=PTJx1gmT_PGz7nlSSUS2VzjYD-aAuvkEOIdIFneUSSQ,1148
29
29
  terminusgps/wialon/items/unit.py,sha256=PwF7xlpDWI5MpM_u6TmYZjNHWk6TSKM4rJ4OB9CIn4A,7533
30
- terminusgps/wialon/items/unit_group.py,sha256=xc7zYitPE59_WYS-G857jeIQnQcUAxLBH3X6Y1VDg_8,4089
30
+ terminusgps/wialon/items/unit_group.py,sha256=LdDCAz3lrr7ROAVKqx2joNitIi22Pw3mS7khAbtcGlc,5036
31
31
  terminusgps/wialon/items/user.py,sha256=INwAibQVmjNNelepQXMfDevgJqMvIjHHgEjAMLRvhB0,7082
32
- python_terminusgps-19.3.0.dist-info/METADATA,sha256=I61CjEuSHa8Y8yr2VurF9-i_8CnokrnGiHlCKn641MY,912
33
- python_terminusgps-19.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
- python_terminusgps-19.3.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
35
- python_terminusgps-19.3.0.dist-info/RECORD,,
32
+ python_terminusgps-20.1.0.dist-info/METADATA,sha256=eOfT7nITGn2pLypPyBtiIImAN0npLFSP3_R-s60986Q,912
33
+ python_terminusgps-20.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
+ python_terminusgps-20.1.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
35
+ python_terminusgps-20.1.0.dist-info/RECORD,,
@@ -1,4 +1,3 @@
1
- from typing import Type
2
1
  from terminusgps.wialon import flags
3
2
  from terminusgps.wialon.items.base import WialonBase
4
3
 
@@ -47,7 +46,7 @@ class WialonUnitGroup(WialonBase):
47
46
  **{"itemId": self.id, "units": new_items}
48
47
  )
49
48
 
50
- def is_member(self, item: Type[WialonBase]) -> bool:
49
+ def is_member(self, item: WialonBase) -> bool:
51
50
  """
52
51
  Determines whether or not ``item`` is a member of the group.
53
52
 
@@ -60,7 +59,7 @@ class WialonUnitGroup(WialonBase):
60
59
  """
61
60
  return True if str(item.id) in self.items else False
62
61
 
63
- def add_item(self, item: Type[WialonBase]) -> None:
62
+ def add_item(self, item: WialonBase) -> None:
64
63
  """
65
64
  Adds a Wialon item to the group.
66
65
 
@@ -74,7 +73,7 @@ class WialonUnitGroup(WialonBase):
74
73
  new_items: list[str] = self.items.copy() + [str(item.id)]
75
74
  self.set_items(new_items)
76
75
 
77
- def rm_item(self, item: Type[WialonBase]) -> None:
76
+ def rm_item(self, item: WialonBase) -> None:
78
77
  """
79
78
  Removes a Wialon unit from the group, if it's a member of the group.
80
79
 
@@ -116,3 +115,38 @@ class WialonUnitGroup(WialonBase):
116
115
  }
117
116
  )
118
117
  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.utils import timezone
124
+ from django.conf import settings
125
+ from terminusgps.wialon.session import WialonSession
126
+ from terminusgps.wialon.items import WialonUnit
127
+ from terminusgps.wialon.utils import get_hw_type_id
128
+
129
+ timestamp = f"{timezone.now():%Y_%m_%d_%H:%M:%S}"
130
+ with WialonSession(log_level=logging.DEBUG) as session:
131
+ unit = WialonUnit(
132
+ id=None,
133
+ session=session,
134
+ creator_id=settings.WIALON_ADMIN_ID,
135
+ name=f"test_unit_{timestamp}",
136
+ hw_type_id=get_hw_type_id("Test HW", session=session),
137
+ )
138
+ group = WialonUnitGroup(
139
+ id=None,
140
+ session=session,
141
+ creator_id=settings.WIALON_ADMIN_ID,
142
+ name=f"test_group_{timestamp}",
143
+ )
144
+ group.add_item(unit)
145
+ print(f"{group.items = }")
146
+ unit.delete()
147
+ group.delete()
148
+ return
149
+
150
+
151
+ if __name__ == "__main__":
152
+ main()
@@ -0,0 +1,29 @@
1
+ import logging
2
+
3
+
4
+ class WialonLogger:
5
+ def __init__(
6
+ self,
7
+ logger: logging.Logger,
8
+ level: int = logging.DEBUG,
9
+ format: str = "%(name)s - %(levelname)s - %(asctime)s - %(message)s",
10
+ use_stream_handler: bool = True,
11
+ use_file_handler: bool = False,
12
+ filename: str = "wialon_debug.log",
13
+ ) -> None:
14
+ self.logger = logger
15
+ self.logger.setLevel(level)
16
+ formatter = logging.Formatter(format)
17
+
18
+ if use_stream_handler and not self.logger.handlers:
19
+ stream_handler = logging.StreamHandler()
20
+ stream_handler.setFormatter(formatter)
21
+ self.logger.addHandler(stream_handler)
22
+
23
+ if use_file_handler and not self.logger.handlers:
24
+ file_handler = logging.FileHandler(filename)
25
+ file_handler.setFormatter(formatter)
26
+ self.logger.addHandler(file_handler)
27
+
28
+ def get_logger(self) -> logging.Logger:
29
+ return self.logger
@@ -1,15 +1,15 @@
1
- import threading
2
- import logging
3
- import typing
4
1
  import dataclasses
5
2
  import datetime
3
+ import logging
4
+ import threading
5
+ import typing
6
6
 
7
- from wialon.api import WialonError
8
- from wialon.api import Wialon as WialonAPI
9
7
  from django.conf import settings
10
8
  from django.utils import timezone
9
+ from wialon.api import Wialon as WialonBase
10
+ from wialon.api import WialonError
11
11
 
12
- from terminusgps.wialon.errors import WialonLogoutError, WialonLoginError
12
+ from terminusgps.wialon.logger import WialonLogger
13
13
 
14
14
 
15
15
  @dataclasses.dataclass
@@ -22,27 +22,21 @@ class WialonAPICall:
22
22
  error: Exception | None = None
23
23
 
24
24
 
25
- class Wialon(WialonAPI):
25
+ class Wialon(WialonBase):
26
26
  def __init__(self, log_level: int = logging.INFO, *args, **kwargs) -> None:
27
27
  super().__init__(*args, **kwargs)
28
28
  self.call_history: list[WialonAPICall] = []
29
- self.logger = self.create_logger(log_level)
29
+ self.logger = WialonLogger(
30
+ logging.getLogger(self.__class__.__name__), level=log_level
31
+ ).get_logger()
30
32
 
31
33
  @property
32
34
  def total_calls(self) -> int:
33
35
  return len(self.call_history)
34
36
 
35
- @property
36
- def successful_calls(self) -> list[WialonAPICall | None]:
37
- return [call for call in self.call_history if not call.error]
38
-
39
- @property
40
- def failed_calls(self) -> list[WialonAPICall | None]:
41
- return [call for call in self.call_history if call.error]
42
-
43
- @property
44
- def failure_rate(self) -> float:
45
- return len(self.failed_calls) / self.total_calls
37
+ def token_login(self, *args, **kwargs) -> typing.Any:
38
+ kwargs["appName"] = "python-terminusgps"
39
+ return self.call("token_login", *args, **kwargs)
46
40
 
47
41
  def call(self, action_name: str, *argc, **kwargs) -> typing.Any:
48
42
  self.logger.debug(f"Executing '{action_name}'...")
@@ -56,31 +50,18 @@ class Wialon(WialonAPI):
56
50
  self.logger.debug(f"Executed '{action_name}' successfully.")
57
51
  return result
58
52
  except WialonError as e:
59
- self.logger.warning(f"Failed to execute '{action_name}': '{e}'")
60
53
  call_record.error = e
61
- raise
54
+ self.logger.warning(f"Failed to execute '{action_name}': '{e}'")
55
+ return
62
56
  finally:
63
57
  self.call_history.append(call_record)
64
58
 
65
- def create_logger(self, log_level: int) -> logging.Logger:
66
- logger = logging.getLogger(self.__class__.__name__)
67
- handler = logging.StreamHandler()
68
- formatter = logging.Formatter(
69
- "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
70
- )
71
-
72
- logger.setLevel(log_level)
73
- handler.setFormatter(formatter)
74
- logger.addHandler(handler)
75
- return logger
76
-
77
59
 
78
60
  class WialonSession:
79
61
  def __init__(
80
62
  self,
81
63
  token: str | None = None,
82
64
  sid: str | None = None,
83
- uid: str | None = None,
84
65
  scheme: str = "https",
85
66
  host: str = "hst-api.wialon.com",
86
67
  port: int = 443,
@@ -93,35 +74,31 @@ class WialonSession:
93
74
  :type token: :py:obj:`str` | :py:obj:`None`
94
75
  :param sid: An optional Wialon API session id. If provided, the session is continued.
95
76
  :type sid: :py:obj:`str` | :py:obj:`None`
96
- :raises ImproperlyConfigured: If either :confval:`WIALON_TOKEN` or :confval:`WIALON_ADMIN_ID` is not set.
77
+ :param scheme: HTTP request scheme to use. Default is ``"https"``.
78
+ :type scheme: :py:obj:`str`
79
+ :param host: Wialon API host url. Default is ``"hst-api.wialon.com"``.
80
+ :type host: :py:obj:`str`
81
+ :param port: Wialon API host port. Default is ``443``.
82
+ :type port: :py:obj:`int`
83
+ :param log_level: Severity level at which log messages should be handled. Default is ``20`` (logging.INFO).
84
+ :type log_level: :py:obj:`int`
97
85
  :returns: Nothing.
98
86
  :rtype: :py:obj:`None`
99
87
 
100
88
  """
101
89
 
102
- self.wialon_api = Wialon(
103
- scheme=scheme, host=host, port=port, sid=sid, log_level=log_level
104
- )
105
90
  self._token = token or settings.WIALON_TOKEN
106
- self.login_id = uid
107
91
  self._username = None
108
92
  self._gis_sid = None
109
93
  self._hw_gp_ip = None
110
94
  self._wsdk_version = None
111
95
  self._uid = None
112
- self.logger = self.create_logger(log_level)
113
-
114
- def create_logger(self, log_level: int) -> logging.Logger:
115
- logger = logging.getLogger(self.__class__.__name__)
116
- handler = logging.StreamHandler()
117
- formatter = logging.Formatter(
118
- "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
96
+ self.wialon_api = Wialon(
97
+ scheme=scheme, host=host, port=port, sid=sid, log_level=log_level
119
98
  )
120
-
121
- logger.setLevel(log_level)
122
- handler.setFormatter(formatter)
123
- logger.addHandler(handler)
124
- return logger
99
+ self.logger = WialonLogger(
100
+ logging.getLogger(self.__class__.__name__), level=log_level
101
+ ).get_logger()
125
102
 
126
103
  def __enter__(self) -> "WialonSession":
127
104
  assert self.token, "Wialon API token was not set"
@@ -285,39 +262,41 @@ class WialonSession:
285
262
  :type token: :py:obj:`str`
286
263
  :param flags: A login response flag integer.
287
264
  :type flags: :py:obj:`int`
288
- :raises WialonLoginError: If the login fails.
265
+ :raises WialonError: If the login fails.
266
+ :raises AssertionError: If the login token was not set.
289
267
  :returns: The new session id.
290
268
  :rtype: :py:obj:`str`
291
269
 
292
270
  """
293
271
  try:
272
+ self.logger.info("Logging into Wialon API session...")
294
273
  response = self.wialon_api.token_login(**{"token": token, "fl": flags})
295
274
  self._set_login_response(response)
296
- self.logger.info(f"Logged into Wialon API session '{response.get('eid')}'")
275
+ self.logger.debug(f"Logged into Wialon API session '{response.get('eid')}'")
297
276
  return response.get("eid")
298
277
  except (WialonError, AssertionError) as e:
299
278
  self.logger.critical(f"Failed to login to Wialon API: '{e}'")
300
- raise WialonLoginError(token, e)
279
+ raise
301
280
 
302
281
  def logout(self) -> None:
303
282
  """
304
283
  Logs out of the Wialon API session.
305
284
 
306
- :raises WialonLogoutError: If the logout fails.
307
285
  :returns: Nothing.
308
286
  :rtype: :py:obj:`None`
309
287
 
310
288
  """
289
+ self.logger.info("Logging out of Wialon API session...")
311
290
  response: dict = self.wialon_api.core_logout({})
312
- self.logger.info(
313
- f"Logged out of session '{self.id}' after {self.wialon_api.total_calls} Wialon API calls."
314
- )
315
- self.logger.debug(f"Failure rate: {self.wialon_api.failure_rate}%")
291
+
316
292
  if response.get("error") != 0:
317
293
  self.logger.warning(
318
294
  f"Failed to logout of session: '{response.get('message')}'"
319
295
  )
320
- raise WialonLogoutError(str(self.id))
296
+ else:
297
+ self.logger.debug(
298
+ f"Logged out after {self.wialon_api.total_calls} Wialon API calls."
299
+ )
321
300
 
322
301
  def _set_login_response(self, login_response: dict) -> None:
323
302
  """
@@ -367,7 +346,7 @@ class WialonSessionManager:
367
346
 
368
347
  def main() -> None:
369
348
  # Usage example
370
- session = WialonSession() # Instantiate session
349
+ session = WialonSession(log_level=logging.DEBUG) # Instantiate session
371
350
  session.login(settings.WIALON_TOKEN) # Login to session
372
351
  session.wialon_api.avl_evts() # Call Wialon API
373
352
  session.logout() # Logout of session
@@ -1,29 +0,0 @@
1
- from wialon.api import WialonError
2
-
3
-
4
- class WialonBaseError(Exception):
5
- def __init__(
6
- self, message: str, wialon_err: WialonError | AssertionError | None = None
7
- ) -> None:
8
- self.wialon_err = wialon_err
9
- return super().__init__(message)
10
-
11
-
12
- class WialonLoginError(WialonBaseError):
13
- def __init__(
14
- self, token: str | None, wialon_err: WialonError | AssertionError | None = None
15
- ) -> None:
16
- message = f"Failed to login to the Wialon API using token: '{token}'\n"
17
- if wialon_err:
18
- message += str(wialon_err)
19
- return super().__init__(message, wialon_err)
20
-
21
-
22
- class WialonLogoutError(WialonBaseError):
23
- def __init__(
24
- self, session_id: str, wialon_err: WialonError | AssertionError | None = None
25
- ) -> None:
26
- message = f"Failed to logout of the Wialon API session: '{session_id}'\n"
27
- if wialon_err:
28
- message += str(wialon_err)
29
- return super().__init__(message, wialon_err)