cognite-extractor-utils 7.5.13__py3-none-any.whl → 7.5.14__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 cognite-extractor-utils might be problematic. Click here for more details.

@@ -16,7 +16,7 @@
16
16
  Cognite extractor utils is a Python package that simplifies the development of new extractors.
17
17
  """
18
18
 
19
- __version__ = "7.5.13"
19
+ __version__ = "7.5.14"
20
20
  from .base import Extractor
21
21
 
22
22
  __all__ = ["Extractor"]
@@ -18,6 +18,7 @@ from dataclasses import dataclass, field
18
18
  from datetime import timedelta
19
19
  from enum import Enum
20
20
  from logging.handlers import TimedRotatingFileHandler
21
+ from pathlib import Path
21
22
  from time import sleep
22
23
  from typing import Any
23
24
  from urllib.parse import urljoin, urlparse
@@ -512,6 +513,7 @@ class _PushGatewayConfig:
512
513
  push_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
513
514
 
514
515
 
516
+ @dataclass
515
517
  class _PromServerConfig:
516
518
  port: int = 9000
517
519
  host: str = "0.0.0.0"
@@ -649,7 +651,7 @@ class LocalStateStoreConfig:
649
651
  Configuration of a state store using a local JSON file
650
652
  """
651
653
 
652
- path: str
654
+ path: Path
653
655
  save_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
654
656
 
655
657
 
@@ -695,8 +697,11 @@ class StateStoreConfig:
695
697
  )
696
698
 
697
699
  if self.local:
700
+ if self.local.path.is_dir():
701
+ raise ValueError(f"{self.local.path} is a directory, and not a file")
702
+
698
703
  return LocalStateStore(
699
- file_path=self.local.path,
704
+ file_path=str(self.local.path),
700
705
  save_interval=self.local.save_interval.seconds,
701
706
  cancellation_token=cancellation_token,
702
707
  )
@@ -7,6 +7,7 @@ from typing import TextIO, TypeVar
7
7
  from pydantic import ValidationError
8
8
 
9
9
  from cognite.client import CogniteClient
10
+ from cognite.client.exceptions import CogniteAPIError
10
11
  from cognite.extractorutils.configtools.loaders import _load_yaml_dict_raw
11
12
  from cognite.extractorutils.exceptions import InvalidConfigError as OldInvalidConfigError
12
13
  from cognite.extractorutils.unstable.configuration.exceptions import InvalidConfigError
