python-terminusgps 31.7.0__py3-none-any.whl → 31.7.2__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: 31.7.0
3
+ Version: 31.7.2
4
4
  Summary: Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more.
5
5
  Project-URL: Documentation, https://docs.terminusgps.com
6
6
  Project-URL: Repository, https://github.com/terminusgps/python-terminusgps
@@ -16,8 +16,8 @@ Requires-Dist: argparse>=1.4.0
16
16
  Requires-Dist: authorizenet>=1.1.5
17
17
  Requires-Dist: boto3>=1.34.144
18
18
  Requires-Dist: django>=5.1.5
19
+ Requires-Dist: loguru>=0.7.3
19
20
  Requires-Dist: matplotlib>=3.10.1
20
- Requires-Dist: opencv-contrib-python-headless>=4.11.0.86
21
21
  Requires-Dist: pandas>=2.2.3
22
22
  Requires-Dist: python-wialon>=1.2.4
23
23
  Requires-Dist: pyzbar>=0.1.9
@@ -28,10 +28,9 @@ terminusgps/twilio/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
28
28
  terminusgps/twilio/tests/test_caller.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  terminusgps/twilio/tests/test_validators.py,sha256=CETv7Mcr19UMMfh1UaWSV26FiOeh2WCK_VutfKXnf7g,1428
30
30
  terminusgps/wialon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- terminusgps/wialon/constants.py,sha256=pMWqXkZK7bbA_KOdBdJ8hs9MnUUEk-MMygJ3fLNA4pQ,5783
31
+ terminusgps/wialon/constants.py,sha256=Ju2XL2A4DPFD-w8NjYqEfnnqregl1luPT0XGhGSUnO8,6316
32
32
  terminusgps/wialon/flags.py,sha256=M50EdhxQ8IMnJnU0mrHK7-h8Asc6tvNiTOOfd1dBW6A,12815
33
- terminusgps/wialon/logger.py,sha256=nUBsaLMaffSaAHGHAM6mFXDzix9hbNecVtA3INVtii8,968
34
- terminusgps/wialon/session.py,sha256=SGiHH58h8d3n4dQqKrLjWKlZvNHjBqpWqK6GKofMCBo,10079
33
+ terminusgps/wialon/session.py,sha256=09WYWvON_H844IFfdt7_x1we6tHhQSkt9K_BEedBjv0,10396
35
34
  terminusgps/wialon/utils.py,sha256=JWHZ7VEeo8VNBH67gjOAQk5ITKuPllWDlJ4dVSQ5blA,11002
36
35
  terminusgps/wialon/validators.py,sha256=CVEpFsxqplEcpv4U2ipA6v9y5cSrMKFUXLvze-3vs4U,4223
37
36
  terminusgps/wialon/items/__init__.py,sha256=3BVthghekMvhMQSzQgBMlD_phxmKSmp3Zvmo-z0O8Bs,211
@@ -44,9 +43,9 @@ terminusgps/wialon/items/unit_group.py,sha256=QV2ZZgICaN3n6W1pFIyMLyNKB6KYBsLyKG
44
43
  terminusgps/wialon/items/user.py,sha256=5LgwalGO8KS_7psmAVmAlnC0S6SPBDZMOuT5ZqPKRmo,7758
45
44
  terminusgps/wialon/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
45
  terminusgps/wialon/tests/test_items.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
