cognite-extractor-utils 7.4.3__tar.gz → 7.4.4__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.4.3 → cognite_extractor_utils-7.4.4}/PKG-INFO +4 -2
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/__init__.py +1 -1
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/exceptions.py +5 -1
- cognite_extractor_utils-7.4.4/cognite/extractorutils/unstable/configuration/__init__.py +0 -0
- cognite_extractor_utils-7.4.4/cognite/extractorutils/unstable/configuration/loaders.py +111 -0
- cognite_extractor_utils-7.4.4/cognite/extractorutils/unstable/configuration/models.py +159 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/pyproject.toml +4 -2
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/LICENSE +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/README.md +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/_inner_util.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/base.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/configtools/__init__.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/configtools/_util.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/configtools/elements.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/configtools/loaders.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/metrics.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/py.typed +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/statestore/__init__.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/statestore/_base.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/statestore/hashing.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/statestore/watermark.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/threading.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/unstable/__init__.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/__init__.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/_base.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/_metrics.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/assets.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/data_modeling.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/events.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/files.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/raw.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader/time_series.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader_extractor.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/uploader_types.py +0 -0
- {cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cognite-extractor-utils
|
|
3
|
-
Version: 7.4.
|
|
3
|
+
Version: 7.4.4
|
|
4
4
|
Summary: Utilities for easier development of extractors for CDF
|
|
5
5
|
Home-page: https://github.com/cognitedata/python-extractor-utils
|
|
6
6
|
License: Apache-2.0
|
|
@@ -17,7 +17,7 @@ Provides-Extra: experimental
|
|
|
17
17
|
Requires-Dist: arrow (>=1.0.0,<2.0.0)
|
|
18
18
|
Requires-Dist: azure-identity (>=1.14.0,<2.0.0)
|
|
19
19
|
Requires-Dist: azure-keyvault-secrets (>=4.7.0,<5.0.0)
|
|
20
|
-
Requires-Dist: cognite-sdk (>=7.
|
|
20
|
+
Requires-Dist: cognite-sdk (>=7.59.0,<8.0.0)
|
|
21
21
|
Requires-Dist: dacite (>=1.6.0,<2.0.0)
|
|
22
22
|
Requires-Dist: decorator (>=5.1.1,<6.0.0)
|
|
23
23
|
Requires-Dist: httpx (>=0.27.0,<0.28.0)
|
|
@@ -25,6 +25,8 @@ Requires-Dist: more-itertools (>=10.0.0,<11.0.0)
|
|
|
25
25
|
Requires-Dist: orjson (>=3.10.3,<4.0.0)
|
|
26
26
|
Requires-Dist: prometheus-client (>0.7.0,<=1.0.0)
|
|
27
27
|
Requires-Dist: psutil (>=6.0.0,<7.0.0)
|
|
28
|
+
Requires-Dist: pydantic (>=2.8.2,<3.0.0)
|
|
29
|
+
Requires-Dist: pyhumps (>=3.8.0,<4.0.0)
|
|
28
30
|
Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
|
|
29
31
|
Requires-Dist: pyyaml (>=5.3.0,<7)
|
|
30
32
|
Requires-Dist: typing-extensions (>=3.7.4,<5)
|
{cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/exceptions.py
RENAMED
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
from typing import List, Optional
|
|
17
|
+
|
|
18
|
+
|
|
16
19
|
class InvalidConfigError(Exception):
|
|
17
20
|
"""
|
|
18
21
|
Exception thrown from ``load_yaml`` and ``load_yaml_dict`` if config file is invalid. This can be due to
|
|
@@ -22,9 +25,10 @@ class InvalidConfigError(Exception):
|
|
|
22
25
|
* Unkown fields
|
|
23
26
|
"""
|
|
24
27
|
|
|
25
|
-
def __init__(self, message: str):
|
|
28
|
+
def __init__(self, message: str, details: Optional[List[str]] = None):
|
|
26
29
|
super(InvalidConfigError, self).__init__()
|
|
27
30
|
self.message = message
|
|
31
|
+
self.details = details
|
|
28
32
|
|
|
29
33
|
def __str__(self) -> str:
|
|
30
34
|
return f"Invalid config: {self.message}"
|
|
File without changes
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from io import StringIO
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict, Optional, TextIO, Type, TypeVar, Union
|
|
6
|
+
|
|
7
|
+
from pydantic import ValidationError
|
|
8
|
+
|
|
9
|
+
from cognite.client import CogniteClient
|
|
10
|
+
from cognite.extractorutils.configtools.loaders import _load_yaml_dict_raw
|
|
11
|
+
from cognite.extractorutils.exceptions import InvalidConfigError
|
|
12
|
+
from cognite.extractorutils.unstable.configuration.models import ConfigModel
|
|
13
|
+
|
|
14
|
+
_T = TypeVar("_T", bound=ConfigModel)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ConfigFormat(Enum):
|
|
18
|
+
JSON = "json"
|
|
19
|
+
YAML = "yaml"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_file(path: Path, schema: Type[_T]) -> _T:
|
|
23
|
+
if path.suffix in [".yaml", ".yml"]:
|
|
24
|
+
format = ConfigFormat.YAML
|
|
25
|
+
elif path.suffix == ".json":
|
|
26
|
+
format = ConfigFormat.JSON
|
|
27
|
+
else:
|
|
28
|
+
raise InvalidConfigError(f"Unknown file type {path.suffix}")
|
|
29
|
+
|
|
30
|
+
with open(path, "r") as stream:
|
|
31
|
+
return load_io(stream, format, schema)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def load_from_cdf(
|
|
35
|
+
cognite_client: CogniteClient, external_id: str, schema: Type[_T], revision: Optional[int] = None
|
|
36
|
+
) -> _T:
|
|
37
|
+
params: Dict[str, Union[str, int]] = {"externalId": external_id}
|
|
38
|
+
if revision:
|
|
39
|
+
params["revision"] = revision
|
|
40
|
+
response = cognite_client.get(
|
|
41
|
+
f"/api/v1/projects/{cognite_client.config.project}/odin/config",
|
|
42
|
+
params=params,
|
|
43
|
+
headers={"cdf-version": "alpha"},
|
|
44
|
+
)
|
|
45
|
+
response.raise_for_status()
|
|
46
|
+
data = response.json()
|
|
47
|
+
return load_io(StringIO(data["config"]), ConfigFormat.YAML, schema)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def load_io(stream: TextIO, format: ConfigFormat, schema: Type[_T]) -> _T:
|
|
51
|
+
if format == ConfigFormat.JSON:
|
|
52
|
+
data = json.load(stream)
|
|
53
|
+
|
|
54
|
+
elif format == ConfigFormat.YAML:
|
|
55
|
+
data = _load_yaml_dict_raw(stream)
|
|
56
|
+
|
|
57
|
+
if "azure-keyvault" in data:
|
|
58
|
+
data.pop("azure-keyvault")
|
|
59
|
+
if "key-vault" in data:
|
|
60
|
+
data.pop("key-vault")
|
|
61
|
+
|
|
62
|
+
return load_dict(data, schema)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _make_loc_str(loc: tuple) -> str:
|
|
66
|
+
# Remove the body parameter if it is present
|
|
67
|
+
if loc[0] == "body":
|
|
68
|
+
loc = loc[1:]
|
|
69
|
+
|
|
70
|
+
# Create a string from the loc parameter
|
|
71
|
+
loc_str = ""
|
|
72
|
+
needs_sep = False
|
|
73
|
+
for lo in loc:
|
|
74
|
+
if not needs_sep:
|
|
75
|
+
loc_str = f"{loc_str}{lo}"
|
|
76
|
+
needs_sep = True
|
|
77
|
+
else:
|
|
78
|
+
if isinstance(lo, int):
|
|
79
|
+
loc_str = f"{loc_str}[{lo}]"
|
|
80
|
+
else:
|
|
81
|
+
loc_str = f"{loc_str}.{lo}"
|
|
82
|
+
|
|
83
|
+
return loc_str
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def load_dict(data: dict, schema: Type[_T]) -> _T:
|
|
87
|
+
try:
|
|
88
|
+
return schema.model_validate(data)
|
|
89
|
+
|
|
90
|
+
except ValidationError as e:
|
|
91
|
+
messages = []
|
|
92
|
+
for err in e.errors():
|
|
93
|
+
loc = err.get("loc")
|
|
94
|
+
if loc is None:
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
# Create a string from the loc parameter
|
|
98
|
+
loc_str = _make_loc_str(loc)
|
|
99
|
+
|
|
100
|
+
if "ctx" in err and "error" in err["ctx"]:
|
|
101
|
+
exc = err["ctx"]["error"]
|
|
102
|
+
if isinstance(exc, ValueError) or isinstance(exc, AssertionError):
|
|
103
|
+
messages.append(f"{loc_str}: {str(exc)}")
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
if err.get("type") == "json_invalid":
|
|
107
|
+
messages.append(f"{err.get('msg')}: {loc_str}")
|
|
108
|
+
else:
|
|
109
|
+
messages.append(f"{loc_str}: {err.get('msg')}")
|
|
110
|
+
|
|
111
|
+
raise InvalidConfigError(", ".join(messages), details=messages) from e
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from datetime import timedelta
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Annotated, Any, Dict, List, Literal, Optional, Union
|
|
6
|
+
|
|
7
|
+
from humps import kebabize
|
|
8
|
+
from pydantic import BaseModel, ConfigDict, Field, GetCoreSchemaHandler
|
|
9
|
+
from pydantic_core import CoreSchema, core_schema
|
|
10
|
+
|
|
11
|
+
from cognite.extractorutils.exceptions import InvalidConfigError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ConfigModel(BaseModel):
|
|
15
|
+
model_config = ConfigDict(
|
|
16
|
+
alias_generator=kebabize,
|
|
17
|
+
populate_by_name=True,
|
|
18
|
+
extra="forbid",
|
|
19
|
+
# arbitrary_types_allowed=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _ClientCredentialsConfig(ConfigModel):
|
|
24
|
+
type: Literal["client-credentials"]
|
|
25
|
+
client_id: str
|
|
26
|
+
client_secret: str
|
|
27
|
+
token_url: str
|
|
28
|
+
scopes: List[str]
|
|
29
|
+
resource: Optional[str] = None
|
|
30
|
+
audience: Optional[str] = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class _ClientCertificateConfig(ConfigModel):
|
|
34
|
+
type: Literal["client-certificate"]
|
|
35
|
+
client_id: str
|
|
36
|
+
certificate_path: Path
|
|
37
|
+
scopes: List[str]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
AuthenticationConfig = Annotated[Union[_ClientCredentialsConfig, _ClientCertificateConfig], Field(discriminator="type")]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TimeIntervalConfig:
|
|
44
|
+
"""
|
|
45
|
+
Configuration parameter for setting a time interval
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(self, expression: str) -> None:
|
|
49
|
+
self._interval, self._expression = TimeIntervalConfig._parse_expression(expression)
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema:
|
|
53
|
+
return core_schema.no_info_after_validator_function(cls, handler(Union[str, int]))
|
|
54
|
+
|
|
55
|
+
def __eq__(self, other: object) -> bool:
|
|
56
|
+
if not isinstance(other, TimeIntervalConfig):
|
|
57
|
+
return NotImplemented
|
|
58
|
+
return self._interval == other._interval
|
|
59
|
+
|
|
60
|
+
def __hash__(self) -> int:
|
|
61
|
+
return hash(self._interval)
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def _parse_expression(cls, expression: str) -> tuple[int, str]:
|
|
65
|
+
# First, try to parse pure number and assume seconds (for backwards compatibility)
|
|
66
|
+
try:
|
|
67
|
+
return int(expression), f"{expression}s"
|
|
68
|
+
except ValueError:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
match = re.match(r"(\d+)[ \t]*(s|m|h|d)", expression)
|
|
72
|
+
if not match:
|
|
73
|
+
raise InvalidConfigError("Invalid interval pattern")
|
|
74
|
+
|
|
75
|
+
number, unit = match.groups()
|
|
76
|
+
numeric_unit = {"s": 1, "m": 60, "h": 60 * 60, "d": 60 * 60 * 24}[unit]
|
|
77
|
+
|
|
78
|
+
return int(number) * numeric_unit, expression
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def seconds(self) -> int:
|
|
82
|
+
return self._interval
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def minutes(self) -> float:
|
|
86
|
+
return self._interval / 60
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def hours(self) -> float:
|
|
90
|
+
return self._interval / (60 * 60)
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def days(self) -> float:
|
|
94
|
+
return self._interval / (60 * 60 * 24)
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def timedelta(self) -> timedelta:
|
|
98
|
+
days = self._interval // (60 * 60 * 24)
|
|
99
|
+
seconds = self._interval % (60 * 60 * 24)
|
|
100
|
+
return timedelta(days=days, seconds=seconds)
|
|
101
|
+
|
|
102
|
+
def __int__(self) -> int:
|
|
103
|
+
return int(self._interval)
|
|
104
|
+
|
|
105
|
+
def __float__(self) -> float:
|
|
106
|
+
return float(self._interval)
|
|
107
|
+
|
|
108
|
+
def __str__(self) -> str:
|
|
109
|
+
return self._expression
|
|
110
|
+
|
|
111
|
+
def __repr__(self) -> str:
|
|
112
|
+
return self._expression
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class _ConnectionParameters(ConfigModel):
|
|
116
|
+
gzip_compression: bool = False
|
|
117
|
+
status_forcelist: List[int] = Field(default_factory=lambda: [429, 502, 503, 504])
|
|
118
|
+
max_retries: int = 10
|
|
119
|
+
max_retries_connect: int = 3
|
|
120
|
+
max_retry_backoff: TimeIntervalConfig = Field(default_factory=lambda: TimeIntervalConfig("30s"))
|
|
121
|
+
max_connection_pool_size: int = 50
|
|
122
|
+
ssl_verify: bool = True
|
|
123
|
+
proxies: Dict[str, str] = Field(default_factory=dict)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class ConnectionConfig(ConfigModel):
|
|
127
|
+
project: str
|
|
128
|
+
base_url: str
|
|
129
|
+
|
|
130
|
+
extraction_pipeline: str
|
|
131
|
+
|
|
132
|
+
authentication: AuthenticationConfig
|
|
133
|
+
|
|
134
|
+
connection: _ConnectionParameters = Field(default_factory=_ConnectionParameters)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class LogLevel(Enum):
|
|
138
|
+
CRITICAL = "CRITICAL"
|
|
139
|
+
ERROR = "ERROR"
|
|
140
|
+
WARNING = "WARNING"
|
|
141
|
+
INFO = "INFO"
|
|
142
|
+
DEBUG = "DEBUG"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class LogFileHandlerConfig(ConfigModel):
|
|
146
|
+
path: Path
|
|
147
|
+
level: LogLevel
|
|
148
|
+
retention: int = 7
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class LogConsoleHandlerConfig(ConfigModel):
|
|
152
|
+
level: LogLevel
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
LogHandlerConfig = Union[LogFileHandlerConfig, LogConsoleHandlerConfig]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class ExtractorConfig(ConfigModel):
|
|
159
|
+
log_handlers: List[LogHandlerConfig] = Field(default_factory=lambda: [LogConsoleHandlerConfig(level=LogLevel.INFO)])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "cognite-extractor-utils"
|
|
3
|
-
version = "7.4.
|
|
3
|
+
version = "7.4.4"
|
|
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"
|
|
@@ -58,7 +58,7 @@ exclude = "tests/*"
|
|
|
58
58
|
|
|
59
59
|
[tool.poetry.dependencies]
|
|
60
60
|
python = "^3.9.0"
|
|
61
|
-
cognite-sdk = "^7.
|
|
61
|
+
cognite-sdk = "^7.59.0"
|
|
62
62
|
prometheus-client = ">0.7.0, <=1.0.0"
|
|
63
63
|
arrow = "^1.0.0"
|
|
64
64
|
pyyaml = ">=5.3.0, <7"
|
|
@@ -72,6 +72,8 @@ azure-identity = "^1.14.0"
|
|
|
72
72
|
azure-keyvault-secrets = "^4.7.0"
|
|
73
73
|
orjson = "^3.10.3"
|
|
74
74
|
httpx = "^0.27.0"
|
|
75
|
+
pydantic = "^2.8.2"
|
|
76
|
+
pyhumps = "^3.8.0"
|
|
75
77
|
|
|
76
78
|
[tool.poetry.extras]
|
|
77
79
|
experimental = ["cognite-sdk-experimental"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/metrics.py
RENAMED
|
File without changes
|
{cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/threading.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cognite_extractor_utils-7.4.3 → cognite_extractor_utils-7.4.4}/cognite/extractorutils/util.py
RENAMED
|
File without changes
|