@@ -313,8 +313,7 @@ def get_asset_by_qualified_name(
313313 raw_json ["entity" ]["attributes" ].update (
314314 raw_json ["entity" ]["relationshipAttributes" ]
315315 )
316- asset = AssetResponse [A ](** raw_json ).entity
317- asset .is_incomplete = False
316+ asset = self .handle_relationships (raw_json )
318317 if not isinstance (asset , asset_type ):
319318 raise NotFoundError (
320319 message = f"Asset with qualifiedName { qualified_name } "
@@ -345,16 +344,7 @@ def get_asset_by_guid(
345344 GET_ENTITY_BY_GUID .format_path_with_params (guid ),
346345 query_params ,
347346 )
348- if (
349- "relationshipAttributes" in raw_json ["entity" ]
350- and raw_json ["entity" ]["relationshipAttributes" ]
351- ):
352- raw_json ["entity" ]["attributes" ].update (
353- raw_json ["entity" ]["relationshipAttributes" ]
354- )
355- raw_json ["entity" ]["relationshipAttributes" ] = {}
356- asset = AssetResponse [A ](** raw_json ).entity
357- asset .is_incomplete = False
347+ asset = self .handle_relationships (raw_json )
358348 if not isinstance (asset , asset_type ):
359349 raise NotFoundError (
360350 message = f"Asset with GUID { guid } is not of the type requested: { asset_type .__name__ } ." ,
@@ -366,6 +356,19 @@ def get_asset_by_guid(
366356 raise NotFoundError (message = ae .user_message , code = ae .code ) from ae
367357 raise ae
368358
359+ def handle_relationships (self , raw_json ):
360+ if (
361+ "relationshipAttributes" in raw_json ["entity" ]
362+ and raw_json ["entity" ]["relationshipAttributes" ]
363+ ):
364+ raw_json ["entity" ]["attributes" ].update (
365+ raw_json ["entity" ]["relationshipAttributes" ]
366+ )
367+ raw_json ["entity" ]["relationshipAttributes" ] = {}
368+ asset = AssetResponse [A ](** raw_json ).entity
369+ asset .is_incomplete = False
370+ return asset
371+
369372 @validate_arguments ()
370373 def retrieve_minimal (self , guid : str , asset_type : Type [A ]) -> A :
371374 return self .get_asset_by_guid (
@@ -602,3 +605,100 @@ def replace_custom_metadata(self, guid: str, custom_metadata: CustomMetadata):
602605 None ,
603606 custom_metadata_request ,
604607 )
608+
609+ @validate_arguments ()
610+ def append_terms (
611+ self ,
612+ asset_type : Type [A ],
613+ terms : list [AtlasGlossaryTerm ],
614+ guid : Optional [str ] = None ,
615+ qualified_name : Optional [str ] = None ,
616+ ) -> A :
617+ if guid :
618+ if qualified_name :
619+ raise ValueError (
620+ "Either guid or qualified_name can be be specified not both"
621+ )
622+ asset = self .get_asset_by_guid (guid = guid , asset_type = asset_type )
623+ elif qualified_name :
624+ asset = self .get_asset_by_qualified_name (
625+ qualified_name = qualified_name , asset_type = asset_type
626+ )
627+ else :
628+ raise ValueError ("Either guid or qualified name must be specified" )
629+ if not terms :
630+ return asset
631+ replacement_terms : list [AtlasGlossaryTerm ] = []
632+ if existing_terms := asset .terms :
633+ replacement_terms .extend (
634+ term for term in existing_terms if term .relationship_status != "DELETED"
635+ )
636+ replacement_terms .extend (terms )
637+ asset .terms = replacement_terms
638+ response = self .upsert (entity = asset )
639+ if assets := response .assets_updated (asset_type = asset_type ):
640+ return assets [0 ]
641+ return asset
642+
643+ @validate_arguments ()
644+ def replace_terms (
645+ self ,
646+ asset_type : Type [A ],
647+ terms : list [AtlasGlossaryTerm ],
648+ guid : Optional [str ] = None ,
649+ qualified_name : Optional [str ] = None ,
650+ ) -> A :
651+ if guid :
652+ if qualified_name :
653+ raise ValueError (
654+ "Either guid or qualified_name can be be specified not both"
655+ )
656+ asset = self .get_asset_by_guid (guid = guid , asset_type = asset_type )
657+ elif qualified_name :
658+ asset = self .get_asset_by_qualified_name (
659+ qualified_name = qualified_name , asset_type = asset_type
660+ )
661+ else :
662+ raise ValueError ("Either guid or qualified name must be specified" )
663+ asset .terms = terms
664+ response = self .upsert (entity = asset )
665+ if assets := response .assets_updated (asset_type = asset_type ):
666+ return assets [0 ]
667+ return asset
668+
669+ @validate_arguments ()
670+ def remove_terms (
671+ self ,
672+ asset_type : Type [A ],
673+ terms : list [AtlasGlossaryTerm ],
674+ guid : Optional [str ] = None ,
675+ qualified_name : Optional [str ] = None ,
676+ ) -> A :
677+ if not terms :
678+ raise ValueError ("A list of terms to remove must be specified" )
679+ if guid :
680+ if qualified_name :
681+ raise ValueError (
682+ "Either guid or qualified_name can be be specified not both"
683+ )
684+ asset = self .get_asset_by_guid (guid = guid , asset_type = asset_type )
685+ elif qualified_name :
686+ asset = self .get_asset_by_qualified_name (
687+ qualified_name = qualified_name , asset_type = asset_type
688+ )
689+ else :
690+ raise ValueError ("Either guid or qualified name must be specified" )
691+ replacement_terms : list [AtlasGlossaryTerm ] = []
692+ guids_to_be_removed = {t .guid for t in terms }
693+ if existing_terms := asset .terms :
694+ replacement_terms .extend (
695+ term
696+ for term in existing_terms
697+ if term .relationship_status != "DELETED"
698+ and term .guid not in guids_to_be_removed
699+ )
700+ asset .terms = replacement_terms
701+ response = self .upsert (entity = asset )
702+ if assets := response .assets_updated (asset_type = asset_type ):
703+ return assets [0 ]
704+ return asset
0 commit comments