cognite-neat 0.105.1__py3-none-any.whl → 0.106.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.
Files changed (29) hide show
  1. cognite/neat/_config.py +6 -260
  2. cognite/neat/_graph/extractors/_classic_cdf/_base.py +26 -13
  3. cognite/neat/_graph/extractors/_classic_cdf/_classic.py +4 -1
  4. cognite/neat/_graph/extractors/_classic_cdf/_sequences.py +2 -2
  5. cognite/neat/_graph/loaders/_rdf2dms.py +7 -2
  6. cognite/neat/_graph/transformers/_base.py +4 -8
  7. cognite/neat/_graph/transformers/_classic_cdf.py +164 -80
  8. cognite/neat/_graph/transformers/_rdfpath.py +1 -1
  9. cognite/neat/_issues/warnings/_external.py +1 -1
  10. cognite/neat/_rules/importers/_rdf/_inference2rules.py +4 -2
  11. cognite/neat/_rules/models/mapping/_classic2core.yaml +70 -58
  12. cognite/neat/_rules/transformers/_mapping.py +3 -2
  13. cognite/neat/_session/_base.py +6 -7
  14. cognite/neat/_session/_inspect.py +6 -2
  15. cognite/neat/_session/_mapping.py +6 -8
  16. cognite/neat/_session/_prepare.py +9 -10
  17. cognite/neat/_session/_read.py +35 -26
  18. cognite/neat/_session/_set.py +9 -0
  19. cognite/neat/_session/_state.py +3 -1
  20. cognite/neat/_session/_to.py +11 -13
  21. cognite/neat/_store/_graph_store.py +33 -28
  22. cognite/neat/_utils/auth.py +35 -15
  23. cognite/neat/_utils/collection_.py +32 -11
  24. cognite/neat/_version.py +1 -1
  25. {cognite_neat-0.105.1.dist-info → cognite_neat-0.106.0.dist-info}/METADATA +1 -7
  26. {cognite_neat-0.105.1.dist-info → cognite_neat-0.106.0.dist-info}/RECORD +29 -29
  27. {cognite_neat-0.105.1.dist-info → cognite_neat-0.106.0.dist-info}/LICENSE +0 -0
  28. {cognite_neat-0.105.1.dist-info → cognite_neat-0.106.0.dist-info}/WHEEL +0 -0
  29. {cognite_neat-0.105.1.dist-info → cognite_neat-0.106.0.dist-info}/entry_points.txt +0 -0
@@ -22,23 +22,22 @@ from .exceptions import NeatSessionError, session_class_wrapper
22
22
  class ReadAPI:
23
23
  """Read from a data source into NeatSession graph store."""
24
24
 
25
- def __init__(self, state: SessionState, client: NeatClient | None, verbose: bool) -> None:
25
+ def __init__(self, state: SessionState, verbose: bool) -> None:
26
26
  self._state = state
27
27
  self._verbose = verbose
28
- self.cdf = CDFReadAPI(state, client, verbose)
29
- self.rdf = RDFReadAPI(state, client, verbose)
30
- self.excel = ExcelReadAPI(state, client, verbose)
31
- self.csv = CSVReadAPI(state, client, verbose)
32
- self.yaml = YamlReadAPI(state, client, verbose)
33
- self.xml = XMLReadAPI(state, client, verbose)
28
+ self.cdf = CDFReadAPI(state, verbose)
29
+ self.rdf = RDFReadAPI(state, verbose)
30
+ self.excel = ExcelReadAPI(state, verbose)
31
+ self.csv = CSVReadAPI(state, verbose)
32
+ self.yaml = YamlReadAPI(state, verbose)
33
+ self.xml = XMLReadAPI(state, verbose)
34
34
 
35
35
 
36
36
  @session_class_wrapper
37
37
  class BaseReadAPI:
38
- def __init__(self, state: SessionState, client: NeatClient | None, verbose: bool) -> None:
38
+ def __init__(self, state: SessionState, verbose: bool) -> None:
39
39
  self._state = state