- terminusgps/wialon/tests/test_session.py,sha256=k5iEwd77nCebxWyFzkDCm9G0c04iztXY6UgOaxhub48,1314
48
- terminusgps/wialon/tests/test_utils.py,sha256=vYnOKCPPYqUWcQ2nTJTOu7NhNKMiTGNBkvX9H2APxL0,1670
49
- python_terminusgps-31.7.0.dist-info/METADATA,sha256=eNDi6Z4AU2kb9zY1iDzX04JwFJ-5HJRfVLEasUF9-20,1609
50
- python_terminusgps-31.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
51
- python_terminusgps-31.7.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
52
- python_terminusgps-31.7.0.dist-info/RECORD,,
46
+ terminusgps/wialon/tests/test_session.py,sha256=9mBlYchMo9NeqRIZsmxYzrM1zBHorqu4ooxqSNppLpI,1336
47
+ terminusgps/wialon/tests/test_utils.py,sha256=SK4PxJQGECFnzx_EQeRAQfsQ5_3FLaVcis2W9u_ibuI,1730
48
+ python_terminusgps-31.7.2.dist-info/METADATA,sha256=t9yLXs5VwoG9MV9BpmEvx5HCt-MpX2cjXumX4lT0M10,1581
49
+ python_terminusgps-31.7.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
50
+ python_terminusgps-31.7.2.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
+ python_terminusgps-31.7.2.dist-info/RECORD,,
@@ -5,15 +5,35 @@ from . import flags
5
5
 
6
6
 
7
7
  class WialonGeofenceType(enum.IntEnum):
8
+ """
9
+ A type of Wialon geofence.
10
+
11
+ `Wialon geofence type reference <https://sdk.wialon.com/wiki/en/kit/remoteapi/apiref/resource/update_zone>`_
12
+
13
+ """
14
+
8
15
  LINE = 1
16
+ """Line geofence."""
9
17
  POLYGON = 2
18
+ """Polygon geofence."""
10
19
  CIRCLE = 3
20
+ """Circular geofence."""
11
21
 
12
22
 
13
23
  class WialonMeasurementUnit(enum.IntEnum):
24
+ """
25
+ A Wialon measurement unit.
26
+
27
+ `Wialon measurement unit reference <https://sdk.wialon.com/wiki/en/local/remoteapi1904/apiref/item/update_measure_units>`_
28
+
29
+ """
30
+
14
31
  METRIC = 0
32
+ """Metric system."""
15
33
  US = 1
34
+ """US measurement system."""
16
35
  IMPERIAL = 2
36
+ """Imperial measurement system."""
17
37
 
18
38
 
19
39
  class WialonItemsType(enum.StrEnum):
@@ -25,19 +45,19 @@ class WialonItemsType(enum.StrEnum):
25
45
  """
26
46
 
27
47
  HARDWARE = "avl_hw"
28
- """Hardware type."""
48
+ """A hardware type."""
29
49
  RESOURCE = "avl_resource"
30
- """Resource."""
50
+ """A resource."""
31
51
  RETRANSLATOR = "avl_retranslator"
32
- """Retranslator."""
52
+ """A retranslator."""
33
53
  ROUTE = "avl_route"
34
- """Route."""
54
+ """A route."""
35
55
  UNIT = "avl_unit"
36
- """Unit."""
56
+ """A unit."""
37
57
  UNIT_GROUP = "avl_unit_group"
38
- """Unit group."""
58
+ """A unit group."""
39
59
  USER = "user"
40
- """User."""
60
+ """A user."""
41
61
 
42
62
 
43
63
  class WialonItemProperty(enum.StrEnum):
@@ -1,13 +1,11 @@
1
1
  import dataclasses
2
2
  import datetime
3
- import logging
4
3
  import typing
5
4
 
6
5
  import wialon.api
7
6
  from django.conf import settings
8
7
  from django.utils import timezone
9
-
10
- from terminusgps.wialon.logger import WialonLogger
8
+ from loguru import logger
11
9
 
12
10
 
13
11
  @dataclasses.dataclass
@@ -21,12 +19,17 @@ class WialonAPICall:
21
19
 
22
20
 
23
21
  class Wialon(wialon.api.Wialon):
24
- def __init__(self, log_level: int = logging.INFO, *args, **kwargs) -> None:
22
+ def __init__(
23
+ self, log_level: int = 10, log_days: int = 10, *args, **kwargs
24
+ ) -> None:
25
25
  super().__init__(*args, **kwargs)
26
26
  self.call_history: list[WialonAPICall] = []
27
- self.logger = WialonLogger(
28
- logging.getLogger(self.__class__.__name__), level=log_level
29
- ).get_logger()
27
+ logger.add(
28
+ f"logs/{self.__class__.__name__}.log",
29
+ level=log_level,
30
+ retention=f"{log_days} days",
31
+ diagnose=settings.DEBUG,
32
+ )
30
33
 
31
34
  @property
32
35
  def total_calls(self) -> int:
@@ -37,7 +40,7 @@ class Wialon(wialon.api.Wialon):
37
40
  return self.call("token_login", *args, **kwargs)
38
41
 
39
42
  def call(self, action_name: str, *argc, **kwargs) -> typing.Any:
40
- self.logger.debug(f"Executing '{action_name}'...")
43
+ logger.debug(f"Executing '{action_name}'...")
41
44
  call_record = WialonAPICall(
42
45
  action=action_name, timestamp=timezone.now(), args=argc, kwargs=kwargs
43
46
  )
@@ -45,11 +48,11 @@ class Wialon(wialon.api.Wialon):
45
48
  try:
46
49
  result = super().call(action_name, *argc, **kwargs)
47
50
  call_record.result = result
48
- self.logger.debug(f"Executed '{action_name}' successfully.")
51
+ logger.debug(f"Executed '{action_name}' successfully.")
49
52
  return result
50
53
  except wialon.api.WialonError as e:
51
54
  call_record.error = e
52
- self.logger.warning(f"Failed to execute '{action_name}': '{e}'")
55
+ logger.warning(f"Failed to execute '{action_name}': '{e}'")
53
56
  return
54
57
  finally:
55
58
  self.call_history.append(call_record)
@@ -63,7 +66,8 @@ class WialonSession:
63
66
  scheme: str = "https",
64
67
  host: str = "hst-api.wialon.com",
65
68
  port: int = 443,
66
- log_level: int = logging.INFO,
69
+ log_level: int = 10,
70
+ log_days: int = 10,
67
71
  ) -> None:
68
72
  """
