Updating asset
All objects in the SDK that you can update within Atlan implement the builder pattern. This allows you to progressively build-up the object you want to update. In addition, each object provides a method that takes the minimal set of required fields to update that asset, when it already exists in Atlan.
When enriching an asset in Atlan, you only need to specify the information you want to change. Any information you don't include in your update will be left untouched on the asset in Atlan. This way you don't need to:
- try to reproduce the complete asset in your request to do targeted updates to specific attributes
- worry about other changes that may be made to the asset in parallel to the changes you will be making to the asset
Build minimal object needed
For example, to update a glossary term we need to provide the qualifiedName and name of the term, and the GUID of the glossary in which it exists:
- Java
- Python
- Kotlin
- Raw REST API
GlossaryTermBuilder<?,?> termUpdater = GlossaryTerm
.updater("gsNccqJraDZqM6WyGP3ea@FzCMyPR2LxkPFgr8eNGrq", // (1)
"Example Term", // (2)
"b4113341-251b-4adc-81fb-2420501c30e6"); // (3)
- The
qualifiedNameof the existing term, which must match exactly (case-sensitive). Note that for some assets (like terms), this may be a strange-looking Atlan-internal string. - The name of the existing term. This must match exactly (case-sensitive).
- The GUID of the glossary in which the term exists.
from pyatlan.client.atlan import AtlanClient
from pyatlan.model.assets import Announcement, AtlasGlossaryTerm
from pyatlan.model.enums import AnnouncementType, CertificateStatus
client = AtlanClient()
term = AtlasGlossaryTerm.updater(
qualified_name="gsNccqJraDZqM6WyGP3ea@FzCMyPR2LxkPFgr8eNGrq", # (1)
name="Example Term", # (2)
glossary_guid="b4113341-251b-4adc-81fb-2420501c30e6", # (3)
)
- The
qualifiedNameof the existing term, which must match exactly (case-sensitive). Note that for some assets (like terms), this may be a strange-looking Atlan-internal string. - The name of the existing term. This must match exactly (case-sensitive).
- The GUID of the glossary in which the term exists.
val termUpdater = GlossaryTerm
.updater(
"gsNccqJraDZqM6WyGP3ea@FzCMyPR2LxkPFgr8eNGrq", // (1)
"Example Term", // (2)
"b4113341-251b-4adc-81fb-2420501c30e6" // (3)
)
- The
qualifiedNameof the existing term, which must match exactly (case-sensitive). Note that for some assets (like terms), this may be a strange-looking Atlan-internal string. - The name of the existing term. This must match exactly (case-sensitive).
- The GUID of the glossary in which the term exists.
There is nothing specific to do for this step when using the raw APIs—constructing the object is simply what you place in the payload of the API calls in the steps below.
What if I already have an asset (for example, from a search)?
Since you should only include your intended changes, and nothing more, the SDKs provide a convenience method to reduce an asset down to its minimal properties. You should use this method to trim an object in your code down to a starting point for the changes you want to make to that asset:
Java
GlossaryTermBuilder<?,?> termUpdater = existing.trimToRequired(); // (1)
-
Assuming you have an existing asset in a variable called
existing, you can calltrimToRequired()to reduce it to a builder with the minimal properties needed to update that asset.Python
term = existing.trim_to_required() # (1)
- Assuming you have an existing asset in a variable called
existing, you can calltrim_to_required()to reduce it to an object with the minimal properties needed to update that asset.
Enrich before updating
The term object now has the minimal required information for Atlan to update it. Without any additional enrichment, though, there isn't really anything to update...
So first you should enrich the object:
- Java
- Python
- Kotlin
- Raw REST API
GlossaryTerm term = termUpdater // (1)
.certificateStatus(CertificateStatus.VERIFIED) // (2)
.announcementType(AtlanAnnouncementType.INFORMATION) // (3)
.announcementTitle("Imported")
.announcementMessage("This term was imported from ...")
.build(); // (4)
-
We'll create an object we can take actions on from this updater.
-
In this example, we're adding a certificate to the object.
-
Note that you can chain any number of enrichments together. Here we're also adding an announcement to the asset.
-
To persist the enrichment back to the object, we must
build()the builder.Assign the result back
Remember to assign the result of the build() operation back to your original object. Otherwise the result isn't persisted back into any variable! (In this case we're assigning to the term variable back on line 5.)
:::
term.certificate_status = CertificateStatus.VERIFIED # (1)
announcement = Announcement(
announcement_type=AnnouncementType.INFORMATION,
announcement_title="Imported",
announcement_message="This term was imported from ..",
)
term.set_announcement(announcement) # (2)
- In this example, we're adding a certificate to the object.
- In this example, we're adding an announcement to the object.
val term = termUpdater // (1)
.certificateStatus(CertificateStatus.VERIFIED) // (2)
.announcementType(AtlanAnnouncementType.INFORMATION) // (3)
.announcementTitle("Imported")
.announcementMessage("This term was imported from ...")
.build() // (4)
-
We'll create an object we can take actions on from this updater.
-
In this example, we're adding a certificate to the object.
-
Note that you can chain any number of enrichments together. Here we're also adding an announcement to the asset.
-
To persist the enrichment back to the object, we must
build()the builder.Assign the result back
Remember to assign the result of the build() operation back to your original object. Otherwise the result isn't persisted back into any variable! (In this case we're assigning to the term variable back on line 5.)
:::
There is nothing specific to do for this step when using the raw APIs—constructing the object is simply what you place in the payload of the API calls in the steps below.
Update asset from object
You can then actually update the object in Atlan1:
- Java
- Python
- Kotlin
- Raw REST API
AssetMutationResponse response = term.save(client); // (1)
Asset updated = response.getUpdatedAssets().get(0); // (2)
GlossaryTerm term;
if (updated instanceof GlossaryTerm)
-
The
save()method will either update an existing asset (if Atlan already has a term with the same name andqualifiedNamein the same glossary) or create a new asset (if Atlan doesn't have a term with the same name in the same glossary). Because this operation will persist the asset in Atlan, you must provide it anAtlanClientthrough which to connect to the tenant. -
You can distinguish what was created or updated:
getCreatedAssets()lists assets that were createdgetUpdatedAssets()lists assets that were updated
Note that the
save()method always returns objects of typeAsset, though. -
The
Assetclass is a superclass of all assets. So we need to cast to more specific types (likeGlossaryTerm) after verifying the object that was actually returned.
try {
AssetMutationResponse response = term.updateMergingCM(client, false); // (1)
Asset updated = response.getUpdatedAssets().get(0); // (2)
GlossaryTerm term;
if (updated instanceof GlossaryTerm)
} catch (NotFoundException e)
-
The
updateMergingCM()method will only update an existing asset (if Atlan already has an asset of the same type with the same namequalifiedName). Because this operation will persist the asset in Atlan, you must provide it anAtlanClientthrough which to connect to the tenant. Depending on the update behavior you want, you could also use:updateMergingCM(false)to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouchedupdateMergingCM(true)to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing assetupdateReplacingCM(false)to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouchedupdateReplacingCM(true)to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset
-
You can distinguish what was created or updated:
getUpdatedAssets()lists assets that were updated
Note that the
update...()methods always returns objects of typeAsset, though. -
The
Assetclass is a superclass of all assets. So we need to cast to more specific types (likeGlossaryTerm) after verifying the object that was actually returned. -
Since the
update...()methods strictly update (and never create) an asset, if the asset you are trying to update doesn't exist the operation will throw aNotFoundException.
response = client.asset.save(term) # (1)
if updated := response.assets_updated(asset_type=AtlasGlossaryTerm): # (2)
term = updated[0] # (3)
-
The
save(term)method will either update an existing asset (if Atlan already has a term with the same name andqualifiedNamein the same glossary) or (create a new asset, if Atlan doesn't have a term with the same name in the same glossary). -
You can distinguish what was created or updated:
assets_created(asset_type = AtlasGlossaryType)returns a list assets of the specified type that were created.assets_updated(asset_type = AtlasGlossaryType)returns a list assets of the specified type that were updated.
-
If the returned list isn't empty, get the term that was updated.
try:
response = client.asset.update_merging_cm(term) # (1)
if updated := response.assets_updated(asset_type=AtlasGlossaryTerm): # (2)
term = updated[0]
except NotFoundError: # (3)
print("No existing asset to update, so nothing changed or created.")
-
The
update_merging_cm()method will only update an existing asset (if Atlan already has an asset of the same type with the same namequalified_name). Depending on the update behavior you want, you could also use:update_merging_cm(replace_atlan_tags=False)to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouchedupdate_merging_cm(replace_atlan_tags=True)to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing assetupdate_replacing_cm(replace_atlan_tags=False)to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouchedupdate_replacing_cm(replace_atlan_tags=True)to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset
-
You can distinguish what was created or updated:
assets_updated(asset_type = AtlasGlossaryType)returns a list assets of the specified type that were updated.
-
Since the
update...()methods strictly update (and never create) an asset, if the asset you are trying to update doesn't exist the operation will throw aNotFoundError.
val response = term.save(client) // (1)
val updated = response.updatedAssets[0] // (2)
val term = if (updated is GlossaryTerm) updated else null // (3)
-
The
save()method will either update an existing asset (if Atlan already has a term with the same name andqualifiedNamein the same glossary) or create a new asset (if Atlan doesn't have a term with the same name in the same glossary). Because this operation will persist the asset in Atlan, you must provide it anAtlanClientthrough which to connect to the tenant. -
You can distinguish what was created or updated:
createdAssetslists assets that were createdupdatedAssetslists assets that were updated
Note that the
save()method always returns objects of typeAsset, though. -
The
Assetclass is a superclass of all assets. So we need to cast to more specific types (likeGlossaryTerm) after verifying the object that was actually returned.
try {
val response = term.updateMergingCM(client, false) // (1)
val updated = response.updatedAssets[0] // (2)
val term = if (updated is GlossaryTerm) updated else null // (3)
} catch (e: NotFoundException)
-
The
updateMergingCM()method will only update an existing asset (if Atlan already has an asset of the same type with the same namequalifiedName). Because this operation will persist the asset in Atlan, you must provide it anAtlanClientthrough which to connect to the tenant. Depending on the update behavior you want, you could also use:updateMergingCM(false)to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while leaving any Atlan tags on the existing asset untouchedupdateMergingCM(true)to only overwrite any custom metadata provided in your update (leaving anything you don't provide untouched on the existing asset), while replacing any Atlan tags on the existing assetupdateReplacingCM(false)to overwrite all custom metadata on the existing asset with what you're providing in your update, while leaving any Atlan tags on the existing asset untouchedupdateReplacingCM(true)to overwrite all custom metadata on the existing asset with what you're providing in your update, while replacing any Atlan tags on the existing asset
-
You can distinguish what was created or updated:
getUpdatedAssets()lists assets that were updated
Note that the
update...()methods always returns objects of typeAsset, though. -
The
Assetclass is a superclass of all assets. So we need to cast to more specific types (likeGlossaryTerm) after verifying the object that was actually returned. -
Since the
update...()methods strictly update (and never create) an asset, if the asset you are trying to update doesn't exist the operation will throw aNotFoundException.
{
"entities": [ // (1),
"certificateStatus": "VERIFIED", // (6)
"announcementType": "information", // (7)
"announcementTitle": "Imported",
"announcementMessage": "This term was imported from ..."
}
}
]
}
-
All assets must be wrapped in an
entitiesarray. -
You must provide the exact type name for the asset (case-sensitive). For a term, this is
AtlasGlossaryTerm. -
You must provide the exact name of the existing asset (case-sensitive). (Unless you want to change its name, in which case you can provide the new name instead.)
-
You must provide the exact
qualifiedNameof the existing asset (case-sensitive).Must exactly match thequalifiedNameof an existing asset
If this doesn't exactly match the qualifiedName of an existing asset, the API call will instead create a new asset rather than updating an existing one.
:::
5. For most assets, you do not need to re-specify the parent object for an update. However, for glossary assets (like terms), you are required to re-specify the parent glossary.
6. In this example, we're adding a certificate to the object.
7. Note that you can include any number of enrichments together. Here we're also adding an announcement to the asset.
If you use a different capitalization or spelling for the qualifiedName, you may accidentally create a new asset rather than updating the existing one.2
Remove information from asset
As mentioned in Enrich before updating section, only the information in your request will be updated on the object. But what if you want to remove some information that already exists on the asset in Atlan?
- Java
- Python
- Kotlin
- Raw REST API
GlossaryTerm term = termUpdater // (1)
.removeCertificate() // (2)
.removeAnnouncement() // (3)
.build(); // (4)
AssetMutationResponse response = term.save(client); // (5)
Asset updated = response.getUpdatedAssets().get(0); // (6)
GlossaryTerm term;
if (updated instanceof GlossaryTerm)
-
We'll create an object we can take actions on from this updater.
-
In this example, we'll remove any existing certificate from the object in Atlan.
-
Note that you can chain any number of enrichments together. Here we're also removing any announcement from the asset.
-
To persist the enrichment back to the object, we must
build()the builder.Assign the result back
Remember to assign the result of the build() operation back to your original object. Otherwise the result isn't persisted back into any variable! (In this case we're assigning to the term variable back on line 5.)
:::
5. The save() method will either:
- Update an existing asset, if Atlan already has a term with the same name and
qualifiedNamein the same glossary. - Create a new asset, if Atlan doesn't have a term with the same name in the same glossary.
Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant.
-
You can distinguish what was created or updated:
getCreatedAssets()lists assets that were createdgetUpdatedAssets()lists assets that were updated
Note that the
save()method always returns objects of typeAsset, though. -
The
Assetclass is a superclass of all assets. So we need to cast to more specific types (likeGlossaryTerm) after verifying the object that was actually returned.
term.remove_certificate() # (1)
term.remove_announcement() # (2)
response = client.asset.save(term)
if updated := response.assets_updated(asset_type=AtlasGlossaryTerm):
term = updated[0]
- In this example we will remove an existing certificate from any existing certificate from the object.
- In this example we will remove any existing announcement from the object.
var term = termUpdater // (1)
.removeCertificate() // (2)
.removeAnnouncement() // (3)
.build() // (4)
val response = term.save(client) // (5)
val updated = response.updatedAssets[0] // (6)
term = if (updated is GlossaryTerm) updated else null // (7)
-
We'll create an object we can take actions on from this updater.
-
In this example, we'll remove any existing certificate from the object in Atlan.
-
Note that you can chain any number of enrichments together. Here we're also removing any announcement from the asset.
-
To persist the enrichment back to the object, we must
build()the builder.Assign the result back
Remember to assign the result of the build() operation back to your original object. Otherwise the result isn't persisted back into any variable! (In this case we're assigning to the term variable back on line 5.)
:::
5. The save() method will either:
- Update an existing asset, if Atlan already has a term with the same name and
qualifiedNamein the same glossary. - Create a new asset, if Atlan doesn't have a term with the same name in the same glossary.
Because this operation will persist the asset in Atlan, you must provide it an AtlanClient through which to connect to the tenant.
-
You can distinguish what was created or updated:
createdAssetslists assets that were createdupdatedAssetslists assets that were updated
Note that the
save()method always returns objects of typeAsset, though. -
The
Assetclass is a superclass of all assets. So we need to cast to more specific types (likeGlossaryTerm) after verifying the object that was actually returned.
{
"entities": [ // (1),
"certificateStatus": null, // (6)
"certificateStatusMessage": null,
"announcementType": null, // (7)
"announcementTitle": null,
"announcementMessage": null
}
}
]
}
-
All assets must be wrapped in an
entitiesarray. -
You must provide the exact type name for the asset (case-sensitive). For a term, this is
AtlasGlossaryTerm. -
You must provide the exact name of the existing asset (case-sensitive). (Unless you want to change its name, in which case you can provide the new name instead.)
-
You must provide the exact
qualifiedNameof the existing asset (case-sensitive).Must exactly match thequalifiedNameof an existing asset
If this doesn't exactly match the qualifiedName of an existing asset, the API call will instead create a new asset rather than updating an existing one.
:::
5. For most assets, you do not need to re-specify the parent object for an update. However, for glossary assets (like terms), you are required to re-specify the parent glossary.
6. In this example, we're removing any existing certificate information from the object in Atlan (by sending null).
7. Note that you can include any number of enrichments together. Here we're also removing any announcement from the asset.