40
40
  self._verbose = verbose
41
- self._client = client
42
41
 
43
42
 
44
43
  @session_class_wrapper
@@ -48,15 +47,15 @@ class CDFReadAPI(BaseReadAPI):
48
47
 
49
48
  """
50
49
 
51
- def __init__(self, state: SessionState, client: NeatClient | None, verbose: bool) -> None:
52
- super().__init__(state, client, verbose)
53
- self.classic = CDFClassicAPI(state, client, verbose)
50
+ def __init__(self, state: SessionState, verbose: bool) -> None:
51
+ super().__init__(state, verbose)
52
+ self.classic = CDFClassicAPI(state, verbose)
54
53
 
55
54
  @property
56
55
  def _get_client(self) -> NeatClient:
57
- if self._client is None:
56
+ if self._state.client is None:
58
57
  raise NeatValueError("No client provided. Please provide a client to read a data model.")
59
- return self._client
58
+ return self._state.client
60
59
 
61
60
  def data_model(self, data_model_id: DataModelIdentifier) -> IssueList:
62
61
  """Reads a Data Model from CDF to the knowledge graph.
@@ -89,11 +88,11 @@ class CDFClassicAPI(BaseReadAPI):
89
88
 
90
89
  @property
91
90
  def _get_client(self) -> NeatClient:
92
- if self._client is None:
91
+ if self._state.client is None:
93
92
  raise ValueError("No client provided. Please provide a client to read a data model.")
94
- return self._client
93
+ return self._state.client
95
94
 
96
- def graph(self, root_asset_external_id: str, limit_per_type: int | None = None) -> None:
95
+ def graph(self, root_asset_external_id: str, limit_per_type: int | None = None) -> IssueList:
97
96
  """Reads the classic knowledge graph from CDF.
98
97
 
99
98
  The Classic Graph consists of the following core resource type.
@@ -129,14 +128,24 @@ class CDFClassicAPI(BaseReadAPI):
129
128
  root_asset_external_id: The external id of the root asset
130
129
  limit_per_type: The maximum number of nodes to extract per core node type. If None, all nodes are extracted.
131
130
 
131
+ Returns:
132
+ IssueList: A list of issues that occurred during the extraction.
133
+
134
+ Example:
135
+ ```python
136
+ neat.read.cdf.graph("root_asset_external_id")
137
+ ```
138
+
132
139
  """
133
140
  extractor = extractors.ClassicGraphExtractor(
134
141
  self._get_client, root_asset_external_id=root_asset_external_id, limit_per_type=limit_per_type
135
142
  )
136
143
 
137
- self._state.instances.store.write(extractor)
138
- if self._verbose:
139
- print(f"Classic Graph {root_asset_external_id} read successfully")
144
+ issues = self._state.instances.store.write(extractor)
145
+ issues.action = "Read Classic Graph"
146
+ if issues:
147
+ print("Use the .inspect.issues() for more details")
148
+ return issues
140
149
 
141
150
 
142
151
  @session_class_wrapper
