splight-lib 5.11.5__tar.gz → 5.11.5.dev0__tar.gz

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.
Files changed (108) hide show
  1. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/PKG-INFO +1 -1
  2. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/pyproject.toml +1 -1
  3. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/auth/__init__.py +2 -0
  4. splight_lib-5.11.5.dev0/splight_lib/auth/exceptions.py +12 -0
  5. splight_lib-5.11.5.dev0/splight_lib/auth/mac_auth.py +96 -0
  6. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/database/abstract.py +4 -3
  7. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/database/builder.py +2 -2
  8. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/database/remote_client.py +23 -23
  9. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/datalake/buffer.py +4 -3
  10. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/datalake/builder.py +2 -2
  11. splight_lib-5.11.5.dev0/splight_lib/client/file_handler.py +34 -0
  12. splight_lib-5.11.5.dev0/splight_lib/client/filter.py +18 -0
  13. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/hub/abstract.py +4 -3
  14. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/hub/client.py +10 -10
  15. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/component/abstract.py +6 -6
  16. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/component/spec.py +28 -31
  17. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/constants.py +0 -1
  18. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/encryption.py +2 -1
  19. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/execution/engine.py +3 -2
  20. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/execution/scheduling.py +11 -10
  21. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/execution/task.py +6 -6
  22. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/execution/trigger.py +4 -3
  23. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/alert.py +33 -38
  24. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/asset.py +13 -16
  25. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/attribute.py +4 -3
  26. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/component.py +58 -58
  27. splight_lib-5.11.5.dev0/splight_lib/models/dashboard.py +307 -0
  28. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/data_address.py +4 -2
  29. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/datalake.py +5 -33
  30. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/file.py +9 -12
  31. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/function.py +17 -21
  32. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/hub.py +29 -39
  33. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/hub_server.py +1 -4
  34. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/hub_solution.py +7 -10
  35. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/metadata.py +5 -5
  36. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/secret.py +3 -3
  37. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/server.py +1 -1
  38. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/solution.py +3 -3
  39. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/tag.py +3 -1
  40. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/settings.py +5 -5
  41. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/stringcase.py +7 -8
  42. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/testing/__init__.py +4 -4
  43. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/utils/custom_model.py +7 -7
  44. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/utils/hub.py +3 -3
  45. splight_lib-5.11.5/splight_lib/models/dashboard.py +0 -126
  46. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/LICENSE.txt +0 -0
  47. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/README.md +0 -0
  48. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/__init__.py +0 -0
  49. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/abstract/__init__.py +0 -0
  50. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/abstract/client.py +0 -0
  51. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/auth/token.py +0 -0
  52. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/__init__.py +0 -0
  53. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/database/__init__.py +0 -0
  54. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/database/classmap.py +0 -0
  55. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/datalake/__init__.py +0 -0
  56. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/datalake/abstract.py +0 -0
  57. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/datalake/constants.py +0 -0
  58. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/datalake/exceptions.py +0 -0
  59. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/datalake/remote_client.py +0 -0
  60. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/exceptions.py +0 -0
  61. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/hub/__init__.py +0 -0
  62. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/tests/test_database.py +0 -0
  63. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/client/tests/test_datalake.py +0 -0
  64. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/component/__init__.py +0 -0
  65. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/component/exceptions.py +0 -0
  66. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/component/tests/test_abstract.py +0 -0
  67. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/component/tests/test_spec.py +0 -0
  68. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/conftest.py +0 -0
  69. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/execution/__init__.py +0 -0
  70. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/execution/exceptions.py +0 -0
  71. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/execution/tests/test_execution.py +0 -0
  72. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/execution/tests/test_scheduling.py +0 -0
  73. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/logging/__init__.py +0 -0
  74. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/logging/_internal.py +0 -0
  75. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/logging/component.py +0 -0
  76. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/logging/constants.py +0 -0
  77. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/logging/logging.py +0 -0
  78. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/logging/tests/test_logging.py +0 -0
  79. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/__init__.py +0 -0
  80. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/actions.py +0 -0
  81. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/database_base.py +0 -0
  82. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/datalake_base.py +0 -0
  83. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/exceptions.py +0 -0
  84. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/generic.py +0 -0
  85. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/native.py +0 -0
  86. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/tests/models.json +0 -0
  87. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/tests/test_component_object_instance.py +0 -0
  88. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/tests/test_database_model.py +0 -0
  89. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/tests/test_metadata.py +0 -0
  90. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/tests/test_models.py +0 -0
  91. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/models/variable_types.py +0 -0
  92. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/restclient/__init__.py +0 -0
  93. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/restclient/client.py +0 -0
  94. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/restclient/exceptions.py +0 -0
  95. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/restclient/tests/test_restclient.py +0 -0
  96. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/restclient/types.py +0 -0
  97. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/server/__init__.py +0 -0
  98. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/server/exceptions.py +0 -0
  99. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/server/server.py +0 -0
  100. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/solution/__init__.py +0 -0
  101. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/solution/exceptions.py +0 -0
  102. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/solution/solution.py +0 -0
  103. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/tests/FakeProc.py +0 -0
  104. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/tests/asset_geometries.json +0 -0
  105. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/tests/test_api_contracts.py +0 -0
  106. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/tests/test_encryption.py +0 -0
  107. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/utils/__init__.py +0 -0
  108. {splight_lib-5.11.5 → splight_lib-5.11.5.dev0}/splight_lib/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: splight-lib
