Skip to content

Commit 2f28a79

Browse files
committed
NAS-4254 manage dependent entities graph
1 parent f7f1ace commit 2f28a79

6 files changed

Lines changed: 131 additions & 4 deletions

File tree

gooddata-sdk/gooddata_sdk/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
)
5151
from gooddata_sdk.catalog.user.entity_model.user import CatalogUser
5252
from gooddata_sdk.catalog.user.entity_model.user_group import CatalogUserGroup
53+
from gooddata_sdk.catalog.workspace.content_service import CatalogWorkspaceContent, CatalogWorkspaceContentService
5354
from gooddata_sdk.catalog.workspace.declarative_model.workspace.analytics_model.analytics_model import (
5455
CatalogDeclarativeAnalytics,
5556
)
@@ -66,8 +67,11 @@
6667
CatalogLabel,
6768
)
6869
from gooddata_sdk.catalog.workspace.entity_model.content_objects.metric import CatalogMetric
70+
from gooddata_sdk.catalog.workspace.entity_model.graph_objects.graph import (
71+
CatalogDependentEntitiesRequest,
72+
CatalogEntityIdentifier,
73+
)
6974
from gooddata_sdk.catalog.workspace.entity_model.workspace import CatalogWorkspace
70-
from gooddata_sdk.catalog.workspace.service import CatalogWorkspaceContent, CatalogWorkspaceContentService
7175
from gooddata_sdk.client import GoodDataApiClient
7276
from gooddata_sdk.compute.model.attribute import Attribute
7377
from gooddata_sdk.compute.model.base import ExecModelEntity, ObjId

gooddata-sdk/gooddata_sdk/catalog/base.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# (C) 2022 GoodData Corporation
22
from __future__ import annotations
33

4-
from typing import Any, Dict, Type, TypeVar
4+
from typing import Any, Dict, Optional, Type, TypeVar
55

66
import attr
7+
import cattr
78
from cattrs import structure
89