69
73
  Starts or continues a Wialon API session.
@@ -78,13 +82,19 @@ class WialonSession:
78
82
  :type host: :py:obj:`str`
79
83
  :param port: Wialon API host port. Default is ``443``.
80
84
  :type port: :py:obj:`int`
81
- :param log_level: Logging severity level. Default is ``20`` (logging.INFO).
85
+ :param log_level: Level of emitted logs. Default is ``10``.
82
86
  :type log_level: :py:obj:`int`
83
87
  :returns: Nothing.
84
88
  :rtype: :py:obj:`None`
85
89
 
86
90
  """
87
91
 
92
+ logger.add(
93
+ f"logs/{self.__class__.__name__}.log",
94
+ level=log_level,
95
+ retention=f"{log_days} days",
96
+ diagnose=settings.DEBUG,
97
+ )
88
98
  self._token = token or settings.WIALON_TOKEN
89
99
  self._username = None
90
100
  self._gis_sid = None
@@ -92,11 +102,13 @@ class WialonSession:
92
102
  self._wsdk_version = None
93
103
  self._uid = None
94
104
  self.wialon_api = Wialon(
95
- scheme=scheme, host=host, port=port, sid=sid, log_level=log_level
105
+ scheme=scheme,
106
+ host=host,
107
+ port=port,
108
+ sid=sid,
109
+ log_level=log_level,
110
+ log_days=log_days,
96
111
  )
97
- self.logger = WialonLogger(
98
- logging.getLogger(self.__class__.__name__), level=log_level
99
- ).get_logger()
100
112
 
101
113
  def __str__(self) -> str:
102
114
  return str(self.id)
@@ -127,6 +139,17 @@ class WialonSession:
127
139
  """
128
140
  self.logout()
129
141
 
142
+ @property
143
+ def active(self) -> bool:
144
+ """
145
+ Whether or not the session is logged in.
146
+
147
+ :type: :py:obj:`bool`
148
+ :value: :py:obj:`False`
149
+
150
+ """
151
+ return bool(self.id)
152
+
130
153
  @property
131
154
  def gis_geocode(self) -> str | None:
132
155
  """
@@ -288,13 +311,13 @@ class WialonSession:
288
311
 
289
312
  """
290
313
  try:
291
- self.logger.debug("Logging into Wialon API session...")
314
+ logger.debug("Logging into Wialon API session...")
292
315
  response = self.wialon_api.token_login(**{"token": token, "fl": flags})
293
316
  self._set_login_response(response)
294
- self.logger.debug(f"Logged into Wialon API session '{response.get('eid')}'")
317
+ logger.debug(f"Logged into Wialon API session '{response.get('eid')}'")
295
318
  return response.get("eid")
296
319
  except (wialon.api.WialonError, AssertionError) as e:
297
- self.logger.critical(f"Failed to login to Wialon API: '{e}'")
320
+ logger.critical(f"Failed to login to Wialon API: '{e}'")
298
321
  raise
299
322
 
300
323
  def logout(self) -> None:
@@ -305,16 +328,14 @@ class WialonSession:
305
328
  :rtype: :py:obj:`None`
306
329
 
307
330
  """
308
- self.logger.debug("Logging out of Wialon API session...")
331
+ logger.debug("Logging out of Wialon API session...")
309
332
  response: dict = self.wialon_api.core_logout({})
310
333
  self.wialon_api.sid = None
311
334
 
312
335
  if response.get("error") != 0:
313
- self.logger.warning(
314
- f"Failed to logout of session: '{response.get('message')}'"
315
- )
336
+ logger.warning(f"Failed to logout of session: '{response.get('message')}'")
316
337
  else:
317
- self.logger.debug(
338
+ logger.debug(
318
339
  f"Logged out after {self.wialon_api.total_calls} Wialon API calls."
319
340
  )
320
341
 
@@ -1,18 +1,22 @@
1
+ import os
1
2
  import unittest
2
3
 
3
4
  from django.conf import settings
4
5
 
5
- from ..session import WialonSession
6
+ from terminusgps.wialon.session import WialonSession
7
+
8
+ TEST_WIALON_TOKEN = os.getenv("WIALON_TOKEN") or settings.WIALON_TOKEN
6
9
 
7
10
 
8
11
  class WialonSessionTestCase(unittest.TestCase):
9
12
  def setUp(self) -> None:
10
- if not hasattr(settings, "WIALON_TOKEN"):
11
- self.fail("'WIALON_TOKEN' setting is required.")
12
-
13
- self.token = settings.WIALON_TOKEN
13
+ self.token = TEST_WIALON_TOKEN
14
14
  self.session = WialonSession()
15
15
 
16
+ def tearDown(self) -> None:
17
+ if self.session.active:
18
+ self.session.logout()
19
+
16
20
  def test_session_init(self) -> None:
17
21
  self.assertIsNone(self.session.id)
18
22
  self.assertIsNone(self.session.username)
@@ -31,10 +35,8 @@ class WialonSessionTestCase(unittest.TestCase):
31
35
  self.session.login(self.token)
32
36
  response = self.session.wialon_api.core_bad_call({})
33
37
  self.assertIsNone(response)
34
- self.session.logout()
35
38
 
36
39
  def test_session_valid_call_count(self) -> None:
37
40
  self.session.login(self.token) # Login/logout does not count
38
41
  self.session.wialon_api.avl_evts()
39
42
  self.assertEqual(self.session.wialon_api.total_calls, 1)
40
- self.session.logout()
@@ -1,8 +1,7 @@
1
1
  import string
2
2
  import unittest
3
3
 
4
-
5
- from .. import utils
4
+ from terminusgps.wialon import utils
6
5
 
7
6
 
8
7
  class WialonUtilsTestCase(unittest.TestCase):
@@ -35,6 +34,7 @@ class WialonUtilsTestCase(unittest.TestCase):
35
34
  self.fail("Generated password did not contain an uppercase letter.")
36
35
  if not any([c for c in password if c in s1]):
37
36
  self.fail("Generated password did not contain a lowercase letter.")
37
+ # TODO: Make this check for 3 digits
38
38
  if not any([c for c in password if c in s2]):
39
39
  self.fail("Generated password did not contain a digit.")
40
40
  if not any([c for c in password if c in s3]):
@@ -1,29 +0,0 @@
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