@@ -41,12 +42,17 @@ def load_from_cdf(
41
42
  params: dict[str, str | int] = {"integration": external_id}
42
43
  if revision:
43
44
  params["revision"] = revision
44
- response = cognite_client.get(
45
- f"/api/v1/projects/{cognite_client.config.project}/odin/config",
46
- params=params,
47
- headers={"cdf-version": "alpha"},
48
- )
49
- response.raise_for_status()
45
+ try:
46
+ response = cognite_client.get(
47
+ f"/api/v1/projects/{cognite_client.config.project}/odin/config",
48
+ params=params,
49
+ headers={"cdf-version": "alpha"},
50
+ )
51
+ except CogniteAPIError as e:
52
+ if e.code == 404:
53
+ raise InvalidConfigError("No configuration found for the given integration") from e
54
+ raise e
55
+
50
56
  data = response.json()
51
57
 
52
58
  try:
@@ -5,17 +5,29 @@ import time
5
5
  from argparse import ArgumentParser, Namespace
6
6
  from multiprocessing import Process, Queue
7
7
  from pathlib import Path
8
+ from random import randint
8
9
  from typing import Any, Generic, TypeVar
10
+ from uuid import uuid4
9
11
 
10
12
  from requests.exceptions import ConnectionError
11
13
  from typing_extensions import assert_never
12
14
 
13
- from cognite.client.exceptions import CogniteAPIError, CogniteAuthError, CogniteConnectionError
15
+ from cognite.client import CogniteClient
16
+ from cognite.client.exceptions import (
17
+ CogniteAPIError,
18
+ CogniteAuthError,
19
+ CogniteConnectionError,
20
+ )
14
21
  from cognite.extractorutils.threading import CancellationToken
15
22
  from cognite.extractorutils.unstable.configuration.exceptions import InvalidConfigError
16
- from cognite.extractorutils.unstable.configuration.loaders import load_file, load_from_cdf
23
+ from cognite.extractorutils.unstable.configuration.loaders import (
24
+ load_file,
25
+ load_from_cdf,
26
+ )
17
27
  from cognite.extractorutils.unstable.configuration.models import ConnectionConfig
18
28
  from cognite.extractorutils.unstable.core._dto import Error
29
+ from cognite.extractorutils.unstable.core.errors import ErrorLevel
30
+ from cognite.extractorutils.util import now
19
31
 
20
32
  from ._messaging import RuntimeMessage
21
33
  from .base import ConfigRevision, ConfigType, Extractor, FullConfig
@@ -26,6 +38,8 @@ ExtractorType = TypeVar("ExtractorType", bound=Extractor)
26
38
 
27
39
 
28
40
  class Runtime(Generic[ExtractorType]):
41
+ RETRY_CONFIG_INTERVAL = 30
42
+
29
43
  def __init__(
30
44
  self,
31
45
  extractor: type[ExtractorType],
@@ -37,6 +51,8 @@ class Runtime(Generic[ExtractorType]):
37
51
  self.logger = logging.getLogger(f"{self._extractor_class.EXTERNAL_ID}.runtime")
38
52
  self._setup_logging()
39
53
 
54
+ self._cognite_client: CogniteClient
55
+
40
56
  def _create_argparser(self) -> ArgumentParser:
41
57
  argparser = ArgumentParser(
42
58
  prog=sys.argv[0],
@@ -121,7 +137,7 @@ class Runtime(Generic[ExtractorType]):
121
137
  self.logger.info(f"Started extractor with PID {process.pid}")
122
138
  return process
123
139
 
124
- def _get_application_config(
140
+ def _try_get_application_config(
125
141
  self,
126
142
  args: Namespace,
127
143
  connection_config: ConnectionConfig,
@@ -143,39 +159,65 @@ class Runtime(Generic[ExtractorType]):
143
159
 
144
160
  else:
145
161
  self.logger.info("Loading application config from CDF")
146
- client = connection_config.get_cognite_client(
147
- f"{self._extractor_class.EXTERNAL_ID}-{self._extractor_class.VERSION}"
162
+
163
+ application_config, current_config_revision = load_from_cdf(
164
+ self._cognite_client,
165
+ connection_config.integration,
166
+ self._extractor_class.CONFIG_TYPE,
148
167
  )
149
168
 
150
- errors: list[Error] = []
169
+ return application_config, current_config_revision
170
+
171
+ def _safe_get_application_config(
172
+ self,
173
+ args: Namespace,
174
+ connection_config: ConnectionConfig,
175
+ ) -> tuple[ConfigType, ConfigRevision] | None:
176
+ prev_error: str | None = None
151
177
 
178
+ while not self._cancellation_token.is_cancelled:
152
179
  try:
153
- application_config, current_config_revision = load_from_cdf(
154
- client,
155
- connection_config.integration,
156
- self._extractor_class.CONFIG_TYPE,
180
+ return self._try_get_application_config(args, connection_config)
181
+
182
+ except Exception as e:
183
+ error_message = str(e)
184
+ if error_message == prev_error:
185
+ # Same error as before, no need to log it again
186
+ self._cancellation_token.wait(randint(1, self.RETRY_CONFIG_INTERVAL))
187
+ continue
188
+ prev_error = error_message
189
+
190
+ ts = now()
191
+ error = Error(
192
+ external_id=str(uuid4()),
193
+ level=ErrorLevel.fatal.value,
194
+ start_time=ts,
195
+ end_time=ts,
196
+ description=error_message,
197
+ details=None,
198
+ task=None,
157
199
  )
158
200
 
159
- finally:
160
- if errors:
161
- client.post(
162
- f"/api/v1/projects/{client.config.project}/odin/checkin",
163
- json={
164
- "externalId": connection_config.integration,
165
- "errors": [e.model_dump() for e in errors],
166
- },
167
- headers={"cdf-version": "alpha"},
168
- )
201
+ self._cognite_client.post(
202
+ f"/api/v1/projects/{self._cognite_client.config.project}/odin/checkin",
203
+ json={
204
+ "externalId": connection_config.integration,
205
+ "errors": [error.model_dump()],
206
+ },
207
+ headers={"cdf-version": "alpha"},
208
+ )
169
209
 
170
- return application_config, current_config_revision
210
+ self._cancellation_token.wait(randint(1, self.RETRY_CONFIG_INTERVAL))
211
+
212
+ return None
171
213
 
172
214
  def _verify_connection_config(self, connection_config: ConnectionConfig) -> bool:
173
- client = connection_config.get_cognite_client(
215
+ self._cognite_client = connection_config.get_cognite_client(
174
216
  f"{self._extractor_class.EXTERNAL_ID}-{self._extractor_class.VERSION}"
175
217
  )
176
218
  try:
177
- client.post(
178
- f"/api/v1/projects/{client.config.project}/odin/checkin",
219
+ self._cognite_client.post(
220
+ f"/api/v1/projects/{self._cognite_client.config.project}/odin/checkin",
179
221
  json={
180
222
  "externalId": connection_config.integration,
181
223
  },
@@ -234,16 +276,19 @@ class Runtime(Generic[ExtractorType]):
234
276
  if not args.skip_init_checks and not self._verify_connection_config(connection_config):
235
277
  sys.exit(1)
236
278
 
237
- # This has to be Any. We don't know the type of the extractors' config at type checking since the sel doesn't
279
+ # This has to be Any. We don't know the type of the extractors' config at type checking since the self doesn't
238
280
  # exist yet, and I have not found a way to represent it in a generic way that isn't just an Any in disguise.
239
281
  application_config: Any
282
+ config: tuple[Any, ConfigRevision] | None
283
+
240
284
  while not self._cancellation_token.is_cancelled:
241
- try:
242
- application_config, current_config_revision = self._get_application_config(args, connection_config)
285
+ config = self._safe_get_application_config(args, connection_config)
286
+ if config is None:
287
+ if self._cancellation_token.is_cancelled:
288
+ break
289
+ continue
243
290
 
244
- except InvalidConfigError:
245
- self.logger.critical("Could not get a valid application config file. Shutting down")
246
- sys.exit(1)
291
+ application_config, current_config_revision = config
247
292
 
248
293
  # Start extractor in separate process, and wait for it to end
249
294
  process = self._spawn_extractor(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite-extractor-utils
3
- Version: 7.5.13
3
+ Version: 7.5.14
4
4
  Summary: Utilities for easier development of extractors for CDF
5
5
  Project-URL: repository, https://github.com/cognitedata/python-extractor-utils
6
6
  Author-email: Mathias Lohne <mathias.lohne@cognite.com>
@@ -1,4 +1,4 @@
1
- cognite/extractorutils/__init__.py,sha256=1tj9c-PWFN7i3jH6BuYbHEj0xM9tfxqJOF4W-c7GuYg,765
1
+ cognite/extractorutils/__init__.py,sha256=CoUfXp9Vt0lIxThUC3H7MjFYpg5gS32akEvDoPirSV8,765
2
2
  cognite/extractorutils/_inner_util.py,sha256=ZMZIBwFpSD39RzLZq_OJlrFtVt8NFOtU4ObzAG8vTB4,1779
3
3
  cognite/extractorutils/base.py,sha256=eGz3sHHsLJWgPYTVw8xJ-7PJUK7GCK8K61CMpU5R3WU,16414
4
4
  cognite/extractorutils/exceptions.py,sha256=4qreRiTwZH9lyLIKR67TP02MUxN9oYhCd2vFTb5bRME,1125
@@ -10,7 +10,7 @@ cognite/extractorutils/uploader_types.py,sha256=lePcXPrXVcQYtvnF9Uv12gHaeOIGfYKx
10
10
  cognite/extractorutils/util.py,sha256=ZAx688yXV85xmWuAASlZ3e9yY5pvyR8H0r4rhnPdgF4,21052
11
11
  cognite/extractorutils/configtools/__init__.py,sha256=LSa7gVws_mrLCMRTKGs1zfiG6-IM0HzyOF6x0EfllSo,3616
12
12
  cognite/extractorutils/configtools/_util.py,sha256=VMxXXmPvNPf3Jjwknqm7i-Bp-z_ORN0DFKjBHgBsWA0,4773
13
- cognite/extractorutils/configtools/elements.py,sha256=chgcv7WSOb1zbHl1XU5dlsCSB7SDTY4NeKREYNeF9kE,26590
13
+ cognite/extractorutils/configtools/elements.py,sha256=n2Nbl-fZnuMmyduWXh0KfOYibUVZQnCwUeT6OQTnJ6U,26760
14
14
  cognite/extractorutils/configtools/loaders.py,sha256=Iqyn1i050j8vDa2Bb7yJgW2I-riXgdbdFpGX9TRLU84,18374
15
15
  cognite/extractorutils/configtools/validators.py,sha256=xug3GOMIO4NOdyyvXtYlpKyq9wuDtGf7-xqIefD5bIo,1016
16
16
  cognite/extractorutils/statestore/__init__.py,sha256=hV3r11FUXkH6-60Ct6zLSROMNVrEeiE3Shmkf28Q-co,359
@@ -20,7 +20,7 @@ cognite/extractorutils/statestore/watermark.py,sha256=CDQW0QkdBSp_dYFVcOEQCqKNQZ
20
20
  cognite/extractorutils/unstable/__init__.py,sha256=L6nqJHjylpk67CE-PbXJyb_TBI4yjhEYEz9J9WShDfM,341
21
21
  cognite/extractorutils/unstable/configuration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  cognite/extractorutils/unstable/configuration/exceptions.py,sha256=2-0jUp9IFwzk2QTQzWLoGgW1KOApk9UmPmLwtwRUBaE,591
23
- cognite/extractorutils/unstable/configuration/loaders.py,sha256=guBSVz7nd3dfsNEfPEHUUmU5WoYdPQmBBaJk2FuKXVw,3640
23
+ cognite/extractorutils/unstable/configuration/loaders.py,sha256=cb7dvEvIypSv5k81qSFhs95bHROTPhGx5quHOviIb7g,3863
24
24
  cognite/extractorutils/unstable/configuration/models.py,sha256=YYGXxSwct04J9A6NDlW0kpKHvlvtPxuLeMHgq5KwH-g,9567
25
25
  cognite/extractorutils/unstable/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  cognite/extractorutils/unstable/core/_dto.py,sha256=tvvy39cvf-QT28GWz5FpqxQ5vAVk0t69JoPPhpWlweY,1293
@@ -29,7 +29,7 @@ cognite/extractorutils/unstable/core/base.py,sha256=eOtz4nNR3bv-vgQ-ma5yaUGpNN4n
29
29
  cognite/extractorutils/unstable/core/errors.py,sha256=oTRB5Alt-rM90wHfQQM0idjATpv0BrKtoAIOvtu7P-k,2115
30
30
  cognite/extractorutils/unstable/core/logger.py,sha256=MLkOZ6ofFKBpm7UAVy7l_RoUEm9ipLdkkay4mxzJJH0,3765
31
31
  cognite/extractorutils/unstable/core/restart_policy.py,sha256=4FUohTXeC74mnq36Q16PQ2i9jPI-WuUZm8XwClFSnYk,631
32
- cognite/extractorutils/unstable/core/runtime.py,sha256=vz9gE05u4UMn8QkGhc6ooPLo7ZTkGZGBzWY9kl0L2gk,9779
32
+ cognite/extractorutils/unstable/core/runtime.py,sha256=RdRRBplPyHxyM6xujAl1e3phjbUA3Fk18x-pPFQB6e0,11067
33
33
  cognite/extractorutils/unstable/core/tasks.py,sha256=XvakIwp_zCV7XaWUgYT2z3LCGoQTljY0xdVJWFfm-ng,3158
34
34
  cognite/extractorutils/unstable/scheduling/__init__.py,sha256=L90_rCZNHvti-PInne0r7W9edIkifctELjiaxEoQiSc,67
35
35
  cognite/extractorutils/unstable/scheduling/_scheduler.py,sha256=jxr5gICz0nrLFr7PfplEWi1nrO5uW1NS-F9CH9v3eHs,3721
@@ -44,7 +44,7 @@ cognite/extractorutils/uploader/files.py,sha256=ag3TUrImJdAUiOSXugagD03-9WGlFpIy
44
44
  cognite/extractorutils/uploader/raw.py,sha256=8duMk9uVJPK3O6C0nzwnvrl0UzBtJs_T_L1la0Vo89k,6713
45
45
  cognite/extractorutils/uploader/time_series.py,sha256=3HaKfWcSOTKFmB6VwpRwioOykkRa6qmruSSsZu8Njdk,26507
46
46
  cognite/extractorutils/uploader/upload_failure_handler.py,sha256=wbUSXUP26rbmK2NGdQMzcWQwNOh2sXYOnlj0A_sk1n8,2003
47
- cognite_extractor_utils-7.5.13.dist-info/METADATA,sha256=D2QVuO8G8mEmQ9tPMzhs062j4N8F4vkLQ3kPL3DWO4I,4889
48
- cognite_extractor_utils-7.5.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
- cognite_extractor_utils-7.5.13.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
50
- cognite_extractor_utils-7.5.13.dist-info/RECORD,,
47
+ cognite_extractor_utils-7.5.14.dist-info/METADATA,sha256=fOEVjTfL3MwM-AYOc64C0pVx4yaay5mvyXLcqLiTEFI,4889
48
+ cognite_extractor_utils-7.5.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
+ cognite_extractor_utils-7.5.14.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
50
+ cognite_extractor_utils-7.5.14.dist-info/RECORD,,