3
- Version: 5.11.5
3
+ Version: 5.11.5.dev0
4
4
  Summary: Splight Library
5
5
  Author: Splight Dev
6
6
  Author-email: dev@splight-ae.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "splight-lib"
3
- version = "5.11.5"
3
+ version = "5.11.5.dev0"
4
4
  description = "Splight Library"
5
5
  authors = ["Splight Dev <dev@splight-ae.com>"]
6
6
  readme = "README.md"
@@ -1,5 +1,7 @@
1
+ from splight_lib.auth.mac_auth import HmacSignature
1
2
  from splight_lib.auth.token import SplightAuthToken
2
3
 
3
4
  __all__ = [
5
+ HmacSignature,
4
6
  SplightAuthToken,
5
7
  ]
@@ -0,0 +1,12 @@
1
+ class SignatureVerificationError(Exception):
2
+ def __init__(self, message, sig_header, http_body=None):
3
+ super(SignatureVerificationError, self).__init__(message)
4
+ self.sig_header = sig_header
5
+ self._message = message
6
+ self.http_body = http_body
7
+
8
+ def __repr__(self):
9
+ return f"{self.message} {self.http_body}"
10
+
11
+ def __str__(self):
12
+ return self._message
@@ -0,0 +1,96 @@
1
+ import hmac
2
+ import time
3
+ from hashlib import sha256
4
+
5
+ import six
6
+
7
+ from splight_lib.auth.exceptions import SignatureVerificationError
8
+
9
+
10
+ def utf8(value):
11
+ if six.PY2 and isinstance(value, six.text_type):
12
+ return value.encode("utf-8")
13
+ else:
14
+ return value
15
+
16
+
17
+ class HmacSignature(object):
18
+ EXPECTED_SCHEME = "v1"
19
+ DEFAULT_TOLERANCE = 300
20
+
21
+ def __init__(self, secret="", *args, **kwargs):
22
+ self.secret = secret
23
+ super().__init__(*args, **kwargs)
24
+
25
+ @staticmethod
26
+ def _compute_signature(payload, secret):
27
+ mac = hmac.new(
28
+ secret.encode("utf-8"),
29
+ msg=payload.encode("utf-8"),
30
+ digestmod=sha256,
31
+ )
32
+ return mac.hexdigest()
33
+
34
+ def compute_header_signature(self, payload: str):
35
+ """
36
+ Compute headers signature using hmac auth method.
37
+ """
38
+ timestamp = int(time.time())
39
+ signed_payload = "%d.%s" % (timestamp, payload.decode("ascii"))
40
+ mac_hexdigest = self._compute_signature(signed_payload, self.secret)
41
+ return f"t={timestamp},{self.EXPECTED_SCHEME}={mac_hexdigest}"
42
+
43
+ @staticmethod
44
+ def _get_timestamp_and_signatures(header, scheme):
45
+ list_items = [i.split("=", 2) for i in header.split(",")]
46
+ timestamp = int([i[1] for i in list_items if i[0] == "t"][0])
47
+ signatures = [i[1] for i in list_items if i[0] == scheme]
48
+ return timestamp, signatures
49
+
50
+ @classmethod
51
+ def verify_header(
52
+ cls, payload, header, secret, tolerance=DEFAULT_TOLERANCE
53
+ ):
54
+ if hasattr(payload, "decode"):
55
+ payload = payload.decode("utf-8")
56
+
57
+ try:
58
+ timestamp, signatures = cls._get_timestamp_and_signatures(
59
+ header, cls.EXPECTED_SCHEME
60
+ )
61
+ except Exception:
62
+ raise SignatureVerificationError(
63
+ "Unable to extract timestamp and signatures from header",
64
+ header,
65
+ payload,
66
+ )
67
+
68
+ if not signatures:
69
+ raise SignatureVerificationError(
70
+ "No signatures found with expected scheme "
71
+ "%s" % cls.EXPECTED_SCHEME,
72
+ header,
73
+ payload,
74
+ )
75
+
76
+ signed_payload = "%d.%s" % (timestamp, payload)
77
+ expected_sig = cls._compute_signature(signed_payload, secret)
78
+ if not any(
79
+ hmac.compare_digest(utf8(expected_sig), utf8(s))
80
+ for s in signatures
81
+ ):
82
+ raise SignatureVerificationError(
83
+ "No signatures found matching the expected signature for "
84
+ "payload",
85
+ header,
86
+ payload,
87
+ )
88
+
89
+ if tolerance and timestamp < time.time() - tolerance:
90
+ raise SignatureVerificationError(
91
+ "Timestamp outside the tolerance zone (%d)" % timestamp,
92
+ header,
93
+ payload,
94
+ )
95
+
96
+ return True
@@ -1,18 +1,19 @@
1
1
  from abc import abstractmethod
