cognite-extractor-utils 7.5.13__py3-none-any.whl → 7.6.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.
Potentially problematic release.
This version of cognite-extractor-utils might be problematic. Click here for more details.
- cognite/extractorutils/__init__.py +1 -1
- cognite/extractorutils/_inner_util.py +1 -1
- cognite/extractorutils/base.py +120 -40
- cognite/extractorutils/configtools/__init__.py +4 -5
- cognite/extractorutils/configtools/_util.py +3 -2
- cognite/extractorutils/configtools/elements.py +213 -35
- cognite/extractorutils/configtools/loaders.py +68 -16
- cognite/extractorutils/configtools/validators.py +5 -1
- cognite/extractorutils/exceptions.py +11 -2
- cognite/extractorutils/metrics.py +17 -12
- cognite/extractorutils/statestore/__init__.py +77 -3
- cognite/extractorutils/statestore/_base.py +7 -3
- cognite/extractorutils/statestore/hashing.py +129 -15
- cognite/extractorutils/statestore/watermark.py +77 -87
- cognite/extractorutils/threading.py +30 -4
- cognite/extractorutils/unstable/__init__.py +5 -5
- cognite/extractorutils/unstable/configuration/__init__.py +3 -0
- cognite/extractorutils/unstable/configuration/exceptions.py +13 -2
- cognite/extractorutils/unstable/configuration/loaders.py +90 -19
- cognite/extractorutils/unstable/configuration/models.py +121 -7
- cognite/extractorutils/unstable/core/__init__.py +5 -0
- cognite/extractorutils/unstable/core/_dto.py +5 -3
- cognite/extractorutils/unstable/core/base.py +113 -4
- cognite/extractorutils/unstable/core/errors.py +41 -0
- cognite/extractorutils/unstable/core/logger.py +149 -0
- cognite/extractorutils/unstable/core/restart_policy.py +16 -2
- cognite/extractorutils/unstable/core/runtime.py +119 -36
- cognite/extractorutils/unstable/core/tasks.py +53 -1
- cognite/extractorutils/unstable/scheduling/__init__.py +13 -0
- cognite/extractorutils/unstable/scheduling/_scheduler.py +1 -1
- cognite/extractorutils/uploader/__init__.py +7 -5
- cognite/extractorutils/uploader/_base.py +4 -5
- cognite/extractorutils/uploader/assets.py +13 -8
- cognite/extractorutils/uploader/data_modeling.py +37 -2
- cognite/extractorutils/uploader/events.py +14 -9
- cognite/extractorutils/uploader/files.py +80 -21
- cognite/extractorutils/uploader/raw.py +12 -7
- cognite/extractorutils/uploader/time_series.py +58 -49
- cognite/extractorutils/uploader/upload_failure_handler.py +35 -2
- cognite/extractorutils/uploader_extractor.py +29 -6
- cognite/extractorutils/uploader_types.py +15 -1
- cognite/extractorutils/util.py +76 -23
- {cognite_extractor_utils-7.5.13.dist-info → cognite_extractor_utils-7.6.0.dist-info}/METADATA +1 -1
- cognite_extractor_utils-7.6.0.dist-info/RECORD +50 -0
- cognite_extractor_utils-7.5.13.dist-info/RECORD +0 -50
- {cognite_extractor_utils-7.5.13.dist-info → cognite_extractor_utils-7.6.0.dist-info}/WHEEL +0 -0
- {cognite_extractor_utils-7.5.13.dist-info → cognite_extractor_utils-7.6.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module containing pre-built elements for common extractor configuration.
|
|
3
|
+
"""
|
|
4
|
+
|
|
1
5
|
# Copyright 2023 Cognite AS
|
|
2
6
|
#
|
|
3
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -18,6 +22,7 @@ from dataclasses import dataclass, field
|
|
|
18
22
|
from datetime import timedelta
|
|
19
23
|
from enum import Enum
|
|
20
24
|
from logging.handlers import TimedRotatingFileHandler
|
|
25
|
+
from pathlib import Path
|
|
21
26
|
from time import sleep
|
|
22
27
|
from typing import Any
|
|
23
28
|
from urllib.parse import urljoin, urlparse
|
|
@@ -55,7 +60,7 @@ _logger = logging.getLogger(__name__)
|
|
|
55
60
|
@dataclass
|
|
56
61
|
class CertificateConfig:
|
|
57
62
|
"""
|
|
58
|
-
Configuration parameters for certificates
|
|
63
|
+
Configuration parameters for certificates.
|
|
59
64
|
"""
|
|
60
65
|
|
|
61
66
|
path: str
|
|
@@ -66,7 +71,7 @@ class CertificateConfig:
|
|
|
66
71
|
@dataclass
|
|
67
72
|
class AuthenticatorConfig:
|
|
68
73
|
"""
|
|
69
|
-
Configuration parameters for an OIDC flow
|
|
74
|
+
Configuration parameters for an OIDC flow.
|
|
70
75
|
"""
|
|
71
76
|
|
|
72
77
|
client_id: str
|
|
@@ -84,7 +89,7 @@ class AuthenticatorConfig:
|
|
|
84
89
|
@dataclass
|
|
85
90
|
class ConnectionConfig:
|
|
86
91
|
"""
|
|
87
|
-
Configuration parameters for the global_config python SDK settings
|
|
92
|
+
Configuration parameters for the global_config python SDK settings.
|
|
88
93
|
"""
|
|
89
94
|
|
|
90
95
|
disable_gzip: bool = False
|
|
@@ -101,6 +106,7 @@ class ConnectionConfig:
|
|
|
101
106
|
class EitherIdConfig:
|
|
102
107
|
"""
|
|
103
108
|
Configuration parameter representing an ID in CDF, which can either be an external or internal ID.
|
|
109
|
+
|
|
104
110
|
An EitherId can only hold one ID type, not both.
|
|
105
111
|
"""
|
|
106
112
|
|
|
@@ -109,23 +115,35 @@ class EitherIdConfig:
|
|
|
109
115
|
|
|
110
116
|
@property
|
|
111
117
|
def either_id(self) -> EitherId:
|
|
118
|
+
"""
|
|
119
|
+
Returns an EitherId object based on the current configuration.
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
TypeError: If both id and external_id are None, or if both are set.
|
|
123
|
+
"""
|
|
112
124
|
return EitherId(id=self.id, external_id=self.external_id)
|
|
113
125
|
|
|
114
126
|
|
|
115
127
|
class TimeIntervalConfig(yaml.YAMLObject):
|
|
116
128
|
"""
|
|
117
|
-
Configuration parameter for setting a time interval
|
|
129
|
+
Configuration parameter for setting a time interval.
|
|
118
130
|
"""
|
|
119
131
|
|
|
120
132
|
def __init__(self, expression: str) -> None:
|
|
121
133
|
self._interval, self._expression = TimeIntervalConfig._parse_expression(expression)
|
|
122
134
|
|
|
123
135
|
def __eq__(self, other: object) -> bool:
|
|
136
|
+
"""
|
|
137
|
+
Two TimeIntervalConfig objects are equal if they have the same number of seconds in their interval.
|
|
138
|
+
"""
|
|
124
139
|
if not isinstance(other, TimeIntervalConfig):
|
|
125
140
|
return NotImplemented
|
|
126
141
|
return self._interval == other._interval
|
|
127
142
|
|
|
128
143
|
def __hash__(self) -> int:
|
|
144
|
+
"""
|
|
145
|
+
Hash function for TimeIntervalConfig based on the number of seconds in the interval.
|
|
146
|
+
"""
|
|
129
147
|
return hash(self._interval)
|
|
130
148
|
|
|
131
149
|
@classmethod
|
|
@@ -147,42 +165,75 @@ class TimeIntervalConfig(yaml.YAMLObject):
|
|
|
147
165
|
|
|
148
166
|
@property
|
|
149
167
|
def seconds(self) -> int:
|
|
168
|
+
"""
|
|
169
|
+
Time interval as number of seconds.
|
|
170
|
+
"""
|
|
150
171
|
return self._interval
|
|
151
172
|
|
|
152
173
|
@property
|
|
153
174
|
def minutes(self) -> float:
|
|
175
|
+
"""
|
|
176
|
+
Time interval as number of minutes.
|
|
177
|
+
|
|
178
|
+
This is a float since the underlying interval is in seconds.
|
|
179
|
+
"""
|
|
154
180
|
return self._interval / 60
|
|
155
181
|
|
|
156
182
|
@property
|
|
157
183
|
def hours(self) -> float:
|
|
184
|
+
"""
|
|
185
|
+
Time interval as number of hours.
|
|
186
|
+
|
|
187
|
+
This is a float since the underlying interval is in seconds.
|
|
188
|
+
"""
|
|
158
189
|
return self._interval / (60 * 60)
|
|
159
190
|
|
|
160
191
|
@property
|
|
161
192
|
def days(self) -> float:
|
|
193
|
+
"""
|
|
194
|
+
Time interval as number of days.
|
|
195
|
+
|
|
196
|
+
This is a float since the underlying interval is in seconds.
|
|
197
|
+
"""
|
|
162
198
|
return self._interval / (60 * 60 * 24)
|
|
163
199
|
|
|
164
200
|
@property
|
|
165
201
|
def timedelta(self) -> timedelta:
|
|
202
|
+
"""
|
|
203
|
+
Time interval as a timedelta object.
|
|
204
|
+
"""
|
|
166
205
|
days = self._interval // (60 * 60 * 24)
|
|
167
206
|
seconds = self._interval % (60 * 60 * 24)
|
|
168
207
|
return timedelta(days=days, seconds=seconds)
|
|
169
208
|
|
|
170
209
|
def __int__(self) -> int:
|
|
210
|
+
"""
|
|
211
|
+
Returns the time interval as a number of seconds.
|
|
212
|
+
"""
|
|
171
213
|
return int(self._interval)
|
|
172
214
|
|
|
173
215
|
def __float__(self) -> float:
|
|
216
|
+
"""
|
|
217
|
+
Returns the time interval as a number of seconds.
|
|
218
|
+
"""
|
|
174
219
|
return float(self._interval)
|
|
175
220
|
|
|
176
221
|
def __str__(self) -> str:
|
|
222
|
+
"""
|
|
223
|
+
Returns the time interval as a human readable string.
|
|
224
|
+
"""
|
|
177
225
|
return self._expression
|
|
178
226
|
|
|
179
227
|
def __repr__(self) -> str:
|
|
228
|
+
"""
|
|
229
|
+
Returns the time interval as a human readable string.
|
|
230
|
+
"""
|
|
180
231
|
return self._expression
|
|
181
232
|
|
|
182
233
|
|
|
183
234
|
class FileSizeConfig(yaml.YAMLObject):
|
|
184
235
|
"""
|
|
185
|
-
Configuration parameter for setting a file size
|
|
236
|
+
Configuration parameter for setting a file size.
|
|
186
237
|
"""
|
|
187
238
|
|
|
188
239
|
def __init__(self, expression: str) -> None:
|
|
@@ -218,50 +269,89 @@ class FileSizeConfig(yaml.YAMLObject):
|
|
|
218
269
|
|
|
219
270
|
@property
|
|
220
271
|
def bytes(self) -> int:
|
|
272
|
+
"""
|
|
273
|
+
File size in bytes.
|
|
274
|
+
"""
|
|
221
275
|
return self._bytes
|
|
222
276
|
|
|
223
277
|
@property
|
|
224
278
|
def kilobytes(self) -> float:
|
|
279
|
+
"""
|
|
280
|
+
File size in kilobytes.
|
|
281
|
+
"""
|
|
225
282
|
return self._bytes / 1000
|
|
226
283
|
|
|
227
284
|
@property
|
|
228
285
|
def megabytes(self) -> float:
|
|
286
|
+
"""
|
|
287
|
+
File size in megabytes.
|
|
288
|
+
"""
|
|
229
289
|
return self._bytes / 1_000_000
|
|
230
290
|
|
|
231
291
|
@property
|
|
232
292
|
def gigabytes(self) -> float:
|
|
293
|
+
"""
|
|
294
|
+
File size in gigabytes.
|
|
295
|
+
"""
|
|
233
296
|
return self._bytes / 1_000_000_000
|
|
234
297
|
|
|
235
298
|
@property
|
|
236
299
|
def terabytes(self) -> float:
|
|
300
|
+
"""
|
|
301
|
+
File size in terabytes.
|
|
302
|
+
"""
|
|
237
303
|
return self._bytes / 1_000_000_000_000
|
|
238
304
|
|
|
239
305
|
@property
|
|
240
306
|
def kibibytes(self) -> float:
|
|
307
|
+
"""
|
|
308
|
+
File size in kibibytes (1024 bytes).
|
|
309
|
+
"""
|
|
241
310
|
return self._bytes / 1024
|
|
242
311
|
|
|
243
312
|
@property
|
|
244
313
|
def mebibytes(self) -> float:
|
|
314
|
+
"""
|
|
315
|
+
File size in mebibytes (1024 kibibytes).
|
|
316
|
+
"""
|
|
245
317
|
return self._bytes / 1_048_576
|
|
246
318
|
|
|
247
319
|
@property
|
|
248
320
|
def gibibytes(self) -> float:
|
|
321
|
+
"""
|
|
322
|
+
File size in gibibytes (1024 mebibytes).
|
|
323
|
+
"""
|
|
249
324
|
return self._bytes / 1_073_741_824
|
|
250
325
|
|
|
251
326
|
@property
|
|
252
327
|
def tebibytes(self) -> float:
|
|
328
|
+
"""
|
|
329
|
+
File size in tebibytes (1024 gibibytes).
|
|
330
|
+
"""
|
|
253
331
|
return self._bytes / 1_099_511_627_776
|
|
254
332
|
|
|
255
333
|
def __int__(self) -> int:
|
|
334
|
+
"""
|
|
335
|
+
Returns the file size as bytes.
|
|
336
|
+
"""
|
|
256
337
|
return int(self._bytes)
|
|
257
338
|
|
|
258
339
|
def __float__(self) -> float:
|
|
340
|
+
"""
|
|
341
|
+
Returns the file size as bytes.
|
|
342
|
+
"""
|
|
259
343
|
return float(self._bytes)
|
|
260
344
|
|
|
261
345
|
def __str__(self) -> str:
|
|
346
|
+
"""
|
|
347
|
+
Returns the file size as a human readable string.
|
|
348
|
+
"""
|
|
262
349
|
return self._expression
|
|
263
350
|
|
|
264
351
|
def __repr__(self) -> str:
|
|
352
|
+
"""
|
|
353
|
+
Returns the file size as a human readable string.
|
|
354
|
+
"""
|
|
265
355
|
return self._expression
|
|
266
356
|
|
|
267
357
|
|
|
@@ -280,7 +370,7 @@ def _validate_https_url(value: str, name: str) -> None:
|
|
|
280
370
|
@dataclass
|
|
281
371
|
class CogniteConfig:
|
|
282
372
|
"""
|
|
283
|
-
Configuration parameters for CDF connection, such as project name, host address and authentication
|
|
373
|
+
Configuration parameters for CDF connection, such as project name, host address and authentication.
|
|
284
374
|
"""
|
|
285
375
|
|
|
286
376
|
project: str
|
|
@@ -289,7 +379,7 @@ class CogniteConfig:
|
|
|
289
379
|
data_set_id: int | None = None
|
|
290
380
|
data_set_external_id: str | None = None
|
|
291
381
|
extraction_pipeline: EitherIdConfig | None = None
|
|
292
|
-
timeout: TimeIntervalConfig = TimeIntervalConfig("30s")
|
|
382
|
+
timeout: TimeIntervalConfig = field(default_factory=lambda: TimeIntervalConfig("30s"))
|
|
293
383
|
connection: ConnectionConfig = field(default_factory=ConnectionConfig)
|
|
294
384
|
security_categories: list[int] | None = None
|
|
295
385
|
external_id_prefix: str = ""
|
|
@@ -301,6 +391,20 @@ class CogniteConfig:
|
|
|
301
391
|
token_custom_args: dict[str, str] | None = None,
|
|
302
392
|
use_experimental_sdk: bool = False,
|
|
303
393
|
) -> CogniteClient:
|
|
394
|
+
"""
|
|
395
|
+
Creates a CogniteClient based on the configuration.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
client_name: Name of the client, set as the x-cdp-app header in the requests.
|
|
399
|
+
token_custom_args: Additional arguments to pass to the token request, such as resource or audience.
|
|
400
|
+
use_experimental_sdk: If True, use the experimental SDK instead of the stable one.
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
A CogniteClient instance configured with the provided parameters.
|
|
404
|
+
|
|
405
|
+
Raises:
|
|
406
|
+
InvalidConfigError: If the configuration is invalid, such as missing project name or invalid authority URL.
|
|
407
|
+
"""
|
|
304
408
|
from cognite.client.config import global_config
|
|
305
409
|
|
|
306
410
|
global_config.disable_pypi_version_check = True
|
|
@@ -389,6 +493,15 @@ class CogniteConfig:
|
|
|
389
493
|
return CogniteClient(client_config)
|
|
390
494
|
|
|
391
495
|
def get_data_set(self, cdf_client: CogniteClient) -> DataSet | None:
|
|
496
|
+
"""
|
|
497
|
+
Retrieves the DataSet object based on the configuration.
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
cdf_client: An instance of CogniteClient to use for retrieving the DataSet.
|
|
501
|
+
|
|
502
|
+
Returns:
|
|
503
|
+
DataSet object if data_set, data_set_id, or data_set_external_id is provided; otherwise None.
|
|
504
|
+
"""
|
|
392
505
|
if self.data_set_external_id:
|
|
393
506
|
logging.getLogger(__name__).warning(
|
|
394
507
|
"Using data-set-external-id is deprecated, please use data-set/external-id instead"
|
|
@@ -408,6 +521,18 @@ class CogniteConfig:
|
|
|
408
521
|
)
|
|
409
522
|
|
|
410
523
|
def get_extraction_pipeline(self, cdf_client: CogniteClient) -> ExtractionPipeline | None:
|
|
524
|
+
"""
|
|
525
|
+
Retrieves the ExtractionPipeline object based on the configuration.
|
|
526
|
+
|
|
527
|
+
Args:
|
|
528
|
+
cdf_client: An instance of CogniteClient to use for retrieving the ExtractionPipeline.
|
|
529
|
+
|
|
530
|
+
Returns:
|
|
531
|
+
ExtractionPipeline object if extraction_pipeline is provided, otherwise None.
|
|
532
|
+
|
|
533
|
+
Raises:
|
|
534
|
+
ValueError: If the extraction pipeline with the specified ID is not found.
|
|
535
|
+
"""
|
|
411
536
|
if not self.extraction_pipeline:
|
|
412
537
|
return None
|
|
413
538
|
|
|
@@ -436,7 +561,7 @@ class _FileLoggingConfig:
|
|
|
436
561
|
@dataclass
|
|
437
562
|
class LoggingConfig:
|
|
438
563
|
"""
|
|
439
|
-
Logging settings, such as log levels and path to log file
|
|
564
|
+
Logging settings, such as log levels and path to log file.
|
|
440
565
|
"""
|
|
441
566
|
|
|
442
567
|
console: _ConsoleLoggingConfig | None
|
|
@@ -448,7 +573,7 @@ class LoggingConfig:
|
|
|
448
573
|
|
|
449
574
|
def setup_logging(self, suppress_console: bool = False) -> None:
|
|
450
575
|
"""
|
|
451
|
-
Sets up the default logger in the logging package to be configured as defined in this config object
|
|
576
|
+
Sets up the default logger in the logging package to be configured as defined in this config object.
|
|
452
577
|
|
|
453
578
|
Args:
|
|
454
579
|
suppress_console: Don't log to console regardless of config. Useful when running an extractor as a Windows
|
|
@@ -509,9 +634,10 @@ class _PushGatewayConfig:
|
|
|
509
634
|
password: str | None
|
|
510
635
|
|
|
511
636
|
clear_after: TimeIntervalConfig | None
|
|
512
|
-
push_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
|
|
637
|
+
push_interval: TimeIntervalConfig = field(default_factory=lambda: TimeIntervalConfig("30s"))
|
|
513
638
|
|
|
514
639
|
|
|
640
|
+
@dataclass
|
|
515
641
|
class _PromServerConfig:
|
|
516
642
|
port: int = 9000
|
|
517
643
|
host: str = "0.0.0.0"
|
|
@@ -524,14 +650,15 @@ class _CogniteMetricsConfig:
|
|
|
524
650
|
asset_external_id: str | None
|
|
525
651
|
data_set: EitherIdConfig | None = None
|
|
526
652
|
|
|
527
|
-
push_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
|
|
653
|
+
push_interval: TimeIntervalConfig = field(default_factory=lambda: TimeIntervalConfig("30s"))
|
|
528
654
|
|
|
529
655
|
|
|
530
656
|
@dataclass
|
|
531
657
|
class MetricsConfig:
|
|
532
658
|
"""
|
|
533
|
-
Destination(s) for metrics
|
|
534
|
-
|
|
659
|
+
Destination(s) for metrics.
|
|
660
|
+
|
|
661
|
+
Including options for one or several Prometheus push gateways, and pushing as CDF Time Series.
|
|
535
662
|
"""
|
|
536
663
|
|
|
537
664
|
push_gateways: list[_PushGatewayConfig] | None
|
|
@@ -539,6 +666,13 @@ class MetricsConfig:
|
|
|
539
666
|
server: _PromServerConfig | None
|
|
540
667
|
|
|
541
668
|
def start_pushers(self, cdf_client: CogniteClient, cancellation_token: CancellationToken | None = None) -> None:
|
|
669
|
+
"""
|
|
670
|
+
Starts the configured metrics pushers.
|
|
671
|
+
|
|
672
|
+
Args:
|
|
673
|
+
cdf_client: An instance of CogniteClient to use for pushing metrics to CDF.
|
|
674
|
+
cancellation_token: Optional cancellation token to stop the pushers gracefully.
|
|
675
|
+
"""
|
|
542
676
|
self._pushers: list[AbstractMetricsPusher] = []
|
|
543
677
|
self._clear_on_stop: dict[PrometheusPusher, int] = {}
|
|
544
678
|
|
|
@@ -587,6 +721,11 @@ class MetricsConfig:
|
|
|
587
721
|
start_http_server(self.server.port, self.server.host, registry=REGISTRY)
|
|
588
722
|
|
|
589
723
|
def stop_pushers(self) -> None:
|
|
724
|
+
"""
|
|
725
|
+
DEPRECATED. Use cancellation_token to stop pushers instead.
|
|
726
|
+
|
|
727
|
+
Manually stop pushers and clear gateways if configured.
|
|
728
|
+
"""
|
|
590
729
|
pushers = self.__dict__.get("_pushers") or []
|
|
591
730
|
|
|
592
731
|
for pusher in pushers:
|
|
@@ -597,11 +736,15 @@ class MetricsConfig:
|
|
|
597
736
|
_logger.debug("Waiting %d seconds before clearing gateways", wait_time)
|
|
598
737
|
|
|
599
738
|
sleep(wait_time)
|
|
600
|
-
for pusher in self._clear_on_stop
|
|
739
|
+
for pusher in self._clear_on_stop:
|
|
601
740
|
pusher.clear_gateway()
|
|
602
741
|
|
|
603
742
|
|
|
604
743
|
class ConfigType(Enum):
|
|
744
|
+
"""
|
|
745
|
+
Type of configuration, either local or remote.
|
|
746
|
+
"""
|
|
747
|
+
|
|
605
748
|
LOCAL = "local"
|
|
606
749
|
REMOTE = "remote"
|
|
607
750
|
|
|
@@ -617,7 +760,7 @@ class _BaseConfig:
|
|
|
617
760
|
@dataclass
|
|
618
761
|
class BaseConfig(_BaseConfig):
|
|
619
762
|
"""
|
|
620
|
-
Basis for an extractor config, containing config version, ``CogniteConfig`` and ``LoggingConfig
|
|
763
|
+
Basis for an extractor config, containing config version, ``CogniteConfig`` and ``LoggingConfig``.
|
|
621
764
|
"""
|
|
622
765
|
|
|
623
766
|
version: str | int | None
|
|
@@ -627,7 +770,7 @@ class BaseConfig(_BaseConfig):
|
|
|
627
770
|
@dataclass
|
|
628
771
|
class RawDestinationConfig:
|
|
629
772
|
"""
|
|
630
|
-
Configuration parameters for using Raw
|
|
773
|
+
Configuration parameters for using Raw.
|
|
631
774
|
"""
|
|
632
775
|
|
|
633
776
|
database: str
|
|
@@ -637,26 +780,26 @@ class RawDestinationConfig:
|
|
|
637
780
|
@dataclass
|
|
638
781
|
class RawStateStoreConfig(RawDestinationConfig):
|
|
639
782
|
"""
|
|
640
|
-
Configuration of a state store based on CDF RAW
|
|
783
|
+
Configuration of a state store based on CDF RAW.
|
|
641
784
|
"""
|
|
642
785
|
|
|
643
|
-
upload_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
|
|
786
|
+
upload_interval: TimeIntervalConfig = field(default_factory=lambda: TimeIntervalConfig("30s"))
|
|
644
787
|
|
|
645
788
|
|
|
646
789
|
@dataclass
|
|
647
790
|
class LocalStateStoreConfig:
|
|
648
791
|
"""
|
|
649
|
-
Configuration of a state store using a local JSON file
|
|
792
|
+
Configuration of a state store using a local JSON file.
|
|
650
793
|
"""
|
|
651
794
|
|
|
652
|
-
path:
|
|
653
|
-
save_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
|
|
795
|
+
path: Path
|
|
796
|
+
save_interval: TimeIntervalConfig = field(default_factory=lambda: TimeIntervalConfig("30s"))
|
|
654
797
|
|
|
655
798
|
|
|
656
799
|
@dataclass
|
|
657
800
|
class StateStoreConfig:
|
|
658
801
|
"""
|
|
659
|
-
Configuration of the State Store, containing ``LocalStateStoreConfig`` or ``RawStateStoreConfig
|
|
802
|
+
Configuration of the State Store, containing ``LocalStateStoreConfig`` or ``RawStateStoreConfig``.
|
|
660
803
|
"""
|
|
661
804
|
|
|
662
805
|
raw: RawStateStoreConfig | None = None
|
|
@@ -675,6 +818,7 @@ class StateStoreConfig:
|
|
|
675
818
|
cdf_client: CogniteClient object to use in case of a RAW state store (ignored otherwise)
|
|
676
819
|
default_to_local: If true, return a LocalStateStore if no state store is configured. Otherwise return a
|
|
677
820
|
NoStateStore
|
|
821
|
+
cancellation_token: Cancellation token to pass to created state stores
|
|
678
822
|
|
|
679
823
|
Returns:
|
|
680
824
|
An (uninitialized) state store
|
|
@@ -695,8 +839,11 @@ class StateStoreConfig:
|
|
|
695
839
|
)
|
|
696
840
|
|
|
697
841
|
if self.local:
|
|
842
|
+
if self.local.path.is_dir():
|
|
843
|
+
raise ValueError(f"{self.local.path} is a directory, and not a file")
|
|
844
|
+
|
|
698
845
|
return LocalStateStore(
|
|
699
|
-
file_path=self.local.path,
|
|
846
|
+
file_path=str(self.local.path),
|
|
700
847
|
save_interval=self.local.save_interval.seconds,
|
|
701
848
|
cancellation_token=cancellation_token,
|
|
702
849
|
)
|
|
@@ -708,12 +855,22 @@ class StateStoreConfig:
|
|
|
708
855
|
|
|
709
856
|
|
|
710
857
|
class RegExpFlag(Enum):
|
|
858
|
+
"""
|
|
859
|
+
Flags for regular expressions.
|
|
860
|
+
"""
|
|
861
|
+
|
|
711
862
|
IGNORECASE = "ignore-case"
|
|
712
863
|
IC = "i"
|
|
713
864
|
ASCII = "ascii-only"
|
|
714
865
|
A = "a"
|
|
715
866
|
|
|
716
867
|
def get_regex_flag(self) -> int:
|
|
868
|
+
"""
|
|
869
|
+
Returns the corresponding regex flag for the enum value.
|
|
870
|
+
|
|
871
|
+
Returns:
|
|
872
|
+
The regex flag corresponding to the enum value.
|
|
873
|
+
"""
|
|
717
874
|
if self in (RegExpFlag.IGNORECASE, RegExpFlag.IC):
|
|
718
875
|
return re.IGNORECASE
|
|
719
876
|
elif self.value in (RegExpFlag.ASCII, RegExpFlag.A):
|
|
@@ -724,7 +881,7 @@ class RegExpFlag(Enum):
|
|
|
724
881
|
@dataclass
|
|
725
882
|
class IgnorePattern:
|
|
726
883
|
"""
|
|
727
|
-
Configuration for regexp for ignore pattern
|
|
884
|
+
Configuration for regexp for ignore pattern.
|
|
728
885
|
"""
|
|
729
886
|
|
|
730
887
|
pattern: str
|
|
@@ -744,6 +901,12 @@ class IgnorePattern:
|
|
|
744
901
|
return re.compile(self.pattern, flag)
|
|
745
902
|
|
|
746
903
|
def __post_init__(self) -> None:
|
|
904
|
+
"""
|
|
905
|
+
Validate the configuration after initialization.
|
|
906
|
+
|
|
907
|
+
Raises:
|
|
908
|
+
ValueError: If both 'options' and 'flags' are specified, or if neither is specified.
|
|
909
|
+
"""
|
|
747
910
|
if self.options is not None and self.flags is not None:
|
|
748
911
|
raise ValueError("Only one of either 'options' or 'flags' can be specified.")
|
|
749
912
|
if self.options is None and self.flags is None:
|
|
@@ -757,19 +920,27 @@ class IgnorePattern:
|
|
|
757
920
|
|
|
758
921
|
class CastableInt(int):
|
|
759
922
|
"""
|
|
760
|
-
Represents an integer in a config schema.
|
|
761
|
-
|
|
923
|
+
Represents an integer in a config schema.
|
|
924
|
+
|
|
925
|
+
The difference from regular int is that the value if this type can be either a string or an integer in the yaml
|
|
926
|
+
file.
|
|
762
927
|
"""
|
|
763
928
|
|
|
764
929
|
def __new__(cls, value: Any) -> "CastableInt":
|
|
765
930
|
"""
|
|
766
|
-
Returns value as is if it's int.
|
|
767
|
-
Raises ValueError if conversion is unsuccessful or value is of not supported type.
|
|
931
|
+
Returns value as is if it's int.
|
|
768
932
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
933
|
+
If it's str or bytes try to convert to int.
|
|
934
|
+
|
|
935
|
+
Type check is required to avoid unexpected behavior, such as implicitly casting booleans, floats and other types
|
|
936
|
+
supported by standard int.
|
|
772
937
|
|
|
938
|
+
Args:
|
|
939
|
+
value: The value to be casted to int.
|
|
940
|
+
|
|
941
|
+
Raises:
|
|
942
|
+
ValueError: If the value can not be converted to an int.
|
|
943
|
+
"""
|
|
773
944
|
if not isinstance(value, int | str | bytes):
|
|
774
945
|
raise ValueError(f"CastableInt cannot be created form value {value!r} of type {type(value)!r}.")
|
|
775
946
|
|
|
@@ -778,14 +949,21 @@ class CastableInt(int):
|
|
|
778
949
|
|
|
779
950
|
class PortNumber(CastableInt):
|
|
780
951
|
"""
|
|
781
|
-
|
|
782
|
-
|
|
952
|
+
Represents a port number in a config schema.
|
|
953
|
+
|
|
954
|
+
It represents a valid port number (0 to 65535) and allows the value to be of either str or int type. If the value is
|
|
955
|
+
not a valid port number raises a ValueError at instantiation.
|
|
783
956
|
"""
|
|
784
957
|
|
|
785
958
|
def __new__(cls, value: Any) -> "PortNumber":
|
|
786
959
|
"""
|
|
787
|
-
Try to
|
|
788
|
-
|
|
960
|
+
Try to cast the value to an integer and validate it as a port number.
|
|
961
|
+
|
|
962
|
+
Args:
|
|
963
|
+
value: The value to be casted to a port number.
|
|
964
|
+
|
|
965
|
+
Raises:
|
|
966
|
+
ValueError: If the value is not a valid port number (not an int or out of range).
|
|
789
967
|
"""
|
|
790
968
|
value = super().__new__(cls, value)
|
|
791
969
|
|