splight-lib 5.2.7__tar.gz → 5.4.0__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 (94) hide show
  1. {splight_lib-5.2.7 → splight_lib-5.4.0}/PKG-INFO +2 -1
  2. {splight_lib-5.2.7 → splight_lib-5.4.0}/pyproject.toml +2 -1
  3. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/database/classmap.py +1 -1
  4. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/database/remote_client.py +57 -14
  5. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/exceptions.py +4 -0
  6. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/exceptions.py +4 -0
  7. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/file.py +7 -24
  8. {splight_lib-5.2.7 → splight_lib-5.4.0}/LICENSE.txt +0 -0
  9. {splight_lib-5.2.7 → splight_lib-5.4.0}/README.md +0 -0
  10. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/__init__.py +0 -0
  11. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/abstract/__init__.py +0 -0
  12. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/abstract/client.py +0 -0
  13. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/auth/__init__.py +0 -0
  14. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/auth/exceptions.py +0 -0
  15. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/auth/mac_auth.py +0 -0
  16. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/auth/token.py +0 -0
  17. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/__init__.py +0 -0
  18. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/database/__init__.py +0 -0
  19. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/database/abstract.py +0 -0
  20. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/database/builder.py +0 -0
  21. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/database/local_client.py +0 -0
  22. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/datalake/__init__.py +0 -0
  23. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/datalake/abstract.py +0 -0
  24. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/datalake/buffer.py +0 -0
  25. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/datalake/builder.py +0 -0
  26. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/datalake/exceptions.py +0 -0
  27. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/datalake/local_client.py +0 -0
  28. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/datalake/remote_client.py +0 -0
  29. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/datalake/schemas.py +0 -0
  30. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/file_handler.py +0 -0
  31. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/filter.py +0 -0
  32. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/hub/__init__.py +0 -0
  33. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/hub/abstract.py +0 -0
  34. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/hub/client.py +0 -0
  35. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/tests/test_database.py +0 -0
  36. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/client/tests/test_datalake.py +0 -0
  37. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/component/__init__.py +0 -0
  38. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/component/abstract.py +0 -0
  39. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/component/exceptions.py +0 -0
  40. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/component/spec.py +0 -0
  41. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/component/tests/test_abstract.py +0 -0
  42. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/component/tests/test_spec.py +0 -0
  43. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/constants.py +0 -0
  44. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/encryption.py +0 -0
  45. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/execution/__init__.py +0 -0
  46. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/execution/engine.py +0 -0
  47. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/execution/exceptions.py +0 -0
  48. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/execution/scheduling.py +0 -0
  49. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/execution/task.py +0 -0
  50. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/execution/tests/test_execution.py +0 -0
  51. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/execution/tests/test_scheduling.py +0 -0
  52. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/execution/trigger.py +0 -0
  53. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/logging/__init__.py +0 -0
  54. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/logging/_internal.py +0 -0
  55. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/logging/component.py +0 -0
  56. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/logging/constants.py +0 -0
  57. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/logging/logging.py +0 -0
  58. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/logging/tests/test_logging.py +0 -0
  59. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/__init__.py +0 -0
  60. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/alert.py +0 -0
  61. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/asset.py +0 -0
  62. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/attribute.py +0 -0
  63. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/base.py +0 -0
  64. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/component.py +0 -0
  65. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/dashboard.py +0 -0
  66. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/data_address.py +0 -0
  67. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/function.py +0 -0
  68. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/generic.py +0 -0
  69. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/hub.py +0 -0
  70. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/metadata.py +0 -0
  71. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/native.py +0 -0
  72. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/pipeline.py +0 -0
  73. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/secret.py +0 -0
  74. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/tests/models.json +0 -0
  75. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/tests/test_component_object_instance.py +0 -0
  76. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/tests/test_database_model.py +0 -0
  77. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/tests/test_metadata.py +0 -0
  78. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/models/tests/test_models.py +0 -0
  79. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/restclient/__init__.py +0 -0
  80. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/restclient/client.py +0 -0
  81. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/restclient/exceptions.py +0 -0
  82. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/restclient/tests/test_restclient.py +0 -0
  83. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/restclient/types.py +0 -0
  84. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/settings.py +0 -0
  85. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/stringcase.py +0 -0
  86. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/testing/__init__.py +0 -0
  87. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/tests/FakeProc.py +0 -0
  88. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/tests/asset_geometries.json +0 -0
  89. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/tests/test_api_contracts.py +0 -0
  90. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/tests/test_encryption.py +0 -0
  91. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/utils/__init__.py +0 -0
  92. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/utils/custom_model.py +0 -0
  93. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/utils/hub.py +0 -0
  94. {splight_lib-5.2.7 → splight_lib-5.4.0}/splight_lib/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: splight-lib
3
- Version: 5.2.7
3
+ Version: 5.4.0
4
4
  Summary: Splight Library
5
5
  Author: Splight Dev
