Skip to content

Commit

Permalink
[Docs] Add generic republish notebook
Browse files Browse the repository at this point in the history
Part of OpenAssetIO/OpenAssetIO#31. This notebook came as an appendix
to illustrating usage of `entityTraits` in the original design notebook
for that API method (see previous commit).

However, during review it became apparent that a generic resolve and
republish workflow is a distinct use-case, and not specific to
`entityTraits`. So it was moved to its own notebook.

Signed-off-by: David Feltell <david.feltell@foundry.com>
  • Loading branch information
feltech committed May 10, 2024
1 parent a38d8cf commit 0530d4b
Show file tree
Hide file tree
Showing 3 changed files with 365 additions and 0 deletions.
286 changes: 286 additions & 0 deletions examples/generic_republish.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "07297a3d-048b-496b-adb0-8fdd67316021",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"# Hosts: Generic republishing\n",
"\n",
"\n",
"This notebook presents the rare case where a manager needs to republish entity data without any knowledge of the provenance of the entity. This may be useful for a generic asset introspection and modification tool. Primarily, this notebook is an exploration of advanced interplay between the entity introspection and publishing APIs."
]
},
{
"cell_type": "markdown",
"id": "60bd9de5-64c3-4f15-8824-ff1d94a894d7",
"metadata": {
"editable": true,
"jp-MarkdownHeadingCollapsed": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"## Setup\n",
"\n",
"See \"Hello OpenAssetIO\" notebook for details on how to bootstrap OpenAssetIO. "
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "df703c44ad53b21c",
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-03-13T08:15:00.152634Z",
"start_time": "2024-03-13T08:15:00.141508Z"
}
},
"outputs": [],
"source": [
"from resources import helpers\n",
"\n",
"manager, context = helpers.bootstrap(\"resources/generic_republish/openassetio_config.toml\")"
]
},
{
"cell_type": "markdown",
"id": "1a80594a-b171-49c5-8cfd-00e334759b1e",
"metadata": {
"editable": true,
"slideshow": {
"slide_type": ""
},
"tags": []
},
"source": [
"## Getting started"
]
},
{
"cell_type": "markdown",
"source": [
"In the following examples we're going to ask the manager about the traits it supports with respect to an asset, and use that to determine a publishing workflow, without knowing anything about the entity.\n",
"\n",
"For these examples, we'll make use of the `project_artwork/logos/openassetio` entity in the asset management system. We must first request an `EntityReference` object representing this entity, for use in API queries:"
],
"metadata": {
"collapsed": false
},
"id": "22277554-b477-4600-8c2a-90ee8d5c064e"
},
{
"cell_type": "code",
"outputs": [
{
"data": {
"text/markdown": "> **Result:**\n> `<openassetio.EntityReference bal:///project_artwork/logos/openassetio>`"
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"logo_ref = manager.createEntityReference(\"bal:///project_artwork/logos/openassetio\")\n",
"\n",
"helpers.display_result(repr(logo_ref))"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-03-13T08:15:00.193600Z",
"start_time": "2024-03-13T08:15:00.188399Z"
}
},
"id": "82c3962a-27b5-4375-b4fa-dbd14dcfc93b",
"execution_count": 9
},
{
"cell_type": "markdown",
"source": [
"## Generic resolve and re-publish\n",
"\n",
"A rare use-case is for a tool that blindly resolves, updates, and re-publishes an entity, regardless what type of entity it is. \n",
"\n",
"Such generic re-publishing is discouraged and dangerous. For example, if \"approval\" status is blindly resolved and re-published, the manager may not know how it should handle this properly. A better approach to such a generic tool is to present the traits and their properties to the user to select before re-publishing.\n",
"\n",
"However, such workflows are possible and have their place in a pipeline. This can be accomplished by making use of `entityTraits`, alongside other introspection and publishing methods. The following subsections explore two possible workflows, illustrating how generic re-publishing might be achieved. "
],
"metadata": {
"collapsed": false
},
"id": "9c4274b9aa5f4965"
},
{
"cell_type": "markdown",
"source": [
"### Re-publishing a mutated entity\n",
"\n",
"The following presents an example of blindly updating the display name for any entity. Note that we make use of the fact that managers should silently ignore data that it cannot persist when publishing."
],
"metadata": {
"collapsed": false
},
"id": "92a3d36ca0b4a816"
},
{
"cell_type": "code",
"outputs": [],
"source": [
"from openassetio.access import EntityTraitsAccess, PolicyAccess, ResolveAccess, PublishingAccess\n",
"from openassetio_mediacreation.traits.identity import DisplayNameTrait\n",
"\n",
"# Get the complete trait set of the entity.\n",
"entity_trait_set = manager.entityTraits(logo_ref, EntityTraitsAccess.kRead, context)\n",
"\n",
"# Ensure the manager will accept a publish of this entity with an updated display name.\n",
"[policy_data] = manager.managementPolicy(\n",
" [entity_trait_set | {DisplayNameTrait.kId}], PolicyAccess.kWrite, context)\n",
"\n",
"if not DisplayNameTrait.kId in policy_data.traitSet():\n",
" raise Exception(\"Cannot update display name of this entity\")\n",
"\n",
"# Get all the properties of the given entity.\n",
"data_to_publish = manager.resolve(logo_ref, entity_trait_set, ResolveAccess.kRead, context)\n",
"\n",
"# Any traits without properties, or where the manager cannot provide them, will be missing from the data.\n",
"# We still need to imbue those traits, so that manager knows what kind of entity we are publishing.\n",
"data_to_publish.addTraits(entity_trait_set)\n",
"\n",
"# Create/update the name of the entity.\n",
"DisplayNameTrait(data_to_publish).setName(\"My New Name\")\n",
"\n",
"# Publish it. Any properties we `resolve`d that cannot be re-published will be silently ignored.\n",
"updated_ref = manager.register(logo_ref, data_to_publish, PublishingAccess.kWrite, context)"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-03-13T08:15:00.233940Z",
"start_time": "2024-03-13T08:15:00.195824Z"
}
},
"id": "499f2040f821e2cd",
"execution_count": 10
},
{
"cell_type": "markdown",
"id": "b0f6750002fc94ee",
"metadata": {
"collapsed": false
},
"source": [
"### Re-publishing a minimal entity\n",
"\n",
"The following example dives deeper into the interaction between `entityTraits`, `managementPolicy` and `resolve` for a generic re-publisher. \n",
"\n",
"We want to re-publish a minimal entity (i.e. only the traits absolutely required for the given entity reference), with two new/updated traits. One of the traits, `BearerTokenTrait`, might not be supported, and the other trait, `LocatableContentTrait`, might have its properties dictated by the manager."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "beab2b9a9c071302",
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-03-13T08:15:00.292376Z",
"start_time": "2024-03-13T08:15:00.235128Z"
}
},
"outputs": [],
"source": [
"from openassetio_mediacreation.traits.auth import BearerTokenTrait\n",
"from openassetio_mediacreation.traits.content import LocatableContentTrait\n",
"\n",
"# The minimum set of traits required to publish to this entity reference.\n",
"minimum_trait_set = manager.entityTraits(logo_ref, EntityTraitsAccess.kWrite, context)\n",
"\n",
"# Whatever the minimum trait set is, we know we want to publish a location and auth token.\n",
"desired_trait_set = minimum_trait_set | {BearerTokenTrait.kId, LocatableContentTrait.kId}\n",
"\n",
"# Get the set of traits that have properties the manager can persist.\n",
"[policy_for_desired_traits] = manager.managementPolicy(\n",
" [desired_trait_set], PolicyAccess.kWrite, context)\n",
"\n",
"# Filter down the desired traits to only those that are supported.\n",
"trait_set_to_publish = desired_trait_set & policy_for_desired_traits.traitSet()\n",
"\n",
"# We want to keep (the minimum amount of) data from the previous version, except for the values we're going to\n",
"# provide.\n",
"trait_set_to_keep = trait_set_to_publish - {BearerTokenTrait.kId, LocatableContentTrait.kId}\n",
"\n",
"# Get the properties that we wish to keep from the current version.\n",
"data_to_publish = manager.resolve(logo_ref, trait_set_to_keep, ResolveAccess.kRead, context)\n",
"\n",
"# Any traits without properties, or where the manager cannot provide them, will be missing from the data.\n",
"# We still need to imbue those traits, so that manager knows what kind of entity we are publishing.\n",
"data_to_publish.addTraits(minimum_trait_set)\n",
"\n",
"# Get the manager's policy for dictating trait properties, i.e. which traits the manager can \"drive\" for us.\n",
"[policy_for_derived_traits] = manager.managementPolicy(\n",
" [trait_set_to_publish], PolicyAccess.kManagerDriven, context)\n",
"\n",
"# Check if the manager can derive a location for us.\n",
"if LocatableContentTrait.kId in policy_for_derived_traits.traitSet():\n",
" # Imbue an empty LocatableContentTrait, so that the manager is aware in `preflight` that we intend to publish\n",
" # this trait. We will ask the manager to fill in the value for us before calling `register`.\n",
" LocatableContentTrait.imbueTo(data_to_publish)\n",
"else:\n",
" # If the manager doesn't want to provide a location for entities of this type, use a default.\n",
" LocatableContentTrait(data_to_publish).setLocation(\"file:///tmp/file\")\n",
"\n",
"# Manager might not support BearerTokenTrait.\n",
"if BearerTokenTrait.kId in trait_set_to_publish:\n",
" # BearerTokenTrait is supported, so imbue and configure.\n",
" BearerTokenTrait(data_to_publish).setToken(\"==ZxErn43G\")\n",
"\n",
"# We can now successfully begin the publishing process.\n",
"working_ref = manager.preflight(logo_ref, data_to_publish, PublishingAccess.kWrite, context)\n",
"\n",
"# Check if the manager can provide a location to us.\n",
"if LocatableContentTrait.kId in policy_for_derived_traits.traitSet():\n",
" derived_data = manager.resolve(\n",
" working_ref, {LocatableContentTrait.kId}, ResolveAccess.kManagerDriven, context)\n",
"\n",
" LocatableContentTrait(data_to_publish).setLocation(\n",
" LocatableContentTrait(derived_data).getLocation())\n",
" \n",
"# [Do some work to write the new file...]\n",
"\n",
"# We can now finally publish\n",
"updated_ref = manager.register(logo_ref, data_to_publish, PublishingAccess.kWrite, context)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.18"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
74 changes: 74 additions & 0 deletions examples/resources/generic_republish/bal_database.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"managementPolicy": {
"read": {
"default": {
"openassetio-mediacreation:managementPolicy.Managed": {},
"openassetio-mediacreation:content.LocatableContent": {},
"openassetio-mediacreation:identity.DisplayName": {},
"openassetio-mediacreation:lifecycle.Version": {}
}
},
"write": {
"default": {
"openassetio-mediacreation:managementPolicy.Managed": {},
"openassetio-mediacreation:content.LocatableContent": {},
"openassetio-mediacreation:identity.DisplayName": {}
}
},
"managerDriven": {
"default": {
"openassetio-mediacreation:managementPolicy.Managed": {},
"openassetio-mediacreation:content.LocatableContent": {},
"openassetio-mediacreation:identity.DisplayName": {}
}
}
},
"entities": {
"project_artwork/logos/openassetio": {
"versions": [],
"overrideByAccess": {
"read": {
"traits": {
"openassetio-mediacreation:usage.Entity": {},
"openassetio-mediacreation:twoDimensional.Image": {},
"openassetio-mediacreation:identity.DisplayName": {
"name": "openassetio logo"
},
"openassetio-mediacreation:content.LocatableContent": {
"location": "file:///mnt/shows/artwork/logos/openassetio.png"
},
"openassetio-mediacreation:timeDomain.FrameRanged": {}
}
},
"write": {
"traits": {
"openassetio-mediacreation:usage.Entity": {},
"openassetio-mediacreation:twoDimensional.Image": {},
"openassetio-mediacreation:content.LocatableContent": {
"location": "file:///mnt/shows/artwork/logos/openassetio.png"
}
}
}
}
},
"project_artwork/logos/openassetio/approved": {
"versions": [],
"overrideByAccess": {
"read": {
"traits": {
"openassetio-mediacreation:usage.Entity": {},
"openassetio-mediacreation:twoDimensional.Image": {},
"openassetio-mediacreation:identity.DisplayName": {
"name": "openassetio logo"
},
"openassetio-mediacreation:content.LocatableContent": {
"location": "file:///mnt/shows/artwork/logos/openassetio.png"
},
"openassetio-mediacreation:timeDomain.FrameRanged": {}
}
},
"write": {}
}
}
}
}
5 changes: 5 additions & 0 deletions examples/resources/generic_republish/openassetio_config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[manager]
identifier = "org.openassetio.examples.manager.bal"

[manager.settings]
library_path = "${config_dir}/bal_database.json"

0 comments on commit 0530d4b

Please sign in to comment.