2
2
  from tempfile import NamedTemporaryFile
3
+ from typing import Dict, List, Union
3
4
 
4
5
  from splight_lib.abstract.client import AbstractClient, QuerySet
5
6
 
6
7
 
7
8
  class AbstractDatabaseClient(AbstractClient):
8
9
  @abstractmethod
9
- def save(self, resource_name: str, instance: dict) -> dict:
10
+ def save(self, resource_name: str, instance: Dict) -> Dict:
10
11
  pass
11
12
 
12
13
  @abstractmethod
13
14
  def _get(
14
15
  self, resource_name: str, first: bool = False, **kwargs
15
- ) -> dict | list[dict]:
16
+ ) -> Union[Dict, List[Dict]]:
16
17
  pass
17
18
 
18
19
  def get(self, resource_name: str, *args, **kwargs) -> QuerySet:
@@ -23,5 +24,5 @@ class AbstractDatabaseClient(AbstractClient):
23
24
  pass
24
25
 
25
26
  @abstractmethod
26
- def download(self, instance: dict) -> NamedTemporaryFile:
27
+ def download(self, instance: Dict) -> NamedTemporaryFile:
27
28
  pass
@@ -1,4 +1,4 @@
1
- from typing import Any
1
+ from typing import Any, Dict
2
2
 
3
3
  from splight_lib.client.database.abstract import AbstractDatabaseClient
4
4
  from splight_lib.client.database.remote_client import RemoteDatabaseClient
@@ -6,6 +6,6 @@ from splight_lib.client.database.remote_client import RemoteDatabaseClient
6
6
 
7
7
  class DatabaseClientBuilder:
8
8
  @staticmethod
