cognite-extractor-utils 7.0.0__tar.gz → 7.0.2__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.
Potentially problematic release.
This version of cognite-extractor-utils might be problematic. Click here for more details.
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/PKG-INFO +1 -1
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/__init__.py +1 -1
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/configtools/__init__.py +6 -1
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/configtools/elements.py +33 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/configtools/loaders.py +4 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/exceptions.py +1 -1
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/threading.py +14 -3
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader/files.py +30 -17
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/util.py +14 -13
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/pyproject.toml +2 -2
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/LICENSE +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/README.md +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/_inner_util.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/base.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/configtools/_util.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/metrics.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/py.typed +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/statestore.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader/__init__.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader/_base.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader/_metrics.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader/assets.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader/events.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader/raw.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader/time_series.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader_extractor.py +0 -0
- {cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/uploader_types.py +0 -0
|
@@ -85,10 +85,15 @@ Get a state store object as configured:
|
|
|
85
85
|
However, all of these things will be automatically done for you if you are using the base Extractor class.
|
|
86
86
|
"""
|
|
87
87
|
|
|
88
|
+
from cognite.extractorutils.exceptions import InvalidConfigError
|
|
89
|
+
|
|
88
90
|
from .elements import (
|
|
91
|
+
AuthenticatorConfig,
|
|
89
92
|
BaseConfig,
|
|
93
|
+
CertificateConfig,
|
|
90
94
|
CogniteConfig,
|
|
91
95
|
ConfigType,
|
|
96
|
+
ConnectionConfig,
|
|
92
97
|
EitherIdConfig,
|
|
93
98
|
FileSizeConfig,
|
|
94
99
|
LocalStateStoreConfig,
|
|
@@ -99,4 +104,4 @@ from .elements import (
|
|
|
99
104
|
StateStoreConfig,
|
|
100
105
|
TimeIntervalConfig,
|
|
101
106
|
)
|
|
102
|
-
from .loaders import ConfigResolver, load_yaml
|
|
107
|
+
from .loaders import ConfigResolver, KeyVaultAuthenticationMethod, KeyVaultLoader, load_yaml, load_yaml_dict
|
|
@@ -53,6 +53,10 @@ _logger = logging.getLogger(__name__)
|
|
|
53
53
|
|
|
54
54
|
@dataclass
|
|
55
55
|
class CertificateConfig:
|
|
56
|
+
"""
|
|
57
|
+
Configuration parameters for certificates
|
|
58
|
+
"""
|
|
59
|
+
|
|
56
60
|
path: str
|
|
57
61
|
password: Optional[str]
|
|
58
62
|
authority_url: Optional[str] = None
|
|
@@ -94,6 +98,11 @@ class ConnectionConfig:
|
|
|
94
98
|
|
|
95
99
|
@dataclass
|
|
96
100
|
class EitherIdConfig:
|
|
101
|
+
"""
|
|
102
|
+
Configuration parameter representing an ID in CDF, which can either be an external or internal ID.
|
|
103
|
+
An EitherId can only hold one ID type, not both.
|
|
104
|
+
"""
|
|
105
|
+
|
|
97
106
|
id: Optional[int]
|
|
98
107
|
external_id: Optional[str]
|
|
99
108
|
|
|
@@ -103,6 +112,10 @@ class EitherIdConfig:
|
|
|
103
112
|
|
|
104
113
|
|
|
105
114
|
class TimeIntervalConfig(yaml.YAMLObject):
|
|
115
|
+
"""
|
|
116
|
+
Configuration parameter for setting a time interval
|
|
117
|
+
"""
|
|
118
|
+
|
|
106
119
|
def __init__(self, expression: str) -> None:
|
|
107
120
|
self._interval, self._expression = TimeIntervalConfig._parse_expression(expression)
|
|
108
121
|
|
|
@@ -167,6 +180,10 @@ class TimeIntervalConfig(yaml.YAMLObject):
|
|
|
167
180
|
|
|
168
181
|
|
|
169
182
|
class FileSizeConfig(yaml.YAMLObject):
|
|
183
|
+
"""
|
|
184
|
+
Configuration parameter for setting a file size
|
|
185
|
+
"""
|
|
186
|
+
|
|
170
187
|
def __init__(self, expression: str) -> None:
|
|
171
188
|
self._bytes, self._expression = FileSizeConfig._parse_expression(expression)
|
|
172
189
|
|
|
@@ -569,23 +586,39 @@ class BaseConfig(_BaseConfig):
|
|
|
569
586
|
|
|
570
587
|
@dataclass
|
|
571
588
|
class RawDestinationConfig:
|
|
589
|
+
"""
|
|
590
|
+
Configuration parameters for using Raw
|
|
591
|
+
"""
|
|
592
|
+
|
|
572
593
|
database: str
|
|
573
594
|
table: str
|
|
574
595
|
|
|
575
596
|
|
|
576
597
|
@dataclass
|
|
577
598
|
class RawStateStoreConfig(RawDestinationConfig):
|
|
599
|
+
"""
|
|
600
|
+
Configuration of a state store based on CDF RAW
|
|
601
|
+
"""
|
|
602
|
+
|
|
578
603
|
upload_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
|
|
579
604
|
|
|
580
605
|
|
|
581
606
|
@dataclass
|
|
582
607
|
class LocalStateStoreConfig:
|
|
608
|
+
"""
|
|
609
|
+
Configuration of a state store using a local JSON file
|
|
610
|
+
"""
|
|
611
|
+
|
|
583
612
|
path: str
|
|
584
613
|
save_interval: TimeIntervalConfig = TimeIntervalConfig("30s")
|
|
585
614
|
|
|
586
615
|
|
|
587
616
|
@dataclass
|
|
588
617
|
class StateStoreConfig:
|
|
618
|
+
"""
|
|
619
|
+
Configuration of the State Store, containing ``LocalStateStoreConfig`` or ``RawStateStoreConfig``
|
|
620
|
+
"""
|
|
621
|
+
|
|
589
622
|
raw: Optional[RawStateStoreConfig] = None
|
|
590
623
|
local: Optional[LocalStateStoreConfig] = None
|
|
591
624
|
|
{cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/exceptions.py
RENAMED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
class InvalidConfigError(Exception):
|
|
17
17
|
"""
|
|
18
|
-
Exception thrown from ``load_yaml`` if config file is invalid. This can be due to
|
|
18
|
+
Exception thrown from ``load_yaml`` and ``load_yaml_dict`` if config file is invalid. This can be due to
|
|
19
19
|
|
|
20
20
|
* Missing fields
|
|
21
21
|
* Incompatible types
|
{cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/threading.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import signal
|
|
3
3
|
from threading import Condition
|
|
4
|
+
from time import time
|
|
4
5
|
from typing import Any, Optional
|
|
5
6
|
|
|
6
7
|
|
|
@@ -59,11 +60,21 @@ class CancellationToken:
|
|
|
59
60
|
self.cancel()
|
|
60
61
|
|
|
61
62
|
def wait(self, timeout: Optional[float] = None) -> bool:
|
|
63
|
+
endtime = None
|
|
64
|
+
if timeout is not None:
|
|
65
|
+
endtime = time() + timeout
|
|
66
|
+
|
|
62
67
|
while not self.is_cancelled:
|
|
63
68
|
with self._cv:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
if endtime is not None:
|
|
70
|
+
remaining_time = endtime - time()
|
|
71
|
+
if remaining_time <= 0.0:
|
|
72
|
+
return True
|
|
73
|
+
timed_out = not self._cv.wait(remaining_time)
|
|
74
|
+
if timed_out:
|
|
75
|
+
return False
|
|
76
|
+
else:
|
|
77
|
+
self._cv.wait()
|
|
67
78
|
return True
|
|
68
79
|
|
|
69
80
|
def create_child_token(self) -> "CancellationToken":
|
|
@@ -19,6 +19,8 @@ from os import PathLike
|
|
|
19
19
|
from types import TracebackType
|
|
20
20
|
from typing import Any, BinaryIO, Callable, Dict, List, Optional, Tuple, Type, Union
|
|
21
21
|
|
|
22
|
+
from requests.utils import super_len
|
|
23
|
+
|
|
22
24
|
from cognite.client import CogniteClient
|
|
23
25
|
from cognite.client.data_classes import FileMetadata
|
|
24
26
|
from cognite.extractorutils.threading import CancellationToken
|
|
@@ -154,23 +156,34 @@ class IOFileUploadQueue(AbstractUploadQueue):
|
|
|
154
156
|
try:
|
|
155
157
|
# Upload file
|
|
156
158
|
with read_file() as file:
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
159
|
+
size = super_len(file)
|
|
160
|
+
if size == 0:
|
|
161
|
+
# upload just the file metadata witout data
|
|
162
|
+
file_meta, _url = self.cdf_client.files.create(
|
|
163
|
+
file_metadata=file_meta, overwrite=self.overwrite_existing
|
|
164
|
+
)
|
|
165
|
+
elif size > pow(5, 9):
|
|
166
|
+
# File bigger than 5Gb
|
|
167
|
+
self.logger.warning(f"File {file_meta.source} has more than 5Gb")
|
|
168
|
+
file_meta = FileMetadata()
|
|
169
|
+
else:
|
|
170
|
+
file_meta = self.cdf_client.files.upload_bytes(
|
|
171
|
+
file,
|
|
172
|
+
file_meta.name if file_meta.name is not None else "",
|
|
173
|
+
overwrite=self.overwrite_existing,
|
|
174
|
+
external_id=file_meta.external_id,
|
|
175
|
+
source=file_meta.source,
|
|
176
|
+
mime_type=file_meta.mime_type,
|
|
177
|
+
metadata=file_meta.metadata,
|
|
178
|
+
directory=file_meta.directory,
|
|
179
|
+
asset_ids=file_meta.asset_ids,
|
|
180
|
+
data_set_id=file_meta.data_set_id,
|
|
181
|
+
labels=file_meta.labels,
|
|
182
|
+
geo_location=file_meta.geo_location,
|
|
183
|
+
source_created_time=file_meta.source_created_time,
|
|
184
|
+
source_modified_time=file_meta.source_modified_time,
|
|
185
|
+
security_categories=file_meta.security_categories,
|
|
186
|
+
)
|
|
174
187
|
|
|
175
188
|
if self.post_upload_function:
|
|
176
189
|
try:
|
{cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/util.py
RENAMED
|
@@ -79,7 +79,7 @@ class EitherId:
|
|
|
79
79
|
|
|
80
80
|
Args:
|
|
81
81
|
id: Internal ID
|
|
82
|
-
|
|
82
|
+
external_id: external ID. It can be `external_id` or `externalId`
|
|
83
83
|
|
|
84
84
|
Raises:
|
|
85
85
|
TypeError: If none of both of id types are set.
|
|
@@ -175,24 +175,25 @@ def add_extraction_pipeline(
|
|
|
175
175
|
added_message: str = "",
|
|
176
176
|
) -> Callable[[Callable[..., _T1]], Callable[..., _T1]]:
|
|
177
177
|
"""
|
|
178
|
-
This is to be used as a decorator for extractor functions to add extraction pipeline information
|
|
178
|
+
This is to be used as a decorator for extractor functions to add extraction pipeline information.
|
|
179
179
|
|
|
180
180
|
Args:
|
|
181
|
-
extraction_pipeline_ext_id:
|
|
182
|
-
cognite_client:
|
|
183
|
-
heartbeat_waiting_time:
|
|
184
|
-
added_message:
|
|
181
|
+
extraction_pipeline_ext_id: External ID of the extraction pipeline
|
|
182
|
+
cognite_client: Client to use when communicating with CDF
|
|
183
|
+
heartbeat_waiting_time: Target interval between heartbeats, in seconds
|
|
185
184
|
|
|
186
185
|
Usage:
|
|
187
186
|
If you have a function named "extract_data(*args, **kwargs)" and want to connect it to an extraction
|
|
188
187
|
pipeline, you can use this decorator function as:
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
188
|
+
|
|
189
|
+
.. code-block:: python
|
|
190
|
+
|
|
191
|
+
@add_extraction_pipeline(
|
|
192
|
+
extraction_pipeline_ext_id=<INSERT EXTERNAL ID>,
|
|
193
|
+
cognite_client=<INSERT COGNITE CLIENT OBJECT>,
|
|
194
|
+
)
|
|
195
|
+
def extract_data(*args, **kwargs):
|
|
196
|
+
<INSERT FUNCTION BODY>
|
|
196
197
|
"""
|
|
197
198
|
|
|
198
199
|
# TODO 1. Consider refactoring this decorator to share methods with the Extractor context manager in .base.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "cognite-extractor-utils"
|
|
3
|
-
version = "7.0.
|
|
3
|
+
version = "7.0.2"
|
|
4
4
|
description = "Utilities for easier development of extractors for CDF"
|
|
5
5
|
authors = ["Mathias Lohne <mathias.lohne@cognite.com>"]
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -81,7 +81,7 @@ pytest-order = "^1.0.1"
|
|
|
81
81
|
parameterized = "*"
|
|
82
82
|
requests = "^2.31.0"
|
|
83
83
|
types-requests = "^2.31.0.20240125"
|
|
84
|
-
httpx = "^0.
|
|
84
|
+
httpx = "^0.27.0"
|
|
85
85
|
|
|
86
86
|
[build-system]
|
|
87
87
|
requires = ["poetry-core>=1.0.0"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/base.py
RENAMED
|
File without changes
|
|
File without changes
|
{cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/metrics.py
RENAMED
|
File without changes
|
{cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/py.typed
RENAMED
|
File without changes
|
{cognite_extractor_utils-7.0.0 → cognite_extractor_utils-7.0.2}/cognite/extractorutils/statestore.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|