Skip to content

Commit e58503a

Browse files
committed
Add remove_terms method to AtlanClient.
1 parent d2aa0d8 commit e58503a

3 files changed

Lines changed: 160 additions & 0 deletions

File tree

pyatlan/client/atlan.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,3 +665,40 @@ def replace_terms(
665665
if assets := response.assets_updated(asset_type=asset_type):
666666
return assets[0]
667667
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

tests/integration/test_client.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,38 @@ def test_replace_all_term(
184184
deleted_terms = [t for t in database.terms if t.relationship_status == "DELETED"]
185185
assert len(deleted_terms) == 1
186186
assert deleted_terms[0].guid == original_term.guid
187+
188+
189+
def test_remove_term(
190+
client: AtlanClient,
191+
make_term: Callable[[str], AtlasGlossaryTerm],
192+
database: Database,
193+
):
194+
original_term = make_term("Term1")
195+
another_term = make_term("Term2")
196+
assert (
197+
database := client.append_terms(
198+
qualified_name=database.qualified_name,
199+
asset_type=Database,
200+
terms=[
201+
AtlasGlossaryTerm.ref_by_guid(guid=original_term.guid),
202+
AtlasGlossaryTerm.ref_by_guid(guid=another_term.guid),
203+
],
204+
)
205+
)
206+
207+
assert (
208+
database := client.remove_terms(
209+
guid=database.guid,
210+
asset_type=Database,
211+
terms=[AtlasGlossaryTerm.ref_by_guid(original_term.guid)],
212+
)
213+
)
214+
215+
database = client.get_asset_by_guid(guid=database.guid, asset_type=Database)
216+
assert len(database.terms) == 2
217+
deleted_terms = [t for t in database.terms if t.relationship_status == "DELETED"]
218+
assert len(deleted_terms) == 1
219+
assert deleted_terms[0].guid == original_term.guid
220+
active_terms = [t for t in database.terms if t.relationship_status != "DELETED"]
221+
assert active_terms[0].guid == another_term.guid

tests/unit/test_client.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,91 @@ def test_replace_terms(
225225
asset := client.replace_terms(guid=guid, asset_type=asset_type, terms=terms)
226226
)
227227
assert asset.terms == terms
228+
229+
230+
@pytest.mark.parametrize(
231+
"guid, qualified_name, asset_type, terms, message",
232+
[
233+
(
234+
None,
235+
None,
236+
Table,
237+
[AtlasGlossaryTerm()],
238+
"Either guid or qualified name must be specified",
239+
),
240+
(
241+
"123",
242+
None,
243+
None,
244+
[AtlasGlossaryTerm()],
245+
"1 validation error for RemoveTerms\\nasset_type\\n none is not an allowed value ",
246+
),
247+
(
248+
"123",
249+
"default/abc",
250+
Table,
251+
[AtlasGlossaryTerm()],
252+
"Either guid or qualified_name can be be specified not both",
253+
),
254+
(
255+
"123",
256+
None,
257+
Table,
258+
None,
259+
"1 validation error for RemoveTerms\\nterms\\n none is not an allowed value ",
260+
),
261+
(
262+
"123",
263+
None,
264+
Table,
265+
[],
266+
"A list of terms to remove must be specified",
267+
),
268+
],
269+
)
270+
def test_remove_terms_with_invalid_parameter_raises_valueerror(
271+
guid,
272+
qualified_name,
273+
asset_type,
274+
terms,
275+
message,
276+
monkeypatch,
277+
):
278+
monkeypatch.setenv("ATLAN_BASE_URL", "https://name.atlan.com")
279+
monkeypatch.setenv("ATLAN_API_KEY", "abkj")
280+
client = AtlanClient()
281+
282+
with pytest.raises(ValueError, match=message):
283+
client.remove_terms(
284+
guid=guid, qualified_name=qualified_name, asset_type=asset_type, terms=terms
285+
)
286+
287+
288+
def test_remove_with_valid_guid_when_terms_present_returns_asset_with_terms_removed(
289+
monkeypatch,
290+
):
291+
monkeypatch.setenv("ATLAN_BASE_URL", "https://name.atlan.com")
292+
monkeypatch.setenv("ATLAN_API_KEY", "abkj")
293+
asset_type = Table
294+
with patch.multiple(
295+
AtlanClient, get_asset_by_guid=DEFAULT, upsert=DEFAULT
296+
) as mock_methods:
297+
table = Table(attributes=Table.Attributes())
298+
exisiting_term = AtlasGlossaryTerm()
299+
exisiting_term.guid = "b4113341-251b-4adc-81fb-2420501c30e6"
300+
other_term = AtlasGlossaryTerm()
301+
other_term.guid = "b267858d-8316-4c41-a56a-6e9b840cef4a"
302+
table.attributes.meanings = [exisiting_term, other_term]
303+
mock_methods["get_asset_by_guid"].return_value = table
304+
mock_methods["upsert"].return_value.assets_updated.return_value = [table]
305+
client = AtlanClient()
306+
guid = "123"
307+
308+
assert (
309+
asset := client.remove_terms(
310+
guid=guid, asset_type=asset_type, terms=[exisiting_term]
311+
)
312+
)
313+
assert (updated_terms := asset.terms)
314+
assert len(updated_terms) == 1
315+
assert other_term in updated_terms

0 commit comments

Comments
 (0)