cognite-neat 0.88.1__py3-none-any.whl → 0.88.3__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 (103) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/graph/__init__.py +0 -3
  3. cognite/neat/graph/loaders/_base.py +6 -6
  4. cognite/neat/graph/loaders/_rdf2asset.py +28 -31
  5. cognite/neat/graph/loaders/_rdf2dms.py +24 -15
  6. cognite/neat/issues/__init__.py +14 -0
  7. cognite/neat/issues/_base.py +415 -0
  8. cognite/neat/issues/errors/__init__.py +72 -0
  9. cognite/neat/issues/errors/_external.py +67 -0
  10. cognite/neat/issues/errors/_general.py +28 -0
  11. cognite/neat/issues/errors/_properties.py +62 -0
  12. cognite/neat/issues/errors/_resources.py +111 -0
  13. cognite/neat/issues/errors/_workflow.py +36 -0
  14. cognite/neat/{rules/issues → issues}/formatters.py +10 -10
  15. cognite/neat/issues/warnings/__init__.py +66 -0
  16. cognite/neat/issues/warnings/_external.py +40 -0
  17. cognite/neat/issues/warnings/_general.py +29 -0
  18. cognite/neat/issues/warnings/_models.py +92 -0
  19. cognite/neat/issues/warnings/_properties.py +44 -0
  20. cognite/neat/issues/warnings/_resources.py +55 -0
  21. cognite/neat/issues/warnings/user_modeling.py +113 -0
  22. cognite/neat/rules/_shared.py +10 -2
  23. cognite/neat/rules/exporters/_base.py +6 -6
  24. cognite/neat/rules/exporters/_rules2dms.py +19 -11
  25. cognite/neat/rules/exporters/_rules2excel.py +4 -4
  26. cognite/neat/rules/exporters/_rules2ontology.py +74 -51
  27. cognite/neat/rules/exporters/_rules2yaml.py +3 -3
  28. cognite/neat/rules/exporters/_validation.py +11 -96
  29. cognite/neat/rules/importers/__init__.py +7 -3
  30. cognite/neat/rules/importers/_base.py +9 -13
  31. cognite/neat/rules/importers/_dms2rules.py +42 -24
  32. cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py +49 -53
  33. cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py +31 -23
  34. cognite/neat/rules/importers/_dtdl2rules/spec.py +7 -0
  35. cognite/neat/rules/importers/_rdf/_imf2rules/__init__.py +3 -0
  36. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2classes.py +82 -0
  37. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2metadata.py +34 -0
  38. cognite/neat/rules/importers/_rdf/_imf2rules/_imf2properties.py +123 -0
  39. cognite/neat/rules/importers/{_owl2rules/_owl2rules.py → _rdf/_imf2rules/_imf2rules.py} +24 -18
  40. cognite/neat/rules/importers/{_inference2rules.py → _rdf/_inference2rules.py} +9 -9
  41. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2classes.py +58 -0
  42. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2metadata.py +68 -0
  43. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2properties.py +60 -0
  44. cognite/neat/rules/importers/_rdf/_owl2rules/_owl2rules.py +76 -0
  45. cognite/neat/rules/importers/_rdf/_shared.py +586 -0
  46. cognite/neat/rules/importers/_spreadsheet2rules.py +35 -22
  47. cognite/neat/rules/importers/_yaml2rules.py +23 -21
  48. cognite/neat/rules/models/_constants.py +2 -1
  49. cognite/neat/rules/models/_rdfpath.py +4 -4
  50. cognite/neat/rules/models/_types/_field.py +9 -11
  51. cognite/neat/rules/models/asset/_rules.py +1 -3
  52. cognite/neat/rules/models/asset/_validation.py +14 -10
  53. cognite/neat/rules/models/dms/_converter.py +2 -4
  54. cognite/neat/rules/models/dms/_exporter.py +30 -8
  55. cognite/neat/rules/models/dms/_rules.py +23 -7
  56. cognite/neat/rules/models/dms/_schema.py +94 -62
  57. cognite/neat/rules/models/dms/_validation.py +105 -66
  58. cognite/neat/rules/models/entities.py +3 -0
  59. cognite/neat/rules/models/information/_converter.py +2 -2
  60. cognite/neat/rules/models/information/_rules.py +7 -8
  61. cognite/neat/rules/models/information/_validation.py +48 -25
  62. cognite/neat/rules/transformers/__init__.py +0 -0
  63. cognite/neat/rules/transformers/_base.py +15 -0
  64. cognite/neat/utils/auxiliary.py +2 -35
  65. cognite/neat/utils/text.py +17 -0
  66. cognite/neat/workflows/base.py +4 -4
  67. cognite/neat/workflows/cdf_store.py +3 -3
  68. cognite/neat/workflows/steps/data_contracts.py +1 -1
  69. cognite/neat/workflows/steps/lib/current/graph_extractor.py +3 -3
  70. cognite/neat/workflows/steps/lib/current/graph_loader.py +2 -2
  71. cognite/neat/workflows/steps/lib/current/graph_store.py +1 -1
  72. cognite/neat/workflows/steps/lib/current/rules_exporter.py +10 -10
  73. cognite/neat/workflows/steps/lib/current/rules_importer.py +78 -6
  74. cognite/neat/workflows/steps/lib/current/rules_validator.py +20 -9
  75. cognite/neat/workflows/steps/lib/io/io_steps.py +5 -5
  76. cognite/neat/workflows/steps_registry.py +4 -5
  77. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/METADATA +1 -1
  78. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/RECORD +86 -77
  79. cognite/neat/exceptions.py +0 -145
  80. cognite/neat/graph/exceptions.py +0 -90
  81. cognite/neat/graph/issues/loader.py +0 -104
  82. cognite/neat/issues.py +0 -158
  83. cognite/neat/rules/importers/_owl2rules/_owl2classes.py +0 -215
  84. cognite/neat/rules/importers/_owl2rules/_owl2metadata.py +0 -209
  85. cognite/neat/rules/importers/_owl2rules/_owl2properties.py +0 -203
  86. cognite/neat/rules/issues/__init__.py +0 -26
  87. cognite/neat/rules/issues/base.py +0 -82
  88. cognite/neat/rules/issues/dms.py +0 -683
  89. cognite/neat/rules/issues/fileread.py +0 -197
  90. cognite/neat/rules/issues/importing.py +0 -423
  91. cognite/neat/rules/issues/ontology.py +0 -298
  92. cognite/neat/rules/issues/spreadsheet.py +0 -563
  93. cognite/neat/rules/issues/spreadsheet_file.py +0 -151
  94. cognite/neat/rules/issues/tables.py +0 -72
  95. cognite/neat/workflows/_exceptions.py +0 -41
  96. /cognite/neat/{graph/issues → rules/importers/_rdf}/__init__.py +0 -0
  97. /cognite/neat/rules/importers/{_owl2rules → _rdf/_owl2rules}/__init__.py +0 -0
  98. /cognite/neat/{graph/stores → store}/__init__.py +0 -0
  99. /cognite/neat/{graph/stores → store}/_base.py +0 -0
  100. /cognite/neat/{graph/stores → store}/_provenance.py +0 -0
  101. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/LICENSE +0 -0
  102. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/WHEEL +0 -0
  103. {cognite_neat-0.88.1.dist-info → cognite_neat-0.88.3.dist-info}/entry_points.txt +0 -0
