cognite-neat 0.121.1__py3-none-any.whl → 0.121.2__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-neat might be problematic. Click here for more details.

Files changed (97) hide show
  1. cognite/neat/_version.py +1 -1
  2. cognite/neat/core/_client/_api/statistics.py +91 -0
  3. cognite/neat/core/_client/_api_client.py +2 -0
  4. cognite/neat/core/_client/data_classes/statistics.py +125 -0
  5. cognite/neat/core/_client/testing.py +4 -0
  6. cognite/neat/core/_constants.py +6 -7
  7. cognite/neat/core/_data_model/_constants.py +23 -16
  8. cognite/neat/core/_data_model/_shared.py +33 -17
  9. cognite/neat/core/_data_model/analysis/__init__.py +2 -2
  10. cognite/neat/core/_data_model/analysis/_base.py +186 -183
  11. cognite/neat/core/_data_model/catalog/__init__.py +1 -1
  12. cognite/neat/core/_data_model/exporters/__init__.py +5 -5
  13. cognite/neat/core/_data_model/exporters/_base.py +10 -8
  14. cognite/neat/core/_data_model/exporters/{_rules2dms.py → _data_model2dms.py} +22 -18
  15. cognite/neat/core/_data_model/exporters/{_rules2excel.py → _data_model2excel.py} +51 -51
  16. cognite/neat/core/_data_model/exporters/{_rules2instance_template.py → _data_model2instance_template.py} +4 -4
  17. cognite/neat/core/_data_model/exporters/{_rules2ontology.py → _data_model2ontology.py} +50 -50
  18. cognite/neat/core/_data_model/exporters/{_rules2yaml.py → _data_model2yaml.py} +21 -18
  19. cognite/neat/core/_data_model/importers/__init__.py +6 -6
  20. cognite/neat/core/_data_model/importers/_base.py +8 -6
  21. cognite/neat/core/_data_model/importers/_base_file_reader.py +56 -0
  22. cognite/neat/core/_data_model/importers/{_yaml2rules.py → _dict2data_model.py} +40 -20
  23. cognite/neat/core/_data_model/importers/{_dms2rules.py → _dms2data_model.py} +58 -49
  24. cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/dtdl_converter.py +22 -22
  25. cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/dtdl_importer.py +7 -7
  26. cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/spec.py +3 -3
  27. cognite/neat/core/_data_model/importers/_rdf/_base.py +9 -9
  28. cognite/neat/core/_data_model/importers/_rdf/_imf2rules.py +15 -15
  29. cognite/neat/core/_data_model/importers/_rdf/_inference2rules.py +36 -36
  30. cognite/neat/core/_data_model/importers/_rdf/_owl2rules.py +12 -12
  31. cognite/neat/core/_data_model/importers/_rdf/_shared.py +25 -25
  32. cognite/neat/core/_data_model/importers/{_spreadsheet2rules.py → _spreadsheet2data_model.py} +72 -12
  33. cognite/neat/core/_data_model/models/__init__.py +8 -8
  34. cognite/neat/core/_data_model/models/_base_unverified.py +1 -1
  35. cognite/neat/core/_data_model/models/_base_verified.py +3 -3
  36. cognite/neat/core/_data_model/models/_types.py +6 -6
  37. cognite/neat/core/_data_model/models/conceptual/__init__.py +6 -6
  38. cognite/neat/core/_data_model/models/conceptual/_unverified.py +20 -20
  39. cognite/neat/core/_data_model/models/conceptual/_validation.py +87 -77
  40. cognite/neat/core/_data_model/models/conceptual/_verified.py +53 -51
  41. cognite/neat/core/_data_model/models/data_types.py +2 -2
  42. cognite/neat/core/_data_model/models/entities/__init__.py +8 -8
  43. cognite/neat/core/_data_model/models/entities/_loaders.py +11 -10
  44. cognite/neat/core/_data_model/models/entities/_multi_value.py +5 -5
  45. cognite/neat/core/_data_model/models/entities/_single_value.py +44 -38
  46. cognite/neat/core/_data_model/models/entities/_types.py +9 -3
  47. cognite/neat/core/_data_model/models/entities/_wrapped.py +3 -3
  48. cognite/neat/core/_data_model/models/mapping/_classic2core.py +12 -9
  49. cognite/neat/core/_data_model/models/physical/__init__.py +40 -0
  50. cognite/neat/core/_data_model/models/{dms → physical}/_exporter.py +71 -52
  51. cognite/neat/core/_data_model/models/{dms/_rules_input.py → physical/_unverified.py} +48 -39
  52. cognite/neat/core/_data_model/models/{dms → physical}/_validation.py +13 -11
  53. cognite/neat/core/_data_model/models/{dms/_rules.py → physical/_verified.py} +68 -60
  54. cognite/neat/core/_data_model/transformers/__init__.py +27 -23
  55. cognite/neat/core/_data_model/transformers/_base.py +26 -19
  56. cognite/neat/core/_data_model/transformers/_converters.py +703 -618
  57. cognite/neat/core/_data_model/transformers/_mapping.py +74 -55
  58. cognite/neat/core/_data_model/transformers/_verification.py +63 -54
  59. cognite/neat/core/_instances/extractors/_base.py +1 -1
  60. cognite/neat/core/_instances/extractors/_classic_cdf/_classic.py +8 -8
  61. cognite/neat/core/_instances/extractors/_dms_graph.py +42 -34
  62. cognite/neat/core/_instances/extractors/_mock_graph_generator.py +98 -95
  63. cognite/neat/core/_instances/loaders/_base.py +2 -2
  64. cognite/neat/core/_instances/loaders/_rdf2dms.py +6 -6
  65. cognite/neat/core/_instances/transformers/_base.py +7 -4
  66. cognite/neat/core/_instances/transformers/_value_type.py +2 -6
  67. cognite/neat/core/_issues/_base.py +4 -4
  68. cognite/neat/core/_issues/errors/__init__.py +2 -2
  69. cognite/neat/core/_issues/errors/_wrapper.py +2 -2
  70. cognite/neat/core/_issues/warnings/_models.py +4 -4
  71. cognite/neat/core/_store/__init__.py +3 -3
  72. cognite/neat/core/_store/{_rules_store.py → _data_model.py} +119 -112
  73. cognite/neat/core/_store/{_graph_store.py → _instance.py} +3 -4
  74. cognite/neat/core/_store/_provenance.py +2 -2
  75. cognite/neat/core/_store/exceptions.py +2 -2
  76. cognite/neat/core/_utils/rdf_.py +14 -0
  77. cognite/neat/core/_utils/text.py +1 -1
  78. cognite/neat/session/_base.py +22 -20
  79. cognite/neat/session/_drop.py +2 -2
  80. cognite/neat/session/_inspect.py +5 -5
  81. cognite/neat/session/_mapping.py +8 -6
  82. cognite/neat/session/_read.py +2 -2
  83. cognite/neat/session/_set.py +3 -3
  84. cognite/neat/session/_show.py +11 -11
  85. cognite/neat/session/_state.py +13 -13
  86. cognite/neat/session/_subset.py +12 -9
  87. cognite/neat/session/_template.py +13 -13
  88. cognite/neat/session/_to.py +17 -17
  89. {cognite_neat-0.121.1.dist-info → cognite_neat-0.121.2.dist-info}/METADATA +1 -1
  90. {cognite_neat-0.121.1.dist-info → cognite_neat-0.121.2.dist-info}/RECORD +95 -93
  91. cognite/neat/core/_data_model/exporters/_validation.py +0 -14
  92. cognite/neat/core/_data_model/models/dms/__init__.py +0 -32
  93. /cognite/neat/core/_data_model/catalog/{info-rules-imf.xlsx → conceptual-imf-data-model.xlsx} +0 -0
  94. /cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/__init__.py +0 -0
  95. /cognite/neat/core/_data_model/importers/{_dtdl2rules → _dtdl2data_model}/_unit_lookup.py +0 -0
  96. {cognite_neat-0.121.1.dist-info → cognite_neat-0.121.2.dist-info}/WHEEL +0 -0
  97. {cognite_neat-0.121.1.dist-info → cognite_neat-0.121.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,24 +1,24 @@
1
1
  from ._unverified import (
2
- UnverifiedConceptualClass,
2
+ UnverifiedConcept,
3
3
  UnverifiedConceptualDataModel,
4
4
  UnverifiedConceptualMetadata,
5
5
  UnverifiedConceptualProperty,
6
6
  )
7
- from ._validation import InformationValidation
7
+ from ._validation import ConceptualValidation
8
8
  from ._verified import (
9
- ConceptualClass,
9
+ Concept,
10
10
  ConceptualDataModel,
11
11
  ConceptualMetadata,
12
12
  ConceptualProperty,
13
13
  )
14
14
 
15
15
  __all__ = [
16
- "ConceptualClass",
16
+ "Concept",
17
17
  "ConceptualDataModel",
18
18
  "ConceptualMetadata",
19
19
  "ConceptualProperty",
20
- "InformationValidation",
21
- "UnverifiedConceptualClass",
20
+ "ConceptualValidation",
21
+ "UnverifiedConcept",
22
22
  "UnverifiedConceptualDataModel",
23
23
  "UnverifiedConceptualMetadata",
24
24
  "UnverifiedConceptualProperty",
@@ -13,7 +13,7 @@ from cognite.neat.core._data_model.models._base_unverified import (
13
13
  )
14
14
  from cognite.neat.core._data_model.models.data_types import DataType
15
15
  from cognite.neat.core._data_model.models.entities import (
16
- ClassEntity,
16
+ ConceptEntity,
17
17
  MultiValueTypeInfo,
18
18
  UnknownEntity,
19
19
  load_value_type,
@@ -21,7 +21,7 @@ from cognite.neat.core._data_model.models.entities import (
21
21
  from cognite.neat.core._utils.rdf_ import uri_display_name
22
22
 
23
23
  from ._verified import (
24
- ConceptualClass,
24
+ Concept,
25
25
  ConceptualDataModel,
26
26
  ConceptualMetadata,
27
27
  ConceptualProperty,
@@ -68,7 +68,7 @@ class UnverifiedConceptualMetadata(UnverifiedComponent[ConceptualMetadata]):
68
68
  Unlike namespace, the identifier does not end with "/" or "#".
69
69
 
70
70
  """
71
- return DEFAULT_NAMESPACE[f"data-model/unverified/logical/{self.space}/{self.external_id}/{self.version}"]
71
+ return DEFAULT_NAMESPACE[f"data-model/unverified/conceptual/{self.space}/{self.external_id}/{self.version}"]
72
72
 
73
73
  @property
74
74
  def namespace(self) -> Namespace:
@@ -78,9 +78,9 @@ class UnverifiedConceptualMetadata(UnverifiedComponent[ConceptualMetadata]):
78
78
 
79
79
  @dataclass
80
80
  class UnverifiedConceptualProperty(UnverifiedComponent[ConceptualProperty]):
81
- class_: ClassEntity | str
81
+ concept: ConceptEntity | str
82
82
  property_: str
83
- value_type: DataType | ClassEntity | MultiValueTypeInfo | UnknownEntity | str
83
+ value_type: DataType | ConceptEntity | MultiValueTypeInfo | UnknownEntity | str
84
84
  name: str | None = None
85
85
  description: str | None = None
86
86
  min_count: int | None = None
@@ -100,7 +100,7 @@ class UnverifiedConceptualProperty(UnverifiedComponent[ConceptualProperty]):
100
100
 
101
101
  def dump(self, default_prefix: str, **kwargs) -> dict[str, Any]: # type: ignore
102
102
  output = super().dump()
103
- output["Class"] = ClassEntity.load(self.class_, prefix=default_prefix)
103
+ output["Concept"] = ConceptEntity.load(self.concept, prefix=default_prefix)
104
104
  output["Value Type"] = load_value_type(self.value_type, default_prefix)
105
105
  return output
106
106
 
@@ -112,33 +112,33 @@ class UnverifiedConceptualProperty(UnverifiedComponent[ConceptualProperty]):
112
112
 
113
113
 
114
114
  @dataclass
115
- class UnverifiedConceptualClass(UnverifiedComponent[ConceptualClass]):
116
- class_: ClassEntity | str
115
+ class UnverifiedConcept(UnverifiedComponent[Concept]):
116
+ concept: ConceptEntity | str
117
117
  name: str | None = None
118
118
  description: str | None = None
119
- implements: str | list[ClassEntity] | None = None
119
+ implements: str | list[ConceptEntity] | None = None
120
120
  instance_source: str | None = None
121
121
  neatId: str | URIRef | None = None
122
122
  # linking
123
123
  physical: str | URIRef | None = None
124
124
 
125
125
  @classmethod
126
- def _get_verified_cls(cls) -> type[ConceptualClass]:
127
- return ConceptualClass
126
+ def _get_verified_cls(cls) -> type[Concept]:
127
+ return Concept
128
128
 
129
129
  @property
130
- def class_str(self) -> str:
131
- return str(self.class_)
130
+ def concept_str(self) -> str:
131
+ return str(self.concept)
132
132
 
133
133
  def dump(self, default_prefix: str, **kwargs) -> dict[str, Any]: # type: ignore
134
134
  output = super().dump()
135
- parent: list[ClassEntity] | None = None
135
+ parent: list[ConceptEntity] | None = None
136
136
  if isinstance(self.implements, str):
137
137
  self.implements = self.implements.strip()
138
- parent = [ClassEntity.load(parent, prefix=default_prefix) for parent in self.implements.split(",")]
138
+ parent = [ConceptEntity.load(parent, prefix=default_prefix) for parent in self.implements.split(",")]
139
139
  elif isinstance(self.implements, list):
140
- parent = [ClassEntity.load(parent_, prefix=default_prefix) for parent_ in self.implements]
141
- output["Class"] = ClassEntity.load(self.class_, prefix=default_prefix)
140
+ parent = [ConceptEntity.load(parent_, prefix=default_prefix) for parent_ in self.implements]
141
+ output["Concept"] = ConceptEntity.load(self.concept, prefix=default_prefix)
142
142
  output["Implements"] = parent
143
143
  return output
144
144
 
@@ -147,7 +147,7 @@ class UnverifiedConceptualClass(UnverifiedComponent[ConceptualClass]):
147
147
  class UnverifiedConceptualDataModel(UnverifiedDataModel[ConceptualDataModel]):
148
148
  metadata: UnverifiedConceptualMetadata
149
149
  properties: list[UnverifiedConceptualProperty] = field(default_factory=list)
150
- classes: list[UnverifiedConceptualClass] = field(default_factory=list)
150
+ concepts: list[UnverifiedConcept] = field(default_factory=list)
151
151
  prefixes: dict[str, Namespace] | None = None
152
152
 
153
153
  @classmethod
@@ -160,7 +160,7 @@ class UnverifiedConceptualDataModel(UnverifiedDataModel[ConceptualDataModel]):
160
160
  return dict(
161
161
  Metadata=self.metadata.dump(),
162
162
  Properties=[prop.dump(default_prefix) for prop in self.properties],
163
- Classes=[class_.dump(default_prefix) for class_ in self.classes],
163
+ Concepts=[concept.dump(default_prefix) for concept in self.concepts],
164
164
  Prefixes=self.prefixes,
165
165
  )
166
166
 
@@ -180,7 +180,7 @@ class UnverifiedConceptualDataModel(UnverifiedDataModel[ConceptualDataModel]):
180
180
  "external_id": self.metadata.external_id,
181
181
  "space": self.metadata.space,
182
182
  "version": self.metadata.version,
183
- "classes": len(self.classes),
183
+ "concepts": len(self.concepts),
184
184
  "properties": len(self.properties),
185
185
  }
186
186
 
@@ -1,8 +1,9 @@
1
1
  import itertools
2
2
  from collections import Counter, defaultdict
3
+ from collections.abc import Iterable
3
4
 
4
5
  from cognite.neat.core._data_model._constants import PATTERNS, EntityTypes
5
- from cognite.neat.core._data_model.models.entities import ClassEntity, UnknownEntity
6
+ from cognite.neat.core._data_model.models.entities import ConceptEntity, UnknownEntity
6
7
  from cognite.neat.core._data_model.models.entities._multi_value import MultiValueTypeInfo
7
8
  from cognite.neat.core._issues import IssueList
8
9
  from cognite.neat.core._issues.errors import NeatValueError
@@ -10,7 +11,7 @@ from cognite.neat.core._issues.errors._resources import (
10
11
  ResourceDuplicatedError,
11
12
  ResourceNotDefinedError,
12
13
  )
13
- from cognite.neat.core._issues.warnings._models import UndefinedClassWarning
14
+ from cognite.neat.core._issues.warnings._models import UndefinedConceptWarning
14
15
  from cognite.neat.core._issues.warnings._resources import (
15
16
  ResourceNotDefinedWarning,
16
17
  ResourceRegexViolationWarning,
@@ -18,23 +19,23 @@ from cognite.neat.core._issues.warnings._resources import (
18
19
  from cognite.neat.core._utils.spreadsheet import SpreadsheetRead
19
20
  from cognite.neat.core._utils.text import humanize_collection
20
21
 
21
- from ._verified import ConceptualDataModel
22
+ from ._verified import ConceptualDataModel, ConceptualProperty
22
23
 
23
24
 
24
- class InformationValidation:
25
+ class ConceptualValidation:
25
26
  """This class does all the validation of the Information rules that have dependencies
26
27
  between components."""
27
28
 
28
29
  def __init__(
29
30
  self,
30
- rules: ConceptualDataModel,
31
+ data_model: ConceptualDataModel,
31
32
  read_info_by_spreadsheet: dict[str, SpreadsheetRead] | None = None,
32
33
  ):
33
- self.rules = rules
34
+ self.data_model = data_model
34
35
  self._read_info_by_spreadsheet = read_info_by_spreadsheet or {}
35
- self._metadata = rules.metadata
36
- self._properties = rules.properties
37
- self._classes = rules.classes
36
+ self._metadata = data_model.metadata
37
+ self._properties = data_model.properties
38
+ self._concepts = data_model.concepts
38
39
  self.issue_list = IssueList()
39
40
 
40
41
  def validate(self) -> IssueList:
@@ -42,7 +43,7 @@ class InformationValidation:
42
43
  self._namespaces_reassigned()
43
44
  self._classes_without_properties()
44
45
  self._undefined_classes()
45
- self._parent_class_defined()
46
+ self._parent_concept_defined()
46
47
  self._referenced_classes_exist()
47
48
  self._referenced_value_types_exist()
48
49
  self._regex_compliance_with_dms()
@@ -51,7 +52,7 @@ class InformationValidation:
51
52
 
52
53
  def _duplicated_resources(self) -> None:
53
54
  properties_sheet = self._read_info_by_spreadsheet.get("Properties")
54
- classes_sheet = self._read_info_by_spreadsheet.get("Classes")
55
+ concepts_sheet = self._read_info_by_spreadsheet.get("Concepts")
55
56
 
56
57
  visited = defaultdict(list)
57
58
  for row_no, property_ in enumerate(self._properties):
@@ -75,9 +76,9 @@ class InformationValidation:
75
76
  )
76
77
 
77
78
  visited = defaultdict(list)
78
- for row_no, class_ in enumerate(self._classes):
79
- visited[class_._identifier()].append(
80
- classes_sheet.adjusted_row_number(row_no) if classes_sheet else row_no + 1
79
+ for row_no, concept in enumerate(self._concepts):
80
+ visited[concept._identifier()].append(
81
+ concepts_sheet.adjusted_row_number(row_no) if concepts_sheet else row_no + 1
81
82
  )
82
83
 
83
84
  for identifier, rows in visited.items():
@@ -86,85 +87,85 @@ class InformationValidation:
86
87
  self.issue_list.append(
87
88
  ResourceDuplicatedError(
88
89
  identifier[0],
89
- "class",
90
+ "concept",
90
91
  (f"the Classes sheet at row {humanize_collection(rows)} if data model is read from a spreadsheet."),
91
92
  )
92
93
  )
93
94
 
94
95
  def _classes_without_properties(self) -> None:
95
- defined_classes = {class_.class_ for class_ in self._classes}
96
- referred_classes = {property_.class_ for property_ in self._properties}
97
- class_parent_pairs = self._class_parent_pairs()
96
+ defined_concepts = {concept.concept for concept in self._concepts}
97
+ referred_classes = {property_.concept for property_ in self._properties}
98
+ concept_parent_pairs = self._concept_parent_pairs()
98
99
 
99
- if classes_without_properties := defined_classes.difference(referred_classes):
100
- for class_ in classes_without_properties:
100
+ if concepts_without_properties := defined_concepts.difference(referred_classes):
101
+ for concept in concepts_without_properties:
101
102
  # USE CASE: class has no direct properties and no parents with properties
102
103
  # and it is a class in the prefix of data model, as long as it is in the
103
104
  # same prefix, meaning same space
104
- if not class_parent_pairs[class_] and class_.prefix == self._metadata.prefix:
105
+ if not concept_parent_pairs[concept] and concept.prefix == self._metadata.prefix:
105
106
  self.issue_list.append(
106
107
  ResourceNotDefinedWarning(
107
- resource_type="class",
108
- identifier=class_,
108
+ resource_type="concept",
109
+ identifier=concept,
109
110
  location="Properties sheet",
110
111
  )
111
112
  )
112
113
 
113
114
  def _undefined_classes(self) -> None:
114
- defined_classes = {class_.class_ for class_ in self._classes}
115
- referred_classes = {property_.class_ for property_ in self._properties}
115
+ defined_concept = {concept.concept for concept in self._concepts}
116
+ referred_concepts = {property_.concept for property_ in self._properties}
116
117
 
117
- if undefined_classes := referred_classes.difference(defined_classes):
118
- for class_ in undefined_classes:
118
+ if undefined_concepts := referred_concepts.difference(defined_concept):
119
+ for concept in undefined_concepts:
119
120
  self.issue_list.append(
120
121
  ResourceNotDefinedError(
121
- identifier=class_,
122
- resource_type="class",
123
- location="Classes sheet",
122
+ identifier=concept,
123
+ resource_type="concept",
124
+ location="Concepts sheet",
124
125
  )
125
126
  )
126
127
 
127
- def _parent_class_defined(self) -> None:
128
- """This is a validation to check if the parent class of a class is defined in the classes sheet."""
129
- class_parent_pairs = self._class_parent_pairs()
130
- classes = set(class_parent_pairs.keys())
131
- parents = set(itertools.chain.from_iterable(class_parent_pairs.values()))
128
+ def _parent_concept_defined(self) -> None:
129
+ """This is a validation to check if the parent concept is defined."""
130
+ concept_parent_pairs = self._concept_parent_pairs()
131
+ concepts = set(concept_parent_pairs.keys())
132
+ parents = set(itertools.chain.from_iterable(concept_parent_pairs.values()))
132
133
 
133
- if undefined_parents := parents.difference(classes):
134
+ if undefined_parents := parents.difference(concepts):
134
135
  for parent in undefined_parents:
135
136
  if parent.prefix != self._metadata.prefix:
136
- self.issue_list.append(UndefinedClassWarning(class_id=str(parent)))
137
+ self.issue_list.append(UndefinedConceptWarning(concept_id=str(parent)))
137
138
  else:
138
139
  self.issue_list.append(
139
140
  ResourceNotDefinedWarning(
140
- resource_type="class",
141
+ resource_type="concept",
141
142
  identifier=parent,
142
- location="Classes sheet",
143
+ location="Concepts sheet",
143
144
  )
144
145
  )
145
146
 
146
147
  def _referenced_classes_exist(self) -> None:
147
148
  # needs to be complete for this validation to pass
148
- defined_classes = {class_.class_ for class_ in self._classes}
149
- classes_with_explicit_properties = {property_.class_ for property_ in self._properties}
149
+ defined_concept = {concept.concept for concept in self._concepts}
150
+ classes_with_explicit_properties = {property_.concept for property_ in self._properties}
150
151
 
151
152
  # USE CASE: models are complete
152
- if missing_classes := classes_with_explicit_properties.difference(defined_classes):
153
- for class_ in missing_classes:
153
+ if missing_classes := classes_with_explicit_properties.difference(defined_concept):
154
+ for concept in missing_classes:
154
155
  self.issue_list.append(
155
156
  ResourceNotDefinedWarning(
156
- resource_type="class",
157
- identifier=class_,
158
- location="Classes sheet",
157
+ resource_type="concept",
158
+ identifier=concept,
159
+ location="Concepts sheet",
159
160
  )
160
161
  )
161
162
 
162
163
  def _referenced_value_types_exist(self) -> None:
163
164
  # adding UnknownEntity to the set of defined classes to handle the case where a property references an unknown
164
- defined_classes = {class_.class_ for class_ in self._classes} | {UnknownEntity()}
165
+ defined_classes = {concept.concept for concept in self._concepts} | {UnknownEntity()}
165
166
  referred_object_types = {
166
167
  property_.value_type
167
- for property_ in self.rules.properties
168
+ for property_ in self.data_model.properties
168
169
  if property_.type_ == EntityTypes.object_property
169
170
  }
170
171
 
@@ -173,9 +174,9 @@ class InformationValidation:
173
174
  for missing in missing_value_types:
174
175
  self.issue_list.append(
175
176
  ResourceNotDefinedWarning(
176
- resource_type="class",
177
+ resource_type="concept",
177
178
  identifier=missing,
178
- location="Classes sheet",
179
+ location="Concepts sheet",
179
180
  )
180
181
  )
181
182
 
@@ -183,28 +184,28 @@ class InformationValidation:
183
184
  """Check regex compliance with DMS of properties, classes and value types."""
184
185
 
185
186
  for prop_ in self._properties:
186
- if not PATTERNS.dms_property_id_compliance.match(prop_.property_):
187
+ if not PATTERNS.physical_property_id_compliance.match(prop_.property_):
187
188
  self.issue_list.append(
188
189
  ResourceRegexViolationWarning(
189
190
  prop_.property_,
190
191
  "Property",
191
192
  "Properties sheet, Property column",
192
- PATTERNS.dms_property_id_compliance.pattern,
193
+ PATTERNS.physical_property_id_compliance.pattern,
193
194
  )
194
195
  )
195
- if not PATTERNS.view_id_compliance.match(prop_.class_.suffix):
196
+ if not PATTERNS.view_id_compliance.match(prop_.concept.suffix):
196
197
  self.issue_list.append(
197
198
  ResourceRegexViolationWarning(
198
- prop_.class_,
199
- "Class",
200
- "Properties sheet, Class column",
199
+ prop_.concept,
200
+ "Concept",
201
+ "Properties sheet, Concept column",
201
202
  PATTERNS.view_id_compliance.pattern,
202
203
  )
203
204
  )
204
205
 
205
206
  # Handling Value Type
206
207
  if (
207
- isinstance(prop_.value_type, ClassEntity)
208
+ isinstance(prop_.value_type, ConceptEntity)
208
209
  and prop_.value_type != UnknownEntity()
209
210
  and not PATTERNS.view_id_compliance.match(prop_.value_type.suffix)
210
211
  ):
@@ -219,7 +220,7 @@ class InformationValidation:
219
220
  if isinstance(prop_.value_type, MultiValueTypeInfo):
220
221
  for value_type in prop_.value_type.types:
221
222
  if (
222
- isinstance(prop_.value_type, ClassEntity)
223
+ isinstance(prop_.value_type, ConceptEntity)
223
224
  and prop_.value_type != UnknownEntity()
224
225
  and not PATTERNS.view_id_compliance.match(value_type.suffix)
225
226
  ):
@@ -232,44 +233,44 @@ class InformationValidation:
232
233
  )
233
234
  )
234
235
 
235
- for class_ in self._classes:
236
- if not PATTERNS.view_id_compliance.match(class_.class_.suffix):
236
+ for concepts in self._concepts:
237
+ if not PATTERNS.view_id_compliance.match(concepts.concept.suffix):
237
238
  self.issue_list.append(
238
239
  ResourceRegexViolationWarning(
239
- class_.class_,
240
- "Class",
241
- "Classes sheet, Class column",
240
+ concepts.concept,
241
+ "Concept",
242
+ "Concepts sheet, Class column",
242
243
  PATTERNS.view_id_compliance.pattern,
243
244
  )
244
245
  )
245
246
 
246
- if class_.implements:
247
- for parent in class_.implements:
247
+ if concepts.implements:
248
+ for parent in concepts.implements:
248
249
  if not PATTERNS.view_id_compliance.match(parent.suffix):
249
250
  self.issue_list.append(
250
251
  ResourceRegexViolationWarning(
251
252
  parent,
252
- "Class",
253
- "Classes sheet, Implements column",
253
+ "Concept",
254
+ "Concepts sheet, Implements column",
254
255
  PATTERNS.view_id_compliance.pattern,
255
256
  )
256
257
  )
257
258
 
258
- def _class_parent_pairs(self) -> dict[ClassEntity, list[ClassEntity]]:
259
- class_parent_pairs: dict[ClassEntity, list[ClassEntity]] = {}
260
- classes = self.rules.model_copy(deep=True).classes
259
+ def _concept_parent_pairs(self) -> dict[ConceptEntity, list[ConceptEntity]]:
260
+ concept_parent_pairs: dict[ConceptEntity, list[ConceptEntity]] = {}
261
+ concepts = self.data_model.model_copy(deep=True).concepts
261
262
 
262
- for class_ in classes:
263
- class_parent_pairs[class_.class_] = []
264
- if class_.implements is None:
263
+ for concept in concepts:
264
+ concept_parent_pairs[concept.concept] = []
265
+ if concept.implements is None:
265
266
  continue
266
- class_parent_pairs[class_.class_].extend(class_.implements)
267
+ concept_parent_pairs[concept.concept].extend(concept.implements)
267
268
 
268
- return class_parent_pairs
269
+ return concept_parent_pairs
269
270
 
270
271
  def _namespaces_reassigned(self) -> None:
271
- prefixes = self.rules.prefixes.copy()
272
- prefixes[self.rules.metadata.namespace.prefix] = self.rules.metadata.namespace
272
+ prefixes = self.data_model.prefixes.copy()
273
+ prefixes[self.data_model.metadata.namespace.prefix] = self.data_model.metadata.namespace
273
274
 
274
275
  if len(set(prefixes.values())) != len(prefixes):
275
276
  reused_namespaces = [value for value, count in Counter(prefixes.values()).items() if count > 1]
@@ -282,3 +283,12 @@ class InformationValidation:
282
283
  "\nMake sure that each unique namespace is assigned to a unique prefix"
283
284
  )
284
285
  )
286
+
287
+
288
+ def duplicated_properties(
289
+ properties: Iterable[ConceptualProperty],
290
+ ) -> dict[tuple[ConceptEntity, str], list[tuple[int, ConceptualProperty]]]:
291
+ concept_properties_by_id: dict[tuple[ConceptEntity, str], list[tuple[int, ConceptualProperty]]] = defaultdict(list)
292
+ for prop_no, prop in enumerate(properties):
293
+ concept_properties_by_id[(prop.concept, prop.property_)].append((prop_no, prop))
294
+ return {k: v for k, v in concept_properties_by_id.items() if len(v) > 1}