-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NEAT-236] DMS Exporter Support downloading Solution with Enterprise 🧑🧒 #448
Changes from all commits
99fe558
6d2288c
f2d5155
514094c
01919b1
5c071d4
ec27838
6f95f9d
d94a672
02f670b
812f27d
8872b2d
b799253
3281b17
66751fc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
__version__ = "0.76.3" | ||
__version__ = "0.77.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ | |
|
||
from cognite.client import CogniteClient | ||
from cognite.client import data_modeling as dm | ||
from cognite.client.data_classes.data_modeling import DataModelIdentifier | ||
from cognite.client.data_classes.data_modeling import DataModelId, DataModelIdentifier | ||
from cognite.client.data_classes.data_modeling.containers import BTreeIndex, InvertedIndex | ||
from cognite.client.data_classes.data_modeling.views import ( | ||
MultiEdgeConnectionApply, | ||
|
@@ -51,12 +51,14 @@ def __init__( | |
schema: DMSSchema, | ||
read_issues: Sequence[ValidationIssue] | None = None, | ||
metadata: DMSMetadata | None = None, | ||
ref_metadata: DMSMetadata | None = None, | ||
): | ||
# Calling this root schema to distinguish it from | ||
# * User Schema | ||
# * Reference Schema | ||
self.root_schema = schema | ||
self.metadata = metadata | ||
self.ref_metadata = ref_metadata | ||
self.issue_list = IssueList(read_issues) | ||
self._all_containers_by_id = {container.as_id(): container for container in schema.containers} | ||
if self.root_schema.reference: | ||
|
@@ -65,51 +67,87 @@ def __init__( | |
) | ||
|
||
@classmethod | ||
def from_data_model_id(cls, client: CogniteClient, data_model_id: DataModelIdentifier) -> "DMSImporter": | ||
def from_data_model_id( | ||
cls, | ||
client: CogniteClient, | ||
data_model_id: DataModelIdentifier, | ||
reference_model_id: DataModelIdentifier | None = None, | ||
) -> "DMSImporter": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this method we only support getting the latest version. We could have mismatch that for some reason user data model was created on top of reference data model, which version is not latest. So maybe add NOTE. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, you can specify whatever datamodel version you want.
|
||
"""Create a DMSImporter ready to convert the given data model to rules. | ||
|
||
Args: | ||
client: Instantiated CogniteClient to retrieve data model. | ||
reference_model_id: The reference data model to retrieve. This is the data model that | ||
the given data model is built on top of, typically, an enterprise data model. | ||
data_model_id: Data Model to retrieve. | ||
|
||
Returns: | ||
DMSImporter: DMSImporter instance | ||
""" | ||
data_models = client.data_modeling.data_models.retrieve(data_model_id, inline_views=True) | ||
if len(data_models) == 0: | ||
data_model_ids = [data_model_id, reference_model_id] if reference_model_id else [data_model_id] | ||
data_models = client.data_modeling.data_models.retrieve(data_model_ids, inline_views=True) | ||
|
||
user_models = cls._find_model_in_list(data_models, data_model_id) | ||
if len(user_models) == 0: | ||
return cls(DMSSchema(), [issues.importing.NoDataModelError(f"Data model {data_model_id} not found")]) | ||
data_model = data_models.latest_version() | ||
user_model = user_models.latest_version() | ||
|
||
if reference_model_id: | ||
ref_models = cls._find_model_in_list(data_models, reference_model_id) | ||
if len(ref_models) == 0: | ||
return cls( | ||
DMSSchema(), [issues.importing.NoDataModelError(f"Data model {reference_model_id} not found")] | ||
) | ||
ref_model: dm.DataModel[dm.View] | None = ref_models.latest_version() | ||
else: | ||
ref_model = None | ||
|
||
try: | ||
schema = DMSSchema.from_data_model(client, data_model) | ||
schema = DMSSchema.from_data_model(client, user_model, ref_model) | ||
except Exception as e: | ||
return cls(DMSSchema(), [issues.importing.APIError(str(e))]) | ||
|
||
created = ms_to_datetime(data_model.created_time) | ||
updated = ms_to_datetime(data_model.last_updated_time) | ||
metadata = cls._create_metadata_from_model(user_model) | ||
ref_metadata = cls._create_metadata_from_model(ref_model) if ref_model else None | ||
|
||
metadata = cls._create_metadata_from_model(data_model, created, updated) | ||
return cls(schema, [], metadata, ref_metadata) | ||
|
||
return cls(schema, [], metadata) | ||
@classmethod | ||
def _find_model_in_list( | ||
cls, data_models: dm.DataModelList[dm.View], model_id: DataModelIdentifier | ||
) -> dm.DataModelList[dm.View]: | ||
identifier = DataModelId.load(model_id) | ||
return dm.DataModelList[dm.View]( | ||
[ | ||
model | ||
for model in data_models | ||
if (model.space, model.external_id) == (identifier.space, identifier.external_id) | ||
] | ||
) | ||
|
||
@classmethod | ||
def _create_metadata_from_model( | ||
cls, | ||
model: dm.DataModel[dm.View] | dm.DataModelApply, | ||
created: datetime | None = None, | ||
updated: datetime | None = None, | ||
) -> DMSMetadata: | ||
description, creator = DMSMetadata._get_description_and_creator(model.description) | ||
now = datetime.now().replace(microsecond=0) | ||
|
||
if isinstance(model, dm.DataModel): | ||
created = ms_to_datetime(model.created_time) | ||
updated = ms_to_datetime(model.last_updated_time) | ||
else: | ||
now = datetime.now().replace(microsecond=0) | ||
created = now | ||
updated = now | ||
return DMSMetadata( | ||
schema_=SchemaCompleteness.complete, | ||
extension=ExtensionCategory.addition, | ||
space=model.space, | ||
external_id=model.external_id, | ||
name=model.name or model.external_id, | ||
version=model.version or "0.1.0", | ||
updated=updated or now, | ||
created=created or now, | ||
updated=updated, | ||
created=created, | ||
creator=creator, | ||
description=description, | ||
) | ||
|
@@ -160,7 +198,10 @@ def to_rules( | |
# Reference should always be an enterprise model. | ||
reference = DMSRules( | ||
**self._create_rule_components( | ||
ref_model, ref_schema, self._create_default_metadata(ref_schema.views), DataModelType.enterprise | ||
ref_model, | ||
ref_schema, | ||
self.ref_metadata or self._create_default_metadata(ref_schema.views), | ||
DataModelType.enterprise, | ||
) | ||
) | ||
schema_completeness = SchemaCompleteness.extended | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that being explicit with stating reference_mode_id. Later on we can add magic of inference, but my worry is if that we might bump into data models not created by neat that might be derived from having more than one reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is an interesting discussion, will add it to tech debt