9
- def build(parameters: dict[str, Any] = {}) -> AbstractDatabaseClient:
9
+ def build(parameters: Dict[str, Any] = {}) -> AbstractDatabaseClient:
10
10
  db_client = RemoteDatabaseClient(**parameters)
11
11
  return db_client
@@ -1,5 +1,5 @@
1
1
  from tempfile import NamedTemporaryFile
2
- from typing import Any, Generator
2
+ from typing import Any, Dict, Generator, List, Optional, Union
3
3
 
4
4
  import progressbar
5
5
  import requests
@@ -31,9 +31,9 @@ logger = get_splight_logger()
31
31
 
32
32
  class PaginatedResponse(TypedDict):
33
33
  count: int
34
- next: str | None
35
- previous: str | None
36
- results: list[Any]
34
+ next: Optional[str]
35
+ previous: Optional[str]
36
+ results: List[Any]
37
37
 
38
38
 
39
39
  class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
@@ -66,9 +66,9 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
66
66
  def save(
67
67
  self,
68
68
  resource_name: str,
69
- instance: dict,
70
- files: dict[str, str] | None = None,
71
- ) -> dict:
69
+ instance: Dict,
70
+ files: Optional[Dict[str, str]] = None,
71
+ ) -> Dict:
72
72
  """Creates or updates a resource depending on the name if
73
73
  it contains the id or not.
74
74
 
@@ -126,7 +126,7 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
126
126
  resource_name: str,
127
127
  first: bool = False,
128
128
  **kwargs,
129
- ) -> dict | list[dict]:
129
+ ) -> Union[Dict, List[Dict]]:
130
130
  """Retrieves one or multiple resources. If the parameter id is passed
131
131
  as a kwarg, the instance with that id will be retrieved.
132
132
 
@@ -149,7 +149,7 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
149
149
  )
150
150
  return instances
151
151
 
152
- def operate(self, resource_name: str, instance: dict) -> dict:
152
+ def operate(self, resource_name: str, instance: Dict) -> Dict:
153
153
  model_name = resource_name.lower()
154
154
  api_path = CUSTOM_PATHS_MAP.get(model_name)
155
155
  if not api_path:
@@ -163,7 +163,7 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
163
163
 
164
164
  def _retrieve_multiple(
165
165
  self, resource_name: str, first: bool = False, **kwargs
166
- ) -> list[dict]:
166
+ ) -> List[Dict]:
167
167
  logger.debug(f"Retrieving objects {resource_name}")
168
168
  api_path = self._get_api_path(resource_name)
169
169
  url = self._base_url / api_path
@@ -176,7 +176,7 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
176
176
  return instances
177
177
 
178
178
  @retry(SPLIGHT_REQUEST_EXCEPTIONS, tries=3, delay=1)
179
- def _retrieve_single(self, resource_name: str, id: str) -> dict:
179
+ def _retrieve_single(self, resource_name: str, id: str) -> Dict:
180
180
  logger.debug(f"Retrieving object {resource_name} with id {id}")
181
181
  api_path = self._get_api_path(resource_name)
182
182
  url = self._base_url / api_path / f"{id}/"
@@ -191,8 +191,8 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
191
191
  def download(
192
192
  self,
193
193
  resource_name: str,
194
- instance: dict,
195
- type_: str | None = None,
194
+ instance: Dict,
195
+ type_: Optional[str] = None,
196
196
  **kwargs,
197
197
  ) -> NamedTemporaryFile:
