Skip to content

Commit 37c4d6b

Browse files
authored
Merge pull request #55 from atlanhq/ACTIV-587
Activ 587
2 parents ce54407 + 14da041 commit 37c4d6b

15 files changed

+3323
-5746
lines changed

HISTORY.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
## 0.0.32 (May 18, 2023)
1+
## 0.0.33 (May 24, 2023)
2+
3+
* Added convenience properties for relationship_attributes
4+
* Rename convenience property for glossary terms from terms to assigned_terms
25

36
* Add create method to Badge
47
* Add integrations tests for CustomMetaData

pyatlan/client/atlan.py

+23-24
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,37 @@
2121

2222
from pyatlan.client.constants import (
2323
ADD_BUSINESS_ATTRIBUTE_BY_ID,
24+
ADD_USER_TO_GROUPS,
2425
BULK_UPDATE,
26+
CHANGE_USER_ROLE,
27+
CREATE_GROUP,
2528
CREATE_TYPE_DEFS,
26-
UPDATE_TYPE_DEFS,
29+
CREATE_USERS,
2730
DELETE_ENTITY_BY_ATTRIBUTE,
2831
DELETE_ENTITY_BY_GUID,
32+
DELETE_GROUP,
2933
DELETE_TYPE_DEF_BY_NAME,
34+
DELETE_USER,
3035
GET_ALL_TYPE_DEFS,
36+
GET_CURRENT_USER,
3137
GET_ENTITY_BY_GUID,
3238
GET_ENTITY_BY_UNIQUE_ATTRIBUTE,
39+
GET_GROUP_MEMBERS,
40+
GET_GROUPS,
3341
GET_LINEAGE,
3442
GET_ROLES,
35-
GET_GROUPS,
43+
GET_USER_GROUPS,
44+
GET_USERS,
3645
INDEX_SEARCH,
3746
PARTIAL_UPDATE_ENTITY_BY_ATTRIBUTE,
47+
REMOVE_USERS_FROM_GROUP,
3848
UPDATE_ENTITY_BY_ATTRIBUTE,
39-
CREATE_GROUP,
40-
DELETE_GROUP,
4149
UPDATE_GROUP,
42-
GET_GROUP_MEMBERS,
43-
REMOVE_USERS_FROM_GROUP,
44-
GET_USERS,
45-
CREATE_USERS,
50+
UPDATE_TYPE_DEFS,
4651
UPDATE_USER,
47-
DELETE_USER,
48-
GET_USER_GROUPS,
49-
ADD_USER_TO_GROUPS,
50-
CHANGE_USER_ROLE,
51-
GET_CURRENT_USER,
5252
)
5353
from pyatlan.error import AtlanError, NotFoundError
5454
from pyatlan.exceptions import AtlanServiceException, InvalidRequestException
55-
from pyatlan.model import group
5655
from pyatlan.model.assets import (
5756
Asset,
5857
AtlasGlossary,
@@ -85,10 +84,10 @@
8584
CertificateStatus,
8685
)
8786
from pyatlan.model.group import (
88-
GroupResponse,
8987
AtlanGroup,
90-
CreateGroupResponse,
9188
CreateGroupRequest,
89+
CreateGroupResponse,
90+
GroupResponse,
9291
RemoveFromGroupRequest,
9392
)
9493
from pyatlan.model.lineage import LineageRequest, LineageResponse
@@ -103,11 +102,11 @@
103102
TypeDefResponse,
104103
)
105104
from pyatlan.model.user import (
105+
AddToGroupsRequest,
106106
AtlanUser,
107+
ChangeRoleRequest,
107108
CreateUserRequest,
108109
UserMinimalResponse,
109-
AddToGroupsRequest,
110-
ChangeRoleRequest,
111110
UserResponse,
112111
)
113112
from pyatlan.utils import HTTPStatus, get_logger
@@ -1074,12 +1073,12 @@ def append_terms(
10741073
if not terms:
10751074
return asset
10761075
replacement_terms: list[AtlasGlossaryTerm] = []
1077-
if existing_terms := asset.terms:
1076+
if existing_terms := asset.assigned_terms:
10781077
replacement_terms.extend(
10791078
term for term in existing_terms if term.relationship_status != "DELETED"
10801079
)
10811080
replacement_terms.extend(terms)
1082-
asset.terms = replacement_terms
1081+
asset.assigned_terms = replacement_terms
10831082
response = self.upsert(entity=asset)
10841083
if assets := response.assets_updated(asset_type=asset_type):
10851084
return assets[0]
@@ -1105,7 +1104,7 @@ def replace_terms(
11051104
)
11061105
else:
11071106
raise ValueError("Either guid or qualified name must be specified")
1108-
asset.terms = terms
1107+
asset.assigned_terms = terms
11091108
response = self.upsert(entity=asset)
11101109
if assets := response.assets_updated(asset_type=asset_type):
11111110
return assets[0]
@@ -1120,7 +1119,7 @@ def remove_terms(
11201119
qualified_name: Optional[str] = None,
11211120
) -> A:
11221121
if not terms:
1123-
raise ValueError("A list of terms to remove must be specified")
1122+
raise ValueError("A list of assigned_terms to remove must be specified")
11241123
if guid:
11251124
if qualified_name:
11261125
raise ValueError(
@@ -1135,14 +1134,14 @@ def remove_terms(
11351134
raise ValueError("Either guid or qualified name must be specified")
11361135
replacement_terms: list[AtlasGlossaryTerm] = []
11371136
guids_to_be_removed = {t.guid for t in terms}
1138-
if existing_terms := asset.terms:
1137+
if existing_terms := asset.assigned_terms:
11391138
replacement_terms.extend(
11401139
term
11411140
for term in existing_terms
11421141
if term.relationship_status != "DELETED"
11431142
and term.guid not in guids_to_be_removed
11441143
)
1145-
asset.terms = replacement_terms
1144+
asset.assigned_terms = replacement_terms
11461145
response = self.upsert(entity=asset)
11471146
if assets := response.assets_updated(asset_type=asset_type):
11481147
return assets[0]

pyatlan/generator/generate_from_typdefs.py

+31-5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
("quick_sight_dataset_field_type", "QuickSightDatasetFieldType"),
4747
("quick_sight_analysis_status", "QuickSightAnalysisStatus"),
4848
("quick_sight_dataset_import_mode", "QuickSightDatasetImportMode"),
49+
("file_type", "FileType"),
4950
]
5051
ARRAY_REPLACEMENTS = [("array<string>", "set{string}")]
5152

@@ -135,15 +136,40 @@ def merge_them(s, a):
135136
return list(attributes.values())
136137

137138
def add_entity_def(self, entity_defs, name):
139+
def get_ancestor_relationship_defs(
140+
ancetor_name: str, ancestor_relationship_defs
141+
):
142+
ancestor_entity_def = self.entity_defs[ancetor_name]
143+
if not ancestor_entity_def.super_types or not ancetor_name:
144+
return ancestor_relationship_defs
145+
for relationship_def in (
146+
ancestor_entity_def.relationship_attribute_defs or []
147+
):
148+
ancestor_relationship_defs.add(relationship_def["name"])
149+
return get_ancestor_relationship_defs(
150+
ancestor_entity_def.super_types[0]
151+
if ancestor_entity_def.super_types
152+
else "",
153+
ancestor_relationship_defs,
154+
)
155+
138156
entity_def = self.entity_defs[name]
139157
if len(entity_def.super_types) > 1:
140158
entity_def.attribute_defs = self.merge_attributes(entity_def)
141159
names = {attribute_def["name"] for attribute_def in entity_def.attribute_defs}
142-
entity_def.relationship_attribute_defs = [
143-
relationship_def
144-
for relationship_def in entity_def.relationship_attribute_defs
145-
if relationship_def["name"] not in names
146-
]
160+
super_type_relationship_defs = (
161+
get_ancestor_relationship_defs(entity_def.super_types[0], set())
162+
if entity_def.super_types
163+
else set()
164+
)
165+
entity_def.relationship_attribute_defs = list(
166+
{
167+
relationship_def["name"]: relationship_def
168+
for relationship_def in entity_def.relationship_attribute_defs
169+
if relationship_def["name"] not in names
170+
and relationship_def["name"] not in super_type_relationship_defs
171+
}.values()
172+
)
147173
for parent in entity_def.super_types:
148174
if parent not in self.processed:
149175
return

pyatlan/generator/templates/entity.jinja2

+16-26
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@
33
# Based on original code from https://github.com/apache/atlas (under Apache-2.0 license)
44
from __future__ import annotations
55

6-
import sys
7-
from io import StringIO
86
import hashlib
7+
import sys
98
from datetime import datetime
9+
from io import StringIO
1010
from typing import Any, ClassVar, Dict, List, Optional, TypeVar
11+
from urllib.parse import quote, unquote
1112

1213
from pydantic import Field, StrictStr, root_validator, validator
1314

1415
from pyatlan.model.core import (
1516
Announcement,
1617
AtlanObject,
17-
CustomMetadata,
1818
Classification,
19+
CustomMetadata,
1920
Meaning,
2021
)
2122
from pyatlan.model.enums import (
@@ -34,16 +35,17 @@ from pyatlan.model.enums import (
3435
AtlanConnectorType,
3536
CertificateStatus,
3637
EntityStatus,
38+
FileType,
39+
GoogleDatastudioAssetType,
3740
IconType,
3841
KafkaTopicCompressionType,
39-
QuickSightFolderType,
40-
QuickSightDatasetFieldType,
42+
PowerbiEndorsement,
43+
QueryUsernameStrategy,
4144
QuickSightAnalysisStatus,
45+
QuickSightDatasetFieldType,
4246
QuickSightDatasetImportMode,
43-
QueryUsernameStrategy,
47+
QuickSightFolderType,
4448
SourceCostUnitType,
45-
GoogleDatastudioAssetType,
46-
PowerbiEndorsement,
4749
)
4850
from pyatlan.model.internal import AtlasServer, Internal
4951
from pyatlan.model.structs import (
@@ -62,7 +64,7 @@ from pyatlan.model.structs import (
6264
SourceTagAttribute,
6365
)
6466
from pyatlan.utils import next_id, validate_required_fields
65-
from urllib.parse import quote, unquote
67+
6668

6769

6870
def validate_single_required_field(field_names: list[str], values: list[Any]):
@@ -87,26 +89,14 @@ class {{ entity_def.name }}({{super_classes[0]}} {%- if "Asset" in super_classes
8789
{% if entity_def.name == "Referenceable" %}
8890
def __init__(__pydantic_self__, **data:Any)->None:
8991
super().__init__(**data)
90-
__pydantic_self__.__fields_set__.add('type_name')
92+
__pydantic_self__.__fields_set__.update(["attributes", "type_name"])
9193
{% endif %}
9294
def __setattr__(self, name, value):
9395
if name in {{ entity_def.name }}._convience_properties:
9496
return object.__setattr__(self, name, value)
9597
super().__setattr__( name, value)
9698

97-
{{ gen_properties(entity_def.attribute_defs, ["terms"]) }}
98-
99-
@property
100-
def terms(self) -> list[AtlasGlossaryTerm]:
101-
if self.attributes is None:
102-
self.attributes = self.Attributes()
103-
return [] if self.attributes.meanings is None else self.attributes.meanings
104-
105-
@terms.setter
106-
def terms(self, terms: list[AtlasGlossaryTerm]):
107-
if self.attributes is None:
108-
self.attributes = self.Attributes()
109-
self.attributes.meanings = terms
99+
{{ gen_properties(entity_def.attribute_defs + entity_def.relationship_attribute_defs) }}
110100

111101
{%- if entity_def.name == "Referenceable" %}
112102

@@ -125,7 +115,7 @@ class {{ entity_def.name }}({{super_classes[0]}} {%- if "Asset" in super_classes
125115
pass
126116

127117
attributes: '{{entity_def.name}}.Attributes' = Field(
128-
None,
118+
default_factory = lambda : {{entity_def.name}}.Attributes(),
129119
description='Map of attributes in the instance and their values. The specific keys of this map will vary '
130120
'by type, so are described in the sub-types of this schema.\n',
131121
)
@@ -209,7 +199,7 @@ class {{ entity_def.name }}({{super_classes[0]}} {%- if "Asset" in super_classes
209199
description="Status of the relationship (when this is a related entity).\n",
210200
)
211201
meaning_names: Optional[list[str]] = Field(
212-
None, description="Names of terms that have been linked to this asset."
202+
None, description="Names of assigned_terms that have been linked to this asset."
213203
)
214204
meanings: Optional[list[Meaning]] = Field(
215205
None, description="", alias="meanings"
@@ -814,7 +804,7 @@ class {{ entity_def.name }}({{super_classes[0]}} {%- if "Asset" in super_classes
814804
)
815805
{%- endif %}
816806
attributes: '{{entity_def.name}}.Attributes' = Field(
817-
None,
807+
default_factory = lambda: {{entity_def.name}}.Attributes(),
818808
description='Map of attributes in the instance and their values. The specific keys of this map will vary by '
819809
'type, so are described in the sub-types of this schema.\n',
820810
)
+7-9
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
1-
{%- macro gen_properties(attribute_defs, additional_names=[]) %}
1+
{%- macro gen_properties(attribute_defs) %}
22
_convience_properties: ClassVar[list[str]] = [
33
{%- for attribute_def in attribute_defs %}
4-
"{{ attribute_def.name | to_snake_case }}",
5-
{%- endfor %}
6-
{%- for name in additional_names %}
7-
"{{ name }}",
8-
{%- endfor %}]
4+
"{{ 'assigned_terms' if attribute_def.name == 'meanings' else attribute_def.name | to_snake_case }}",
5+
{%- endfor %}]
96

107
{%- for attribute_def in attribute_defs %}
118
{%- set type = attribute_def.typeName | get_type %}
129
{%- set property_type %}{% if attribute_def.isOptional %}Optional[{% endif %}{{type}}{% if attribute_def.isOptional %}]{% endif %}{% endset %}
13-
{%- set property_name = attribute_def.name | to_snake_case %}
10+
{%- set attribute_name = attribute_def.name | to_snake_case %}
11+
{%- set property_name = 'assigned_terms' if attribute_def.name == 'meanings' else attribute_def.name | to_snake_case %}
1412
@property
1513
def {{ property_name }}(self)->{{ property_type }}:
16-
return self.attributes.{{ property_name }}
14+
return self.attributes.{{ attribute_name }}
1715

1816
@{{ property_name }}.setter
1917
def {{ property_name }}(self, {{ property_name }}:{{ property_type }}):
2018
if self.attributes is None:
2119
self.attributes = self.Attributes()
22-
self.attributes.{{ property_name }} = {{ property_name }}
20+
self.attributes.{{ attribute_name }} = {{ property_name }}
2321

2422
{%- endfor %}
2523
{% endmacro %}

0 commit comments

Comments
 (0)