6
6
  Author-email: dev@splight-ae.com
@@ -23,6 +23,7 @@ Requires-Dist: mergedeep (==1.3.4)
23
23
  Requires-Dist: pandas (==1.5.2)
24
24
  Requires-Dist: parameterized (==0.8.1)
25
25
  Requires-Dist: pathspec (==0.11.1)
26
+ Requires-Dist: progressbar2 (==4.4.1)
26
27
  Requires-Dist: protobuf (==4.21.6)
27
28
  Requires-Dist: py7zr (==0.20.8)
28
29
  Requires-Dist: pydantic (==2.4.2)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "splight-lib"
3
- version = "5.2.7"
3
+ version = "5.4.0"
4
4
  description = "Splight Library"
5
5
  authors = ["Splight Dev <dev@splight-ae.com>"]
6
6
  readme = "README.md"
@@ -33,6 +33,7 @@ pydantic-settings = "2.0.3"
33
33
  email-validator = "^2.1.0.post1"
34
34
  apscheduler = "3.10.4"
35
35
  typer = "0.9.0"
36
+ progressbar2 = "4.4.1"
36
37
 
37
38
  [tool.poetry.group.dev.dependencies]
38
39
  black = "23.3.0"
@@ -11,7 +11,7 @@ MODEL_NAME_MAP = {
11
11
  "component": f"{ENGINE_PREFIX}/component/components/",
12
12
  "componentobject": f"{ENGINE_PREFIX}/component/objects/",
13
13
  "dashboard": f"{ENGINE_PREFIX}/dashboard/dashboards/",
14
- "file": f"{ENGINE_PREFIX}/file/files/",
14
+ "file": f"{ENGINE_PREFIX}/files/",
15
15
  "filter": f"{ENGINE_PREFIX}/dashboard/filters/",
16
16
  "function": f"{ENGINE_PREFIX}/function/functions/",
17
17
  "query": f"{ENGINE_PREFIX}/queries/",
@@ -1,6 +1,8 @@
1
1
  from tempfile import NamedTemporaryFile
2
2
  from typing import Any, Dict, Generator, List, Optional, Union
3
3
 
4
+ import progressbar
5
+ import requests
4
6
  from furl import furl
5
7
  from httpx._status_codes import codes
6
8
  from retry import retry
@@ -16,6 +18,7 @@ from splight_lib.client.database.classmap import (
16
18
  from splight_lib.client.exceptions import (
17
19
  SPLIGHT_REQUEST_EXCEPTIONS,
18
20
  InstanceNotFound,
21
+ InvalidModel,
19
22
  InvalidModelName,
20
23
  )
21
24
  from splight_lib.constants import ENGINE_PREFIX
@@ -145,7 +148,6 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
145
148
  response.raise_for_status()
146
149
  return response.json()
147
150
 
148
- # @retry(SPLIGHT_REQUEST_EXCEPTIONS, tries=3, delay=1)
149
151
  def _retrieve_multiple(
150
152
  self, resource_name: str, first: bool = False, **kwargs
151
153
  ) -> List[Dict]:
@@ -196,16 +198,33 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
196
198
  ------
197
199
  InvalidModelName thrown when the model name is not correct.
198
200
  """
201
+ if resource_name.lower() != "file":
202
+ raise InvalidModel("Only files can be downloaded.")
199
203
  api_path = self._get_api_path(resource_name)
200
204
  resource_id = instance.get("id")
201
- url = self._base_url / api_path / f"{resource_id}/download/"
205
+ url = self._base_url / api_path / f"{resource_id}/download_url/"
202
206
  response = self._restclient.get(url)
203
207
  response.raise_for_status()
204
- f = NamedTemporaryFile("wb+")
205
- f.write(response.content)
206
- f.seek(0)
208
+ download_url = response.json().get("url")
209
+
210
+ file = NamedTemporaryFile(mode="wb+", suffix=instance["name"])
211
+ # TODO: Check why python wget is raised and error with code 403
212
+ response = requests.get(download_url, stream=True)
213
+ with open(file.name, "wb") as f:
214
+ length = int(response.headers.get("content-length"))
215
+ chunk_size = 8192
216
+ total_chunks = length // chunk_size + 1
217
+ widgets = ["Downloading: ", progressbar.Bar("#")]
218
+ bar = progressbar.ProgressBar(
219
+ max_value=total_chunks, widgets=widgets
220
+ ).start()
221
+ for counter, chunk in enumerate(
222
+ response.iter_content(chunk_size=chunk_size)
223
+ ):
224
+ f.write(chunk)
225
+ bar.update(counter)
207
226
  logger.debug("Downloaded instance %s.", id, tags=LogTags.DATABASE)
208
- return f
227
+ return file
209
228
 
210
229
  def _pages(
211
230
  self, url: furl, **kwargs
@@ -233,16 +252,11 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
233
252
  api_path = self._get_api_path(resource_name)
234
253
  url = self._base_url / api_path
235
254
  if model_name == "file":
236
- with open(instance["file"], "rb") as f:
237
- file = {"file": f}
238
- response = self._restclient.post(
239
- url, data=instance, files=file
240
- )
255
+ instance = self._create_file(instance, url)
241
256
  else:
242
257
  response = self._restclient.post(url, json=instance)
243
-
244
- response.raise_for_status()
245
- instance = response.json()
258
+ response.raise_for_status()
259
+ instance = response.json()
246
260
  logger.debug(
247
261
  "Instance %s created", instance["id"], tags=LogTags.DATABASE
248
262
  )
@@ -265,6 +279,35 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
265
279
  response.raise_for_status()
266
280
  return response.json()
267
281
 
282
+ def _create_file(self, instance: Dict, url: furl):
283
+ response = self._restclient.post(url, data=instance)
284
+ response.raise_for_status()
285
+ file_path = instance["file"]
286
+ # Check is this is handled somewher
287
+ created_instance = response.json()
288
+ self._upload_file(created_instance, file_path=file_path)
289
+ return created_instance
290
+
291
+ def _upload_file(self, instance: Dict, file_path: str):
292
+ api_path = self._get_api_path("file")
293
+ resource_id = instance.get("id")
294
+ url = self._base_url / api_path / f"{resource_id}/upload_url/"
295
+ response = self._restclient.get(url)
296
+ response.raise_for_status()
297
+ upload_url = response.json().get("url")
298
+ file = open(file_path, "rb")
299
+ file_name = instance["name"]
300
+ with open(file_path, "rb") as fid:
301
+ file = {"file": (file_name, fid)}
302
+ response = requests.put(
303
+ upload_url,
304
+ files=file,
305
+ )
306
+ response.raise_for_status()
307
+ logger.debug(
308
+ "File uploaded succesfully %s.", resource_id, tags=LogTags.DATABASE
309
+ )
310
+
268
311
  @staticmethod
269
312
  def _get_api_path(resource_name: str) -> str:
270
313
  model_name = resource_name.lower()
@@ -30,3 +30,7 @@ class InstanceNotFound(Exception):
30
30
 
31
31
  def __str__(self) -> str:
32
32
  return self._msg
33
+
34
+
35
+ class InvalidModel(Exception):
36
+ ...
@@ -28,3 +28,7 @@ class InvalidAlertConfiguration(Exception):
28
28
 
29
29
  class MissingAlertItemExpression(Exception):
30
30
  pass
31
+
32
+
33
+ class ForbiddenOperation(Exception):
34
+ pass
@@ -1,13 +1,12 @@
1
1
  import json
2
- import os
3
2
  from typing import Dict, List, Optional
4
3
 
5
- from pydantic import Field, field_validator, model_validator
6
- from pysher.pusher import hashlib
4
+ from pydantic import Field, field_validator
7
5
 
8
6
  from splight_lib.constants import DESCRIPTION_MAX_LENGTH
9
7
  from splight_lib.models.asset import Asset
10
8
  from splight_lib.models.base import SplightDatabaseBaseModel
9
+ from splight_lib.models.exceptions import ForbiddenOperation
11
10
 
12
11
 
13
12
  class File(SplightDatabaseBaseModel):
@@ -20,24 +19,7 @@ class File(SplightDatabaseBaseModel):
20
19
  )
21
20
  metadata: Dict = {}
22
21
  content_type: Optional[str] = None
23
- url: Optional[str] = None
24
- checksum: Optional[str] = None
25
-
26
- @model_validator(mode="after")
27
- def validate_file(self):
28
- if self.file:
29
- self.file = self.file.replace("/", os.sep)
30
- self.file = self.file.replace("\\", os.sep)
31
-
32
- # Compute the checksum if missing
33
- if self.checksum is None:
34
- hasher = hashlib.md5()
35
- with open(self.file, "rb") as file:
36
- # Read in chunks of 8KiB for large files
37
- while chunk := file.read(8192):
38
- hasher.update(chunk)
39
- self.checksum = hasher.hexdigest()
40
- return self
22
+ parent: Optional[str] = None
41
23
 
42
24
  @field_validator("metadata", mode="before")
43
25
  def validate_metadata(cls, v):
@@ -65,12 +47,13 @@ class File(SplightDatabaseBaseModel):
65
47
  return res
66
48
 
67
49
  def save(self):
50
+ if self.id:
51
+ raise ForbiddenOperation(
52
+ "File object already exists in database. Can't be updated"
53
+ )
68
54
  saved = self._db_client.save(
69
55
  self.__class__.__name__, self.model_dump(exclude_none=True)
70
56
  )
71
57
  if not self.id:
72
58
  self.id = saved["id"]
73
59
  self.name = saved["name"]
74
- self.content_type = saved["content_type"]
75
- self.checksum = saved["checksum"]
76
- self.url = saved["url"]
File without changes
File without changes