198
198
  """Returns the number of resources in the database for a given model
@@ -271,9 +271,9 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
271
271
  def _create(
272
272
  self,
273
273
  resource_name: str,
274
- instance: dict,
275
- files: dict[str, str] | None = None,
276
- ) -> dict:
274
+ instance: Dict,
275
+ files: Optional[Dict[str, str]] = None,
276
+ ) -> Dict:
277
277
  logger.debug("Saving new instance", tags=LogTags.DATABASE)
278
278
  model_name = resource_name.lower()
279
279
  api_path = self._get_api_path(resource_name)
@@ -305,9 +305,9 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
305
305
  self,
306
306
  resource_name: str,
307
307
  resource_id: str,
308
- instance: dict,
309
- files: dict[str, str] | None = None,
310
- ) -> dict:
308
+ instance: Dict,
309
+ files: Optional[Dict[str, str]] = None,
310
+ ) -> Dict:
311
311
  logger.debug("Saving instance %s", resource_id, tags=LogTags.DATABASE)
312
312
  model_name = resource_name.lower()
313
313
  api_path = self._get_api_path(resource_name)
@@ -323,7 +323,7 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
323
323
  raise RequestError(response.status_code, response.text)
324
324
  return response.json()
325
325
 
326
- def _create_file(self, instance: dict, url: furl):
326
+ def _create_file(self, instance: Dict, url: furl):
327
327
  response = self._restclient.post(url, data=instance)
328
328
  if response.is_error:
329
329
  raise RequestError(response.status_code, response.text)
@@ -333,7 +333,7 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
333
333
  self._upload_file(created_instance, file_path=file_path)
334
334
  return created_instance
335
335
 
336
- def _upload_file(self, instance: dict, file_path: str):
336
+ def _upload_file(self, instance: Dict, file_path: str):
337
337
  api_path = self._get_api_path("file")
338
338
  resource_id = instance.get("id")
339
339
  url = self._base_url / api_path / f"{resource_id}/upload_url/"
@@ -358,9 +358,9 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
358
358
  def upload(
359
359
  self,
360
360
  resource_name: str,
361
- instance: dict,
361
+ instance: Dict,
362
362
  file_path: str,
363
- type_: str | None = None,
363
+ type_: Optional[str] = None,
364
364
  ):
365
365
  api_path = self._get_api_path(resource_name)
366
366
  resource_id = instance.get("id")
@@ -1,4 +1,5 @@
1
1
  from datetime import datetime, timezone
2
+ from typing import Dict, List
2
3
 
3
4
 
4
5
  class DatalakeDocumentBuffer:
@@ -7,13 +8,13 @@ class DatalakeDocumentBuffer:
7
8
  def __init__(self, buffer_size: int, buffer_timeout: float):
8
9
  self._size = buffer_size
9
10
  self._timeout = buffer_timeout
10
- self._buffer: list[dict] = []
11
+ self._buffer: List[Dict] = []
11
12
  self._last_flush = datetime.now(timezone.utc)
12
13
 
13
14
  self.reset()
14
15
 
15
16
  @property
16
- def data(self) -> list[dict]:
17
+ def data(self) -> List[Dict]:
17
18
  """Retrieves the buffer data
18
19
 
19
20
  Returns
@@ -44,7 +45,7 @@ class DatalakeDocumentBuffer:
44
45
  self._last_flush = datetime.now(timezone.utc)
45
46
  self._buffer = []
46
47
 