910
T = TypeVar("T", bound="Base")
@@ -21,12 +22,18 @@ def value_in_allowed(instance: Type[Base], attribute: attr.Attribute, value: str
2122

2223
@attr.s
2324
class Base:
25+
_converter: Optional[cattr.GenConverter] = None
26+
2427
@classmethod
2528
def from_api(cls: Type[T], entity: Dict[str, Any]) -> T:
2629
"""
2730
Creates object from entity passed by client class, which represents it as dictionary.
2831
"""
29-
return structure(entity, cls)
32+
converter = cls._custom_converter()
33+
if converter is not None:
34+
return converter.structure(entity, cls)
35+
else:
36+
return structure(entity, cls)
3037

3138
@classmethod
3239
def from_dict(cls: Type[T], data: Dict[str, Any], camel_case: bool = True) -> T:
@@ -65,3 +72,7 @@ def client_class() -> Any:
6572
def to_api(self) -> Any:
6673
dictionary = self._get_snake_dict()
6774
return self.client_class().from_dict(dictionary, camel_case=False)
75+
76+
@classmethod
77+
def _custom_converter(cls) -> Optional[cattr.GenConverter]:
78+
return cls._converter

gooddata-sdk/gooddata_sdk/catalog/catalog_service_base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def __init__(self, api_client: GoodDataApiClient) -> None:
1616
self._client = api_client
1717
self._entities_api = metadata_apis.EntitiesApi(api_client.metadata_client)
1818
self._layout_api = metadata_apis.LayoutApi(api_client.metadata_client)
19+
self._metadata_actions_api = metadata_apis.ActionsApi(api_client.metadata_client)
1920

2021
def get_organization(self) -> CatalogOrganization:
2122
# The generated client does work properly with redirecting APIs
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# (C) 2022 GoodData Corporation
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# (C) 2022 GoodData Corporation
2+
from __future__ import annotations
3+
4+
from typing import Any, List, Optional, Type
5+
6+
import attr
7+
import cattr
8+
from cattrs.gen import make_dict_structure_fn, make_dict_unstructure_fn, override
9+
10+
from gooddata_metadata_client.model.dependent_entities_edge import DependentEntitiesEdge
11+
from gooddata_metadata_client.model.dependent_entities_graph import DependentEntitiesGraph
12+
from gooddata_metadata_client.model.dependent_entities_node import DependentEntitiesNode
13+
from gooddata_metadata_client.model.dependent_entities_request import DependentEntitiesRequest
14+
from gooddata_metadata_client.model.dependent_entities_response import DependentEntitiesResponse
15+
from gooddata_metadata_client.model.entity_identifier import EntityIdentifier
16+
from gooddata_sdk.catalog.base import Base
17+
18+
19+
@attr.s(auto_attribs=True, kw_only=True)
20+
class GraphBase(Base):
21+
@classmethod
22+
def _custom_converter(cls) -> Optional[cattr.GenConverter]:
23+
if cls._converter is None:
24+
cls._converter = cattr.GenConverter()
25+
unstructured_hook = make_dict_unstructure_fn(
26+
CatalogDependentEntitiesEdge, cls._converter, from_=override(rename="_from")
27+
)
28+
structured_hook = make_dict_structure_fn(
29+
CatalogDependentEntitiesEdge, cls._converter, from_=override(rename="_from")
30+
)
31+
cls._converter.register_unstructure_hook(CatalogDependentEntitiesEdge, unstructured_hook)
32+
cls._converter.register_structure_hook(CatalogDependentEntitiesEdge, structured_hook)
33+
return cls._converter
34+
35+
def to_api(self) -> Any:
36+
"""
37+
to_api method is not supported for dependent entities graph for these reasons:
38+
* there is no endpoint which would require dependent entities as the input
39+
* it would take some effort to change to_api to support
40+
conversion regarding the from attribute (from\\_ -> _from)
41+
"""
42+
return NotImplemented
43+
44+
45+
@attr.s(auto_attribs=True, kw_only=True)
46+
class CatalogDependentEntitiesRequest(Base):
47+
identifiers: List[CatalogEntityIdentifier] = attr.field(factory=list)
48+
49+
@staticmethod
50+
def client_class() -> Type[DependentEntitiesRequest]:
51+
return DependentEntitiesRequest
52+
53+
54+
@attr.s(auto_attribs=True, kw_only=True)
55+
class CatalogDependentEntitiesResponse(GraphBase):
56+
graph: CatalogDependentEntitiesGraph
57+
58+
@staticmethod
59+
def client_class() -> Type[DependentEntitiesResponse]:
60+
return DependentEntitiesResponse
61+
62+
63+
@attr.s(auto_attribs=True, kw_only=True)
64+
class CatalogDependentEntitiesGraph(GraphBase):
65+
nodes: List[CatalogDependentEntitiesNode] = attr.field(factory=list)
66+
edges: List[CatalogDependentEntitiesEdge] = attr.field(factory=list)
67+
68+
@staticmethod
69+
def client_class() -> Type[DependentEntitiesGraph]:
70+
return DependentEntitiesGraph
71+
72+
73+
@attr.s(auto_attribs=True, kw_only=True)
74+
class CatalogDependentEntitiesNode(Base):
75+
id: str
76+
type: str
77+
title: Optional[str] = None
78+
79+
@staticmethod
80+
def client_class() -> Type[DependentEntitiesNode]:
81+
return DependentEntitiesNode
82+
83+
84+
@attr.s(auto_attribs=True, kw_only=True)
85+
class CatalogDependentEntitiesEdge(GraphBase):
86+
from_: CatalogEntityIdentifier
87+
"""
88+
Beware of the attribute from\\_ which may result in several issues.
89+
Important points:
90+
* from is a Python keyword and cannot be used as a variable name therefore we use from\\_ in dataclass
91+
* client class uses _from naming and as a result to_dict contains _from key
92+
* variable _from results in error
93+
* using from_dict we expect from\\_
94+
"""
95+
to: CatalogEntityIdentifier
96+
97+
@staticmethod
98+
def client_class() -> Type[DependentEntitiesEdge]:
99+
return DependentEntitiesEdge
100+
101+
102+
@attr.s(auto_attribs=True, kw_only=True)
103+
class CatalogEntityIdentifier(Base):
104+
id: str
105+
type: str
106+
107+
@staticmethod
108+
def client_class() -> Type[EntityIdentifier]:
109+
return EntityIdentifier

gooddata-sdk/gooddata_sdk/sdk.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from gooddata_sdk.catalog.organization.service import CatalogOrganizationService
88
from gooddata_sdk.catalog.permission.service import CatalogPermissionService
99
from gooddata_sdk.catalog.user.service import CatalogUserService
10-
from gooddata_sdk.catalog.workspace.service import CatalogWorkspaceContentService, CatalogWorkspaceService
10+
from gooddata_sdk.catalog.workspace.content_service import CatalogWorkspaceContentService
11+
from gooddata_sdk.catalog.workspace.service import CatalogWorkspaceService
1112
from gooddata_sdk.client import GoodDataApiClient
1213
from gooddata_sdk.compute.service import ComputeService
1314
from gooddata_sdk.insight import InsightService

0 commit comments

Comments
 (0)