@@ -153,9 +162,9 @@ class ExcelReadAPI(BaseReadAPI):
153
162
  ```
154
163
  """
155
164
 
156
- def __init__(self, state: SessionState, client: NeatClient | None, verbose: bool) -> None:
157
- super().__init__(state, client, verbose)
158
- self.examples = ExcelExampleAPI(state, client, verbose)
165
+ def __init__(self, state: SessionState, verbose: bool) -> None:
166
+ super().__init__(state, verbose)
167
+ self.examples = ExcelExampleAPI(state, verbose)
159
168
 
160
169
  def __call__(self, io: Any) -> IssueList:
161
170
  """Reads a Neat Excel Rules sheet to the graph store. The rules sheet may stem from an Information architect,
@@ -201,7 +210,7 @@ class YamlReadAPI(BaseReadAPI):
201
210
  if format == "neat":
202
211
  importer = importers.YAMLImporter.from_file(path, source_name=f"{reader!s}")
203
212
  elif format == "toolkit":
204
- dms_importer = importers.DMSImporter.from_path(path, self._client)
213
+ dms_importer = importers.DMSImporter.from_path(path, self._state.client)
205
214
  if dms_importer.issue_list.has_warning_type(MissingCogniteClientWarning):
206
215
  raise NeatSessionError(
207
216
  "No client provided. You are referencing Cognite containers in your data model, "
@@ -316,8 +325,8 @@ class RDFReadAPI(BaseReadAPI):
316
325
  io: file path or url to the RDF source
317
326
  """
318
327
 
319
- def __init__(self, state: SessionState, client: NeatClient | None, verbose: bool) -> None:
320
- super().__init__(state, client, verbose)
328
+ def __init__(self, state: SessionState, verbose: bool) -> None:
329
+ super().__init__(state, verbose)
321
330
  self.examples = RDFExamples(state)
322
331
 
323
332
  def ontology(self, io: Any) -> IssueList:
@@ -1,5 +1,7 @@
1
+ from cognite.client import CogniteClient
1
2
  from cognite.client import data_modeling as dm
2
3
 
4
+ from cognite.neat._client import NeatClient
3
5
  from cognite.neat._constants import COGNITE_MODELS
4
6
  from cognite.neat._issues import IssueList
5
7
  from cognite.neat._rules.models import DMSRules
@@ -35,3 +37,10 @@ class SetAPI:
35
37
  " due to temporarily issue with the reverse direct relation interpretation"
36
38
  )
37
39
  return self._state.rule_transform(SetIDDMSModel(new_model_id))
40
+
41
+ def client(self, client: CogniteClient) -> None:
42
+ """Sets the client to be used in the session."""
43
+ self._state.client = NeatClient(client)
44
+ if self._verbose:
45
+ print(f"Client set to {self._state.client.config.project} CDF project.")
46
+ return None
@@ -1,6 +1,7 @@
1
1
  from dataclasses import dataclass, field
2
2
  from typing import Literal, cast
3
3
 
4
+ from cognite.neat._client import NeatClient
4
5
  from cognite.neat._issues import IssueList
5
6
  from cognite.neat._rules.importers import BaseImporter, InferenceImporter
6
7
  from cognite.neat._rules.models import DMSRules, InformationRules
@@ -15,10 +16,11 @@ from .exceptions import NeatSessionError
15
16
 
16
17
 
17
18
  class SessionState:
18
- def __init__(self, store_type: Literal["memory", "oxigraph"]) -> None:
19
+ def __init__(self, store_type: Literal["memory", "oxigraph"], client: NeatClient | None = None) -> None:
19
20
  self.instances = InstancesState(store_type)
20
21
  self.rule_store = NeatRulesStore()
21
22
  self.last_reference: DMSRules | InformationRules | None = None
23
+ self.client = client
22
24
 
23
25
  def rule_transform(self, *transformer: RulesTransformer) -> IssueList:
24
26
  if not transformer:
@@ -4,7 +4,6 @@ from typing import Any, Literal, overload
4
4
 
5
5
  from cognite.client.data_classes.data_modeling import SpaceApply
6
6
 
7
- from cognite.neat._client import NeatClient
8
7
  from cognite.neat._constants import COGNITE_MODELS
9
8
  from cognite.neat._graph import loaders
10
9
  from cognite.neat._rules import exporters
@@ -25,10 +24,10 @@ class ToAPI:
25
24
 
26
25
  """
27
26
 
28
- def __init__(self, state: SessionState, client: NeatClient | None, verbose: bool) -> None:
27
+ def __init__(self, state: SessionState, verbose: bool) -> None:
29
28
  self._state = state
30
29
  self._verbose = verbose
31
- self.cdf = CDFToAPI(state, client, verbose)
30
+ self.cdf = CDFToAPI(state, verbose)
32
31
 
33
32
  def excel(
34
33
  self,
@@ -153,8 +152,7 @@ class ToAPI:
153
152
  class CDFToAPI:
154
153
  """Write a verified Data Model and Instances to CDF."""
155
154
 
156
- def __init__(self, state: SessionState, client: NeatClient | None, verbose: bool) -> None:
157
- self._client = client
155
+ def __init__(self, state: SessionState, verbose: bool) -> None:
158
156
  self._state = state
159
157
  self._verbose = verbose
160
158
 
@@ -166,9 +164,9 @@ class CDFToAPI:
166
164
  Note this space is required to be different than the space with the data model.
167
165
 
168
166
  """
169
- if not self._client:
167
+ if not self._state.client:
170
168
  raise NeatSessionError("No CDF client provided!")
171
-
169
+ client = self._state.client
172
170
  space = space or f"{self._state.rule_store.last_verified_dms_rules.metadata.space}_instances"
173
171
 
174
172
  if space and space == self._state.rule_store.last_verified_dms_rules.metadata.space:
@@ -176,16 +174,16 @@ class CDFToAPI:
176
174
  elif not PATTERNS.space_compliance.match(str(space)):
177
175
  raise NeatSessionError("Please provide a valid space name. {PATTERNS.space_compliance.pattern}")
178
176
 
179
- if not self._client.data_modeling.spaces.retrieve(space):
180
- self._client.data_modeling.spaces.apply(SpaceApply(space=space))
177
+ if not client.data_modeling.spaces.retrieve(space):
178
+ client.data_modeling.spaces.apply(SpaceApply(space=space))
181
179
 
182
180
  loader = loaders.DMSLoader.from_rules(
183
181
  self._state.rule_store.last_verified_dms_rules,
184
182
  self._state.instances.store,
185
183
  instance_space=space,
186
- client=self._client,
184
+ client=client,
187
185
  )
188
- result = loader.load_into_cdf(self._client)
186
+ result = loader.load_into_cdf(client)
189
187
  self._state.instances.outcome.append(result)
190
188
  print("You can inspect the details with the .inspect.outcome.instances(...) method.")
191
189
  return result
@@ -219,9 +217,9 @@ class CDFToAPI:
219
217
 
220
218
  exporter = exporters.DMSExporter(existing=existing, export_components=components, drop_data=drop_data)
221
219
 
222
- if not self._client:
220
+ if not self._state.client:
223
221
  raise NeatSessionError("No client provided!")
224
222
 
225
- result = self._state.rule_store.export_to_cdf(exporter, self._client, dry_run)
223
+ result = self._state.rule_store.export_to_cdf(exporter, self._state.client, dry_run)
226
224
  print("You can inspect the details with the .inspect.outcome.data_model(...) method.")
227
225
  return result
@@ -15,6 +15,7 @@ from cognite.neat._graph._shared import rdflib_to_oxi_type
15
15
  from cognite.neat._graph.extractors import RdfFileExtractor, TripleExtractors
16
16
  from cognite.neat._graph.queries import Queries
17
17
  from cognite.neat._graph.transformers import Transformers
18
+ from cognite.neat._issues import IssueList, catch_issues
18
19
  from cognite.neat._rules.analysis import InformationAnalysis
19
20
  from cognite.neat._rules.models import InformationRules
20
21
  from cognite.neat._rules.models.entities import ClassEntity
@@ -157,39 +158,43 @@ class NeatGraphStore:
157
158
 
158
159
  return cls(graph, rules)
159
160
 
160
- def write(self, extractor: TripleExtractors) -> None:
161
- _start = datetime.now(timezone.utc)
162
- success = True
163
-
164
- if isinstance(extractor, RdfFileExtractor) and not extractor.issue_list.has_errors:
165
- self._parse_file(extractor.filepath, cast(str, extractor.format), extractor.base_uri)
166
- elif isinstance(extractor, RdfFileExtractor):
167
- success = False
168
- issue_text = "\n".join([issue.as_message() for issue in extractor.issue_list])
169
- warnings.warn(
170
- f"Cannot write to graph store with {type(extractor).__name__}, errors found in file:\n{issue_text}",
171
- stacklevel=2,
172
- )
173
- else:
174
- self._add_triples(extractor.extract())
175
-
176
- if success:
177
- _end = datetime.now(timezone.utc)
178
- # Need to do the hasattr in case the extractor comes from NeatEngine.
179
- activities = (
180
- extractor._get_activity_names()
181
- if hasattr(extractor, "_get_activity_names")
182
- else [type(extractor).__name__]
183
- )
184
- for activity in activities:
185
- self.provenance.append(
186
- Change.record(
161
+ def write(self, extractor: TripleExtractors) -> IssueList:
162
+ last_change: Change | None = None
163
+ with catch_issues() as issue_list:
164
+ _start = datetime.now(timezone.utc)
165
+ success = True
166
+
167
+ if isinstance(extractor, RdfFileExtractor) and not extractor.issue_list.has_errors:
168
+ self._parse_file(extractor.filepath, cast(str, extractor.format), extractor.base_uri)
169
+ elif isinstance(extractor, RdfFileExtractor):
170
+ success = False
171
+ issue_text = "\n".join([issue.as_message() for issue in extractor.issue_list])
172
+ warnings.warn(
173
+ f"Cannot write to graph store with {type(extractor).__name__}, errors found in file:\n{issue_text}",
174
+ stacklevel=2,
175
+ )
176
+ else:
177
+ self._add_triples(extractor.extract())
178
+
179
+ if success:
180
+ _end = datetime.now(timezone.utc)
181
+ # Need to do the hasattr in case the extractor comes from NeatEngine.
182
+ activities = (
183
+ extractor._get_activity_names()
184
+ if hasattr(extractor, "_get_activity_names")
185
+ else [type(extractor).__name__]
186
+ )
187
+ for activity in activities:
188
+ last_change = Change.record(
187
189
  activity=activity,
188
190
  start=_start,
189
191
  end=_end,
190
192
  description=f"Extracted triples to graph store using {type(extractor).__name__}",
191
193
  )
192
- )
194
+ self.provenance.append(last_change)
195
+ if last_change:
196
+ last_change.target_entity.issues.extend(issue_list)
197
+ return issue_list
193
198
 
194
199
  def _read_via_rules_linkage(
195
200
  self, class_neat_id: URIRef, property_link_pairs: dict[str, URIRef] | None
@@ -23,8 +23,9 @@ def get_cognite_client(env_file_name: str) -> CogniteClient:
23
23
  be prompted to enter them.
24
24
 
25
25
  Args:
26
- env_file_name: The name of the .env file to look for in the repository root. If the file is found, the variables
27
- will be loaded from the file. If the file is not found, the user will be prompted to enter the variables.
26
+ env_file_name: The name of the .env file to look for in the repository root / current working directory. If
27
+ the file is found, the variables will be loaded from the file. If the file is not found, the user will
28
+ be prompted to enter the variables and the file will be created.
28
29
 
29
30
  Returns:
30
31
  CogniteClient: A CogniteClient instance.
@@ -40,26 +41,44 @@ def get_cognite_client(env_file_name: str) -> CogniteClient:
40
41
  client = variables.get_client()
41
42
  print(f"Found {env_file_name} file in repository root. Loaded variables from {env_file_name} file.")
42
43
  return client
44
+ elif (Path.cwd() / env_file_name).exists():
45
+ with suppress(KeyError, FileNotFoundError, TypeError):
46
+ variables = _from_dotenv(Path.cwd() / env_file_name)
47
+ client = variables.get_client()
48
+ print(
49
+ f"Found {env_file_name} file in current working directory. Loaded variables from {env_file_name} file."
50
+ )
51
+ return client
43
52
  # Then try to load from environment variables
44
53
  with suppress(KeyError):
45
54
  variables = EnvironmentVariables.create_from_environ()
55
+ print("Loaded variables from environment variables.")
46
56
  return variables.get_client()
47
57
  # If not found, prompt the user
48
58
  variables = _prompt_user()
49
59
  if repo_root and _env_in_gitignore(repo_root, env_file_name):
50
- local_import("rich", "jupyter")
51
- from rich.prompt import Prompt
52
-
53
60
  env_file = repo_root / env_file_name
54
- answer = Prompt.ask(
55
- f"Do you store the variables in an {env_file_name} file in the repository root for easy reuse?",
56
- choices=["y", "n"],
57
- )
58
- if env_file.exists():
59
- answer = Prompt.ask(f"{env_file} already exists. Overwrite?", choices=["y", "n"])
60
- if answer == "y":
61
- env_file.write_text(variables.create_env_file())
62
- print(f"Created {env_file_name} file in repository root.")
61
+ location = "repository root"
62
+ elif repo_root:
63
+ # We do not offer to create the file in the repository root if it is in .gitignore
64
+ # as an inexperienced user might accidentally commit it.
65
+ print("Cannot create .env file in repository root as there is no .env entry in the .gitignore.")
66
+ return variables.get_client()
67
+ else:
68
+ env_file = Path.cwd() / env_file_name
69
+ location = "current working directory"
70
+ local_import("rich", "jupyter")
71
+ from rich.prompt import Prompt
72
+
73
+ answer = Prompt.ask(
74
+ f"Do you store the variables in an {env_file_name} file in the {location} for easy reuse?",
75
+ choices=["y", "n"],
76
+ )
77
+ if env_file.exists():
78
+ answer = Prompt.ask(f"{env_file} already exists. Overwrite?", choices=["y", "n"])
79
+ if answer == "y":
80
+ env_file.write_text(variables.create_env_file())
81
+ print(f"Created {env_file_name} file in {location}.")
63
82
 
64
83
  return variables.get_client()
65
84
 
@@ -320,7 +339,8 @@ def _prompt_cluster_and_project() -> EnvironmentVariables:
320
339
  def _repo_root() -> Path | None:
321
340
  with suppress(Exception):
322
341
  result = subprocess.run("git rev-parse --show-toplevel".split(), stdout=subprocess.PIPE)
323
- return Path(result.stdout.decode().strip())
342
+ if (output := result.stdout.decode().strip()) != "":
343
+ return Path(output)
324
344
  return None
325
345
 
326
346
 
@@ -2,6 +2,7 @@ from collections import Counter
2
2
  from collections.abc import Iterable, Sequence
3
3
  from typing import TypeVar
4
4
 
5
+ from cognite.neat._config import GLOBAL_CONFIG
5
6
  from cognite.neat._constants import IN_PYODIDE
6
7
 
7
8
  T_Element = TypeVar("T_Element")
@@ -26,20 +27,40 @@ def remove_list_elements(input_list: list, elements_to_remove: list) -> list:
26
27
 
27
28
 
28
29
  def iterate_progress_bar(iterable: Iterable[T_Element], total: int, description: str) -> Iterable[T_Element]:
29
- if IN_PYODIDE:
30
+ if IN_PYODIDE or GLOBAL_CONFIG.progress_bar in ("infer", "tqdm"):
30
31
  try:
31
- from tqdm import tqdm # type: ignore [import]
32
+ from tqdm import tqdm
32
33
  except ModuleNotFoundError:
33
34
  return iterable
34
35
  return tqdm(iterable, total=total, desc=description)
35
- # Progress bar from rich requires multi-threading, which is not supported in Pyodide
36
- try:
37
- from rich.progress import track
38
- except ModuleNotFoundError:
36
+
37
+ elif GLOBAL_CONFIG.progress_bar == "tqdm-notebook":
38
+ try:
39
+ from tqdm.notebook import tqdm as tqdm_notebook
40
+ except ModuleNotFoundError:
41
+ return iterable
42
+ return tqdm_notebook(iterable, total=total, desc=description)
43
+ elif GLOBAL_CONFIG.progress_bar in ("infer", "rich"):
44
+ # Progress bar from rich requires multi-threading, which is not supported in Pyodide
45
+ try:
46
+ from rich.progress import track
47
+ except ModuleNotFoundError:
48
+ return iterable
49
+
50
+ return track(
51
+ iterable,
52
+ total=total,
53
+ description=description,
54
+ )
55
+ elif GLOBAL_CONFIG.progress_bar is None:
39
56
  return iterable
57
+ else:
58
+ raise ValueError(f"Unsupported progress bar type: {GLOBAL_CONFIG.progress_bar}")
59
+
40
60
 
41
- return track(
42
- iterable,
43
- total=total,
44
- description=description,
45
- )
61
+ def iterate_progress_bar_if_above_config_threshold(
62
+ iterable: Iterable[T_Element], total: int, description: str
63
+ ) -> Iterable[T_Element]:
64
+ if GLOBAL_CONFIG.use_iterate_bar_threshold and total > GLOBAL_CONFIG.use_iterate_bar_threshold:
65
+ return iterate_progress_bar(iterable, total, description)
66
+ return iterable
cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.105.1"
1
+ __version__ = "0.106.0"
2
2
  __engine__ = "^2.0.3"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: cognite-neat
3
- Version: 0.105.1
3
+ Version: 0.106.0
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0
@@ -17,13 +17,11 @@ Provides-Extra: all
17
17
  Provides-Extra: docs
18
18
  Provides-Extra: google
19
19
  Provides-Extra: oxi
20
- Provides-Extra: service
21
20
  Requires-Dist: PyYAML
22
21
  Requires-Dist: backports.strenum (>=1.2,<2.0) ; python_version < "3.11"
23
22
  Requires-Dist: cognite-sdk (>=7.71.2,<8.0.0)
24
23
  Requires-Dist: elementpath (>=4.0.0,<5.0.0)
25
24
  Requires-Dist: exceptiongroup (>=1.1.3,<2.0.0) ; python_version < "3.11"
26
- Requires-Dist: fastapi (>=0,<1) ; extra == "service" or extra == "all"
27
25
  Requires-Dist: google-api-python-client ; extra == "google"
28
26
  Requires-Dist: google-auth-oauthlib ; extra == "google"
29
27
  Requires-Dist: gspread ; extra == "google"
@@ -45,20 +43,16 @@ Requires-Dist: openpyxl
45
43
  Requires-Dist: oxrdflib[oxigraph] (>=0.4.0,<0.5.0) ; extra == "oxi" or extra == "all"
46
44
  Requires-Dist: packaging (>=22.0,<25.0)
47
45
  Requires-Dist: pandas
48
- Requires-Dist: prometheus-client (>=0,<1) ; extra == "service" or extra == "all"
49
46
  Requires-Dist: pydantic (>=2,<3)
50
47
  Requires-Dist: pymdown-extensions ; extra == "docs"
51
48
  Requires-Dist: pyoxigraph (==0.4.3) ; extra == "oxi" or extra == "all"
52
- Requires-Dist: python-multipart (==0.0.9) ; extra == "service" or extra == "all"
53
49
  Requires-Dist: pyvis (>=0.3.2,<0.4.0)
54
50
  Requires-Dist: rdflib
55
51
  Requires-Dist: requests
56
52
  Requires-Dist: rich[jupyter] (>=13.7.1,<14.0.0)
57
- Requires-Dist: schedule (>=1,<2) ; extra == "service" or extra == "all"
58
53
  Requires-Dist: tomli (>=2.0.1,<3.0.0) ; python_version < "3.11"
59
54
  Requires-Dist: typing_extensions (>=4.8,<5.0) ; python_version < "3.11"
60
55
  Requires-Dist: urllib3 (>=2,<3)
61
- Requires-Dist: uvicorn[standard] (>=0,<1) ; extra == "service" or extra == "all"
62
56
  Project-URL: Documentation, https://cognite-neat.readthedocs-hosted.com/
63
57
  Project-URL: Repository, https://github.com/cognitedata/neat
64
58
  Description-Content-Type: text/markdown