47
- def add_documents(self, documents: list[dict]):
48
+ def add_documents(self, documents: List[Dict]):
48
49
  """Adds new documents to the buffer.
49
50
 
50
51
  Parameters
@@ -1,4 +1,4 @@
1
- from typing import Any
1
+ from typing import Any, Dict
2
2
 
3
3
  from splight_lib.client.datalake.abstract import AbstractDatalakeClient
4
4
  from splight_lib.client.datalake.remote_client import (
@@ -19,6 +19,6 @@ class DatalakeClientBuilder:
19
19
  @staticmethod
20
20
  def build(
21
21
  dl_client_type: DatalakeClientType = DatalakeClientType.BUFFERED_ASYNC,
22
- parameters: dict[str, Any] = {},
22
+ parameters: Dict[str, Any] = {},
23
23
  ) -> AbstractDatalakeClient:
24
24
  return DL_CLIENT_TYPE_MAP[dl_client_type](**parameters)
@@ -0,0 +1,34 @@
1
+ import os
2
+ from typing import List
3
+
4
+
5
+ class FixedLineNumberFileHandler:
6
+ def __init__(self, file_path: str, total_lines: int = 10000):
7
+ self._file_path = file_path
8
+ if not os.path.exists(self._file_path):
9
+ self._write_file([])
10
+ self._total_lines = total_lines
11
+
12
+ def write(self, lines: List[str], override=False):
13
+ all_lines = self._read_file()
14
+
15
+ if override:
16
+ all_lines = lines
17
+ else:
18
+ all_lines.extend(lines)
19
+
20
+ lines = all_lines[-self._total_lines :]
21
+ lines = [f"{x}\n" for x in lines]
22
+ self._write_file(lines)
23
+
24
+ def read(self) -> List[str]:
25
+ return self._read_file()
26
+
27
+ def _write_file(self, lines: List[str]):
28
+ with open(self._file_path, "w") as fid:
29
+ fid.writelines(lines)
30
+
31
+ def _read_file(self) -> List[str]:
32
+ with open(self._file_path, "r") as fid:
33
+ all_lines = [x.strip() for x in fid.readlines()]
34
+ return all_lines
@@ -0,0 +1,18 @@
1
+ from typing import Any, Dict, Tuple
2
+
3
+
4
+ def value_filter(name: str, value: Any, item: Dict):
5
+ satisfied = False
6
+ if "__icontains" in name:
7
+ variable_name = name.split("__")[0]
8
+ satisfied = value in item.get(variable_name, None)
9
+ elif "__in" in name:
10
+ variable_name = name.split("__in")[0]
11
+ satisfied = item.get(variable_name, None) in value
12
+ else:
13
+ satisfied = item.get(name, None) == value
14
+ return satisfied
15
+
16
+
17
+ def value_filter_on_tuple(name: str, value: Any, item: Tuple[str, Dict]):
18
+ return value_filter(name=name, value=value, item=item[1])
@@ -1,4 +1,5 @@
1
1
  from abc import abstractmethod
2
+ from typing import Dict, List, Tuple
2
3
 
3
4
  from pydantic import BaseModel
4
5
 
@@ -16,7 +17,7 @@ class AbstractHubClient(AbstractClient):
16
17
  limit_: int = -1,
17
18
  skip_: int = 0,
18
19
  **kwargs,
19
- ) -> list[BaseModel]:
20
+ ) -> List[BaseModel]:
20
21
  pass
21
22
 
22
23
  @abstractmethod
@@ -24,7 +25,7 @@ class AbstractHubClient(AbstractClient):
24
25
  pass
25
26
 
26
27
  @abstractmethod
27
- def download(self, data: dict) -> tuple:
28
+ def download(self, data: Dict) -> Tuple:
28
29
  pass
29
30
 
30
31
  @abstractmethod
@@ -32,5 +33,5 @@ class AbstractHubClient(AbstractClient):
32
33
  pass
33
34
 
34
35
  @abstractmethod
35
- def save(self, instance: dict) -> dict:
36
+ def save(self, instance: Dict) -> Dict:
36
37
  pass
@@ -1,5 +1,5 @@
1
1
  from tempfile import NamedTemporaryFile
2
- from typing import Any, Generator, TypedDict
2
+ from typing import Any, Dict, Generator, List, Optional, TypedDict
3
3
 
4
4
  import progressbar
5
5
  import requests
@@ -13,9 +13,9 @@ from splight_lib.client.hub.abstract import AbstractHubClient
13
13
 
14
14
  class PaginatedResponse(TypedDict):
15
15
  count: int
16
- next: str | None
17
- previous: str | None
18
- results: list[Any]
16
+ next: Optional[str]
17
+ previous: Optional[str]
18
+ results: List[Any]
19
19
 
20
20
 
21
21
  class SplightHubClient(AbstractHubClient):
@@ -58,7 +58,7 @@ class SplightHubClient(AbstractHubClient):
58
58
  limit_: int = -1,
59
59
  skip_: int = 0,
60
60
  **kwargs,
61
- ) -> list[BaseModel]:
61
+ ) -> List[BaseModel]:
62
62
  url = self._hub_url / "versions/"
63
63
  params = self._get_params(limit_, skip_, **kwargs)
64
64
  instances = []
@@ -71,14 +71,14 @@ class SplightHubClient(AbstractHubClient):
71
71
  def get_org_id(self):
72
72
  return self._org_id
73
73
 
74
- def _create(self, instance: dict) -> dict:
74
+ def _create(self, instance: Dict) -> Dict:
75
75
  url = self._hub_url / "components/"
76
76
  response = self._session.post(url, json=instance)
77
77
  response.raise_for_status()
78
78
  instance = response.json()
79
79
  return instance
80
80
 
81
- def _update(self, instance: dict) -> dict:
81
+ def _update(self, instance: Dict) -> Dict:
82
82
  instance_id = instance.get("id")
83
83
  url = self._hub_url / "versions" / f"{instance_id}/"
84
84
  response = self._session.put(url, json=instance)
@@ -86,12 +86,12 @@ class SplightHubClient(AbstractHubClient):
86
86
  instance = response.json()
87
87
  return instance
88
88
 
89
- def build(self, id: str) -> None:
89
+ def build(self, id: str):
90
90
  url = self._hub_url / f"versions/{id}/build/"
91
91
  response = self._session.post(url)
92
92
  response.raise_for_status()
93
93
 
94
- def upload(self, id: str, file_path: str, type_: str) -> None:
94
+ def upload(self, id: str, file_path: str, type_: str):
95
95
  url = self._hub_url / f"versions/{id}/upload_url/"
96
96
  params = {"type": type_}
97
97
  response = self._session.get(url, params=params)
@@ -135,7 +135,7 @@ class SplightHubClient(AbstractHubClient):
135
135
  response.status_code == 204
136
136
  ), f"Failed to delete component: {response.json()}"
137
137
 
138
- def save(self, instance: dict) -> dict:
138
+ def save(self, instance: Dict) -> Dict:
139
139
  if instance.get("id"):
140
140
  return self._update(instance)
141
141
  else:
@@ -5,7 +5,7 @@ from collections import namedtuple
5
5
  from tempfile import NamedTemporaryFile
6
6
  from threading import Thread
7
7
  from time import sleep
8
- from typing import Callable, Type
8
+ from typing import Callable, Dict, Optional, Type
9
9
 
10
10
  from pydantic import BaseModel
11
11
  from pydantic_core import ValidationError
@@ -70,7 +70,7 @@ class HealthCheckProcessor:
70
70
  class SplightBaseComponent(ABC):
71
71
  def __init__(
72
72
  self,
73
- component_id: str | None = None,
73
+ component_id: Optional[str] = None,
74
74
  ):
75
75
  self._component_id = component_id
76
76
  self._execution_engine = ExecutionEngine()
@@ -185,7 +185,7 @@ class SplightBaseComponent(ABC):
185
185
  return wrapper
186
186
 
187
187
  def _get_custom_type_model(
188
- self, component_object: dict[str, Type[ComponentObjectInstance]]
188
+ self, component_object: Dict[str, Type[ComponentObjectInstance]]
189
189
  ) -> BaseModel:
190
190
  custom_type_model = namedtuple(
191
191
  "CustomTypes", [k for k in component_object.keys()]
@@ -193,7 +193,7 @@ class SplightBaseComponent(ABC):
193
193
  return custom_type_model(**component_object)
194
194
 
195
195
  def _get_routine_model(
196
- self, routine_objects: dict[str, Type[RoutineObjectInstance]]
196
+ self, routine_objects: Dict[str, Type[RoutineObjectInstance]]
197
197
  ) -> namedtuple:
198
198
  routine_model = namedtuple(
199
199
  "ComponentRoutine", [k for k in routine_objects.keys()]
@@ -209,9 +209,9 @@ class SplightBaseComponent(ABC):
209
209
  return spec
210
210
 
211
211
  @abstractmethod
212
- def start(self) -> None:
212
+ def start(self):
213
213
  raise NotImplementedError()
214
214
 
215
- def stop(self) -> None:
215
+ def stop(self):
216
216
  self._execution_engine.stop()
217
217
  sys.exit(1)