@@ -1,90 +0,0 @@
1
- """This module contains the definition of validation errors and warnings raised during graph methods"""
2
-
3
- from cognite.neat.constants import DEFAULT_DOCS_URL
4
- from cognite.neat.exceptions import NeatException
5
-
6
- DOCS_BASE_URL = f"{DEFAULT_DOCS_URL}api/exceptions.html#{__name__}"
7
-
8
-
9
- class UnsupportedPropertyType(NeatException):
10
- """Unsupported property type when processing the graph capturing sheet
11
-
12
- Args:
13
- property_type: property type that is not supported
14
- verbose: flag that indicates whether to provide enhanced exception message, by default False
15
- """
16
-
17
- type_: str = "UnsupportedPropertyType"
18
- code: int = 1000
19
- description: str = "Unsupported property type when processing the graph capturing sheet."
20
- example: str = ""
21
- fix: str = ""
22
-
23
- def __init__(self, property_type: str, verbose: bool = False):
24
- self.property_type = property_type
25
-
26
- self.message = (
27
- f"Property type {self.property_type} is not supported. "
28
- " Only the following property types are supported: DatatypeProperty and ObjectProperty"
29
- f"\nFor more information visit: {DOCS_BASE_URL}.{self.__class__.__name__}"
30
- )
31
-
32
- if verbose:
33
- self.message += f"\nDescription: {self.description}"
34
- self.message += f"\nExample: {self.example}"
35
- self.message += f"\nFix: {self.fix}"
36
- super().__init__(self.message)
37
-
38
-
39
- class NamespaceRequired(NeatException):
40
- """The functionality requires namespace in the TransformationRules.
41
-
42
- Args:
43
- functionality: functionality that requires namespace
44
- verbose: flag that indicates whether to provide enhanced exception message, by default False
45
- """
46
-
47
- type_ = "NamespaceRequired"
48
- description: str = "The functionality requires namespace in the TransformationRules."
49
- example: str = ""
50
- fix: str = ""
51
-
52
- def __init__(self, functionality: str, verbose: bool = False):
53
- self.message = (
54
- f"Namespace is required to be set in the Transformation rules"
55
- f"to use {functionality}."
56
- f"\nFor more information visit: {DOCS_BASE_URL}.{self.__class__.__name__}"
57
- )
58
-
59
- if verbose:
60
- self.message += f"\nDescription: {self.description}"
61
- self.message += f"\nExample: {self.example}"
62
- self.message += f"\nFix: {self.fix}"
63
- super().__init__(self.message)
64
-
65
-
66
- class DatasetIdRequired(NeatException):
67
- """The functionality requires data_set_id in the TransformationRules.
68
-
69
- Args:
70
- functionality: functionality that requires namespace
71
- verbose: flag that indicates whether to provide enhanced exception message, by default False
72
- """
73
-
74
- type_ = "DatasetIdRequired"
75
- description: str = "The functionality requires data_set_id in the TransformationRules."
76
- example: str = ""
77
- fix: str = ""
78
-
79
- def __init__(self, functionality: str, verbose: bool = False):
80
- self.message = (
81
- f"DataSetId is required to be set in the Transformation rules"
82
- f"to use {functionality}."
83
- f"\nFor more information visit: {DOCS_BASE_URL}.{self.__class__.__name__}"
84
- )
85
-
86
- if verbose:
87
- self.message += f"\nDescription: {self.description}"
88
- self.message += f"\nExample: {self.example}"
89
- self.message += f"\nFix: {self.fix}"
90
- super().__init__(self.message)
@@ -1,104 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Any
3
-
4
- from cognite.neat.issues import NeatError, NeatWarning
5
-
6
- __all__ = [
7
- "FailedAuthorizationError",
8
- "MissingDataModelError",
9
- "FailedConvertError",
10
- "InvalidClassWarning",
11
- "InvalidInstanceError",
12
- ]
13
-
14
-
15
- @dataclass(frozen=True)
16
- class FailedAuthorizationError(NeatError):
17
- description = "Missing authorization for {action}: {reason}"
18
-
19
- action: str
20
- reason: str
21
-
22
- def message(self) -> str:
23
- return self.description.format(action=self.action, reason=self.reason)
24
-
25
- def dump(self) -> dict[str, Any]:
26
- output = super().dump()
27
- output["action"] = self.action
28
- output["reason"] = self.reason
29
- return output
30
-
31
-
32
- @dataclass(frozen=True)
33
- class MissingDataModelError(NeatError):
34
- description = "The data model with identifier {identifier} is missing: {reason}"
35
- fix = "Check the data model identifier and try again."
36
-
37
- identifier: str
38
- reason: str
39
-
40
- def message(self) -> str:
41
- return self.description.format(identifier=self.identifier, reason=self.reason)
42
-
43
- def dump(self) -> dict[str, Any]:
44
- output = super().dump()
45
- output["identifier"] = self.identifier
46
- output["reason"] = self.reason
47
- return output
48
-
49
-
50
- @dataclass(frozen=True)
51
- class FailedConvertError(NeatError):
52
- description = "Failed to convert the {identifier} to {target_format}: {reason}"
53
- fix = "Check the error message and correct the rules."
54
- identifier: str
55
- target_format: str
56
- reason: str
57
-
58
- def message(self) -> str:
59
- return self.description.format(identifier=self.identifier, target_format=self.target_format, reason=self.reason)
60
-
61
- def dump(self) -> dict[str, Any]:
62
- output = super().dump()
63
- output["identifier"] = self.identifier
64
- output["targetFormat"] = self.target_format
65
- output["reason"] = self.reason
66
- return output
67
-
68
-
69
- @dataclass(frozen=True)
70
- class InvalidClassWarning(NeatWarning):
71
- description = "The class {class_name} is invalid and will be skipped. {reason}"
72
- fix = "Check the error message and correct the class."
73
-
74
- class_name: str
75
- reason: str
76
-
77
- def message(self) -> str:
78
- return self.description.format(class_name=self.class_name, reason=self.reason)
79
-
80
- def dump(self) -> dict[str, Any]:
81
- output = super().dump()
82
- output["class_name"] = self.class_name
83
- output["reason"] = self.reason
84
- return output
85
-
86
-
87
- @dataclass(frozen=True)
88
- class InvalidInstanceError(NeatError):
89
- description = "The {type_} with identifier {identifier} is invalid and will be skipped. {reason}"
90
- fix = "Check the error message and correct the instance."
91
-
92
- type_: str
93
- identifier: str
94
- reason: str
95
-
96
- def message(self) -> str:
97
- return self.description.format(type_=self.type_, identifier=self.identifier, reason=self.reason)
98
-
99
- def dump(self) -> dict[str, Any]:
100
- output = super().dump()
101
- output["type"] = self.type_
102
- output["identifier"] = self.identifier
103
- output["reason"] = self.reason
104
- return output
cognite/neat/issues.py DELETED
@@ -1,158 +0,0 @@
1
- import sys
2
- import warnings
3
- from abc import ABC, abstractmethod
4
- from collections import UserList
5
- from collections.abc import Sequence
6
- from dataclasses import dataclass
7
- from functools import total_ordering
8
- from typing import Any, ClassVar, TypeVar
9
- from warnings import WarningMessage
10
-
11
- import pandas as pd
12
- from pydantic_core import PydanticCustomError
13
-
14
- if sys.version_info < (3, 11):
15
- from exceptiongroup import ExceptionGroup
16
- from typing_extensions import Self
17
- else:
18
- from typing import Self
19
-
20
-
21
- @total_ordering
22
- @dataclass(frozen=True)
23
- class NeatIssue(ABC):
24
- description: ClassVar[str]
25
- fix: ClassVar[str]
26
-
27
- def message(self) -> str:
28
- """Return a human-readable message for the issue.
29
-
30
- This is the default implementation, which returns the description.
31
- It is recommended to override this method in subclasses with a more
32
- specific message.
33
- """
34
- return self.description
35
-
36
- @abstractmethod
37
- def dump(self) -> dict[str, Any]:
38
- """Return a dictionary representation of the issue."""
39
- raise NotImplementedError()
40
-
41
- def __lt__(self, other: "NeatIssue") -> bool:
42
- if not isinstance(other, NeatIssue):
43
- return NotImplemented
44
- return (type(self).__name__, self.message()) < (type(other).__name__, other.message())
45
-
46
- def __eq__(self, other: object) -> bool:
47
- if not isinstance(other, NeatIssue):
48
- return NotImplemented
49
- return (type(self).__name__, self.message()) == (type(other).__name__, other.message())
50
-
51
-
52
- @dataclass(frozen=True)
53
- class NeatError(NeatIssue, ABC):
54
- def dump(self) -> dict[str, Any]:
55
- return {"errorType": type(self).__name__}
56
-
57
- def as_exception(self) -> ValueError:
58
- return ValueError(self.message())
59
-
60
- def as_pydantic_exception(self) -> PydanticCustomError:
61
- return PydanticCustomError(
62
- self.__class__.__name__,
63
- self.message(),
64
- dict(description=self.description, fix=self.fix),
65
- )
66
-
67
-
68
- @dataclass(frozen=True)
69
- class NeatWarning(NeatIssue, ABC, UserWarning):
70
- def dump(self) -> dict[str, Any]:
71
- return {"warningType": type(self).__name__}
72
-
73
- @classmethod
74
- def from_warning(cls, warning: WarningMessage) -> "NeatWarning":
75
- return DefaultWarning.from_warning_message(warning)
76
-
77
-
78
- @dataclass(frozen=True)
79
- class DefaultWarning(NeatWarning):
80
- description = "A warning was raised during validation."
81
- fix = "No fix is available."
82
-
83
- warning: str | Warning
84
- category: type[Warning]
85
- source: str | None = None
86
-
87
- def dump(self) -> dict[str, Any]:
88
- output = super().dump()
89
- output["msg"] = str(self.warning)
90
- output["category"] = self.category.__name__
91
- output["source"] = self.source
92
- return output
93
-
94
- @classmethod
95
- def from_warning_message(cls, warning: WarningMessage) -> NeatWarning:
96
- if isinstance(warning.message, NeatWarning):
97
- return warning.message
98
-
99
- return cls(
100
- warning=warning.message,
101
- category=warning.category,
102
- source=warning.source,
103
- )
104
-
105
- def message(self) -> str:
106
- return str(self.warning)
107
-
108
-
109
- T_NeatIssue = TypeVar("T_NeatIssue", bound=NeatIssue)
110
-
111
-
112
- class NeatIssueList(UserList[T_NeatIssue], ABC):
113
- def __init__(self, issues: Sequence[T_NeatIssue] | None = None, title: str | None = None):
114
- super().__init__(issues or [])
115
- self.title = title
116
-
117
- @property
118
- def errors(self) -> Self:
119
- return type(self)([issue for issue in self if isinstance(issue, NeatError)]) # type: ignore[misc]
120
-
121
- @property
122
- def has_errors(self) -> bool:
123
- return any(isinstance(issue, NeatError) for issue in self)
124
-
125
- @property
126
- def warnings(self) -> Self:
127
- return type(self)([issue for issue in self if isinstance(issue, NeatWarning)]) # type: ignore[misc]
128
-
129
- def as_errors(self) -> ExceptionGroup:
130
- return ExceptionGroup(
131
- "Operation failed",
132
- [ValueError(issue.message()) for issue in self if isinstance(issue, NeatError)],
133
- )
134
-
135
- def trigger_warnings(self) -> None:
136
- for warning in [issue for issue in self if isinstance(issue, NeatWarning)]:
137
- warnings.warn(warning, stacklevel=2)
138
-
139
- def to_pandas(self) -> pd.DataFrame:
140
- return pd.DataFrame([issue.dump() for issue in self])
141
-
142
- def _repr_html_(self) -> str | None:
143
- return self.to_pandas()._repr_html_() # type: ignore[operator]
144
-
145
- def as_exception(self) -> "MultiValueError":
146
- return MultiValueError(self.errors)
147
-
148
-
149
- class MultiValueError(ValueError):
150
- """This is a container for multiple errors.
151
-
152
- It is used in the pydantic field_validator/model_validator to collect multiple errors, which
153
- can then be caught in a try-except block and returned as an IssueList.
154
-
155
- """
156
-
157
- def __init__(self, errors: Sequence[T_NeatIssue]):
158
- self.errors = list(errors)
@@ -1,215 +0,0 @@
1
- from typing import cast
2
-
3
- import numpy as np
4
- import pandas as pd
5
- from rdflib import OWL, Graph
6
-
7
- from cognite.neat.rules.models._base import MatchType
8
- from cognite.neat.utils.rdf_ import remove_namespace_from_uri
9
-
10
-
11
- def parse_owl_classes(graph: Graph, language: str = "en") -> list[dict]:
12
- """Parse owl classes from graph to pandas dataframe.
13
-
14
- Args:
15
- graph: Graph containing owl classes
16
- language: Language to use for parsing, by default "en"
17
-
18
- Returns:
19
- Dataframe containing owl classes
20
-
21
- !!! note "Compliant OWL classes"
22
- This makes the method very opinionated, but results in a compliant classes.
23
- """
24
-
25
- query = """
26
- SELECT ?class ?name ?description ?parentClass ?reference ?match ?comment
27
- WHERE {
28
- ?class a owl:Class .
29
- OPTIONAL {?class rdfs:subClassOf ?parentClass }.
30
- OPTIONAL {?class rdfs:label ?name }.
31
- OPTIONAL {?class rdfs:comment ?description} .
32
- FILTER (!isBlank(?class))
33
- FILTER (!bound(?parentClass) || !isBlank(?parentClass))
34
- FILTER (!bound(?name) || LANG(?name) = "" || LANGMATCHES(LANG(?name), "en"))
35
- FILTER (!bound(?description) || LANG(?description) = "" || LANGMATCHES(LANG(?description), "en"))
36
- }
37
- """
38
-
39
- # create raw dataframe
40
-
41
- raw_df = _parse_raw_dataframe(cast(list[tuple], list(graph.query(query.replace("en", language)))))
42
- if raw_df.empty:
43
- return []
44
-
45
- # group values and clean up
46
- processed_df = _clean_up_classes(raw_df)
47
-
48
- # make compliant
49
- processed_df = make_classes_compliant(processed_df)
50
-
51
- # Make Parent Class list elements into string joined with comma
52
- processed_df["Parent Class"] = processed_df["Parent Class"].apply(
53
- lambda x: ", ".join(x) if isinstance(x, list) and x else None
54
- )
55
-
56
- return processed_df.dropna(axis=0, how="all").replace(float("nan"), None).to_dict(orient="records")
57
-
58
-
59
- def _parse_raw_dataframe(query_results: list[tuple]) -> pd.DataFrame:
60
- df = pd.DataFrame(
61
- query_results,
62
- columns=["Class", "Name", "Description", "Parent Class", "Reference", "Match", "Comment"],
63
- )
64
- if df.empty:
65
- return df
66
-
67
- # # remove NaNs
68
- df.replace(np.nan, "", regex=True, inplace=True)
69
-
70
- df.Reference = df.Class
71
- df.Class = df.Class.apply(lambda x: remove_namespace_from_uri(x))
72
- df["Match Type"] = len(df) * [MatchType.exact]
73
- df["Comment"] = len(df) * [None]
74
- df["Parent Class"] = df["Parent Class"].apply(lambda x: remove_namespace_from_uri(x))
75
-
76
- return df
77
-
78
-
79
- def _clean_up_classes(df: pd.DataFrame) -> pd.DataFrame:
80
- clean_list = [
81
- {
82
- "Class": class_,
83
- "Name": group_df["Name"].unique()[0],
84
- "Description": "\n".join(list(group_df.Description.unique())),
85
- "Parent Class": ", ".join(list(group_df["Parent Class"].unique())),
86
- "Reference": group_df["Reference"].unique()[0],
87
- "Match Type": group_df["Match Type"].unique()[0],
88
- "Comment": group_df["Comment"].unique()[0],
89
- }
90
- for class_, group_df in df.groupby("Class")
91
- ]
92
-
93
- df = pd.DataFrame(clean_list)
94
-
95
- # bring NaNs back
96
- df.replace("", None, inplace=True)
97
-
98
- # split Parent Class column back into list
99
- df["Parent Class"] = df["Parent Class"].apply(lambda x: x.split(", ") if isinstance(x, str) else None)
100
-
101
- return df
102
-
103
-
104
- def make_classes_compliant(classes: pd.DataFrame) -> pd.DataFrame:
105
- """Make classes compliant.
106
-
107
- Returns:
108
- Dataframe containing compliant classes
109
-
110
- !!! note "About the compliant classes"
111
- The compliant classes are based on the OWL base ontology, but adapted to NEAT and use in CDF.
112
- One thing to note is that this method would not be able to fix issues with class ids which
113
- are not compliant with the CDF naming convention. For example, if a class id contains a space,
114
- starts with a number, etc. This will cause issues when trying to create the class in CDF.
115
- """
116
-
117
- # Replace empty or non-string values in "Match" column with "exact"
118
- classes["Match Type"] = classes["Match Type"].fillna(MatchType.exact)
119
- classes["Match Type"] = classes["Match Type"].apply(
120
- lambda x: MatchType.exact if not isinstance(x, str) or len(x) == 0 else x
121
- )
122
-
123
- # Replace empty or non-string values in "Comment" column with a default value
124
- classes["Comment"] = classes["Comment"].fillna("Imported from Ontology by NEAT")
125
- classes["Comment"] = classes["Comment"].apply(
126
- lambda x: "Imported from Ontology by NEAT" if not isinstance(x, str) or len(x) == 0 else x
127
- )
128
-
129
- # Add _object_property_class, _data_type_property_class, _thing_class to the dataframe
130
- classes = pd.concat(
131
- [classes, pd.DataFrame([_object_property_class(), _data_type_property_class(), _thing_class()])],
132
- ignore_index=True,
133
- )
134
-
135
- # Reduce length of elements in the "Description" column to 1024 characters
136
- classes["Description"] = classes["Description"].apply(lambda x: x[:1024] if isinstance(x, str) else None)
137
-
138
- # Add missing parent classes to the dataframe
139
- classes = pd.concat(
140
- [classes, pd.DataFrame(_add_parent_class(classes))],
141
- ignore_index=True,
142
- )
143
-
144
- return classes
145
-
146
-
147
- def _object_property_class() -> dict:
148
- return {
149
- "Class": "ObjectProperty",
150
- "Name": None,
151
- "Description": "The class of object properties.",
152
- "Parent Class": None,
153
- "Reference": OWL.ObjectProperty,
154
- "Match Type": MatchType.exact,
155
- "Comment": "Added by NEAT based on owl:ObjectProperty but adapted to NEAT and use in CDF.",
156
- }
157
-
158
-
159
- def _data_type_property_class() -> dict:
160
- return {
161
- "Class": "DatatypeProperty",
162
- "Name": None,
163
- "Description": "The class of data properties.",
164
- "Parent Class": None,
165
- "Reference": OWL.DatatypeProperty,
166
- "Match Type": MatchType.exact,
167
- "Comment": "Added by NEAT based on owl:DatatypeProperty but adapted to NEAT and use in CDF.",
168
- }
169
-
170
-
171
- def _thing_class() -> dict:
172
- return {
173
- "Class": "Thing",
174
- "Name": None,
175
- "Description": "The class of holding class individuals.",
176
- "Parent Class": None,
177
- "Reference": OWL.Thing,
178
- "Match Type": MatchType.exact,
179
- "Comment": (
180
- "Added by NEAT. "
181
- "Imported from OWL base ontology, it is meant for use as a default"
182
- " value type for object properties which miss a declared range."
183
- ),
184
- }
185
-
186
-
187
- def _add_parent_class(df: pd.DataFrame) -> list[dict]:
188
- parent_set = {
189
- item
190
- for sublist in df["Parent Class"].tolist()
191
- if sublist
192
- for item in sublist
193
- if item != "" and item is not None
194
- }
195
- class_set = set(df["Class"].tolist())
196
-
197
- rows = []
198
- for missing_parent_class in parent_set.difference(class_set):
199
- rows += [
200
- {
201
- "Class": missing_parent_class,
202
- "Name": None,
203
- "Description": None,
204
- "Parent Class": None,
205
- "Reference": None,
206
- "Match Type": None,
207
- "Comment": (
208
- "Added by NEAT. "
209
- "This is a parent class that is missing in the ontology. "
210
- "It is added by NEAT to make the ontology compliant with CDF."
211
- ),
212
- }
213
- ]
214
-
215
- return rows