Skip to content

Commit ae7b405

Browse files
committed
[Examples] Trait versioning design sketch
Closes #88. As due diligence before going ahead with an implementation, we need to sketch out what a versioned trait package would look like, and how hosts and managers would interact with it. So add a contrived trait package with two versions. The "generated" view classes have been manually created to reflect what the `traitgen` output should be, once implemented. These view classes are then used in a tutorial notebook that describes how one would go about working with versioned traits. This work may be abandoned or adapted in favour of more concrete documentation as the feature is developed. Signed-off-by: David Feltell <[email protected]>
1 parent b356f0e commit ae7b405

File tree

14 files changed

+1804
-0
lines changed

14 files changed

+1804
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""
2+
An example traits schema
3+
"""
4+
5+
# WARNING: This file is auto-generated by openassetio-traitgen, do not edit.
6+
7+
from .v2 import *
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""
2+
An example traits schema
3+
"""
4+
5+
# WARNING: This file is auto-generated by openassetio-traitgen, do not edit.
6+
7+
from . import traits
8+
from . import specifications
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""
2+
Specifications defined in the 'openassetio-example' package.
3+
"""
4+
5+
# WARNING: This file is auto-generated by openassetio-traitgen, do not edit.
6+
7+
from . import example
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
"""
3+
Specification definitions in the 'example' namespace.
4+
5+
Test specifications.
6+
"""
7+
8+
# WARNING: This file is auto-generated by openassetio-traitgen, do not edit.
9+
10+
from openassetio.trait import TraitsData
11+
12+
13+
from .. import traits
14+
15+
16+
17+
class ExampleSpecification:
18+
"""
19+
An example.
20+
Usage: entity
21+
"""
22+
kTraitSet = {
23+
# 'openassetio-example:example.Unchanged'
24+
traits.example.UnchangedTrait.kId,
25+
# 'openassetio-example:example.Updated'
26+
traits.example.UpdatedTrait.kId,
27+
28+
}
29+
30+
def __init__(self, traitsData):
31+
"""
32+
Constructs the specification as a view on the supplied
33+
shared @fqref{TraitsData} "TraitsData" instance.
34+
35+
@param traitsData @fqref{TraitsData} "TraitsData"
36+
37+
@warning Specifications are always a view on the supplied data,
38+
which is held by reference. Any changes made to the data will be
39+
visible to any other specifications or @ref trait "traits" that
40+
wrap the same TraitsData instance.
41+
"""
42+
if not isinstance(traitsData, TraitsData):
43+
raise TypeError("Specifications must be constructed with a TraitsData instance")
44+
self.__data = traitsData
45+
46+
def traitsData(self):
47+
"""
48+
Returns the underlying (shared) @fqref{TraitsData} "TraitsData"
49+
instance held by this specification.
50+
"""
51+
return self.__data
52+
53+
@classmethod
54+
def create(cls):
55+
"""
56+
Returns a new instance of the Specification, holding a new
57+
@fqref{TraitsData} "TraitsData" instance, pre-populated with all
58+
of the specifications traits.
59+
"""
60+
data = TraitsData(cls.kTraitSet)
61+
return cls(data)
62+
63+
64+
def unchangedTrait(self):
65+
"""
66+
Returns the view for the 'openassetio-example:example.Unchanged' trait wrapped around
67+
the data held in this instance.
68+
"""
69+
return traits.example.UnchangedTrait(self.traitsData())
70+
71+
def updatedTrait(self):
72+
"""
73+
Returns the view for the 'openassetio-example:example.Updated' trait wrapped around
74+
the data held in this instance.
75+
"""
76+
return traits.example.UpdatedTrait(self.traitsData())
77+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""
2+
Traits defined in the 'openassetio-example' package.
3+
"""
4+
5+
# WARNING: This file is auto-generated by openassetio-traitgen, do not edit.
6+
7+
from . import example
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
2+
"""
3+
Trait definitions in the 'example' namespace.
4+
5+
Example namespace
6+
"""
7+
8+
# WARNING: This file is auto-generated by openassetio-traitgen, do not edit.
9+
10+
from typing import Union
11+
12+
from openassetio.trait import TraitsData
13+
14+
15+
class RemovedTrait:
16+
"""
17+
An example.
18+
Usage: entity, locale, relationship
19+
"""
20+
kId = "openassetio-example:example.Removed.v1"
21+
22+
def __init__(self, traitsData):
23+
"""
24+
Construct this trait view, wrapping the given data.
25+
26+
@param traitsData @fqref{TraitsData}} "TraitsData" The target
27+
data that holds/will hold the traits properties.
28+
"""
29+
self.__data = traitsData
30+
31+
def isImbued(self):
32+
"""
33+
Checks whether the data this trait has been applied to
34+
actually has this trait.
35+
@return `True` if the underlying data has this trait, `False`
36+
otherwise.
37+
"""
38+
return self.isImbuedTo(self.__data)
39+
40+
@classmethod
41+
def isImbuedTo(cls, traitsData):
42+
"""
43+
Checks whether the given data actually has this trait.
44+
@param traitsData: Data to check for trait.
45+
@return `True` if the underlying data has this trait, `False`
46+
otherwise.
47+
"""
48+
return traitsData.hasTrait(cls.kId)
49+
50+
def imbue(self):
51+
"""
52+
Adds this trait to the held data.
53+
54+
If the data already has this trait, it is a no-op.
55+
"""
56+
self.__data.addTrait(self.kId)
57+
58+
@classmethod
59+
def imbueTo(cls, traitsData):
60+
"""
61+
Adds this trait to the provided data.
62+
63+
If the data already has this trait, it is a no-op.
64+
"""
65+
traitsData.addTrait(cls.kId)
66+
67+
68+
69+
70+
class UnchangedTrait:
71+
"""
72+
An example.
73+
Usage: entity, locale, relationship
74+
"""
75+
kId = "openassetio-example:example.Unchanged.v1"
76+
77+
def __init__(self, traitsData):
78+
"""
79+
Construct this trait view, wrapping the given data.
80+
81+
@param traitsData @fqref{TraitsData}} "TraitsData" The target
82+
data that holds/will hold the traits properties.
83+
"""
84+
self.__data = traitsData
85+
86+
def isImbued(self):
87+
"""
88+
Checks whether the data this trait has been applied to
89+
actually has this trait.
90+
@return `True` if the underlying data has this trait, `False`
91+
otherwise.
92+
"""
93+
return self.isImbuedTo(self.__data)
94+
95+
@classmethod
96+
def isImbuedTo(cls, traitsData):
97+
"""
98+
Checks whether the given data actually has this trait.
99+
@param traitsData: Data to check for trait.
100+
@return `True` if the underlying data has this trait, `False`
101+
otherwise.
102+
"""
103+
return traitsData.hasTrait(cls.kId)
104+
105+
def imbue(self):
106+
"""
107+
Adds this trait to the held data.
108+
109+
If the data already has this trait, it is a no-op.
110+
"""
111+
self.__data.addTrait(self.kId)
112+
113+
@classmethod
114+
def imbueTo(cls, traitsData):
115+
"""
116+
Adds this trait to the provided data.
117+
118+
If the data already has this trait, it is a no-op.
119+
"""
120+
traitsData.addTrait(cls.kId)
121+
122+
123+
124+
125+
class UpdatedTrait:
126+
"""
127+
An example.
128+
Usage: entity, locale, relationship
129+
"""
130+
kId = "openassetio-example:example.Updated.v1"
131+
132+
def __init__(self, traitsData):
133+
"""
134+
Construct this trait view, wrapping the given data.
135+
136+
@param traitsData @fqref{TraitsData}} "TraitsData" The target
137+
data that holds/will hold the traits properties.
138+
"""
139+
self.__data = traitsData
140+
141+
def isImbued(self):
142+
"""
143+
Checks whether the data this trait has been applied to
144+
actually has this trait.
145+
@return `True` if the underlying data has this trait, `False`
146+
otherwise.
147+
"""
148+
return self.isImbuedTo(self.__data)
149+
150+
@classmethod
151+
def isImbuedTo(cls, traitsData):
152+
"""
153+
Checks whether the given data actually has this trait.
154+
@param traitsData: Data to check for trait.
155+
@return `True` if the underlying data has this trait, `False`
156+
otherwise.
157+
"""
158+
return traitsData.hasTrait(cls.kId)
159+
160+
def imbue(self):
161+
"""
162+
Adds this trait to the held data.
163+
164+
If the data already has this trait, it is a no-op.
165+
"""
166+
self.__data.addTrait(self.kId)
167+
168+
@classmethod
169+
def imbueTo(cls, traitsData):
170+
"""
171+
Adds this trait to the provided data.
172+
173+
If the data already has this trait, it is a no-op.
174+
"""
175+
traitsData.addTrait(cls.kId)
176+
177+
178+
def setPropertyToKeep(self, propertyToKeep: str):
179+
"""
180+
Sets the propertyToKeep property.
181+
182+
A property that is unchanged between versions.
183+
"""
184+
if not isinstance(propertyToKeep, str):
185+
raise TypeError("propertyToKeep must be a 'str'.")
186+
self.__data.setTraitProperty(self.kId, "propertyToKeep", propertyToKeep)
187+
188+
def getPropertyToKeep(self, defaultValue: str=None) -> Union[str, None]:
189+
"""
190+
Gets the value of the propertyToKeep property or the supplied default.
191+
192+
A property that is unchanged between versions.
193+
"""
194+
value = self.__data.getTraitProperty(self.kId, "propertyToKeep")
195+
if value is None:
196+
return defaultValue
197+
198+
if not isinstance(value, str):
199+
if defaultValue is None:
200+
raise TypeError(f"Invalid stored value type: '{type(value).__name__}' should be 'str'.")
201+
return defaultValue
202+
return value
203+
204+
def setPropertyToRemove(self, propertyToRemove: bool):
205+
"""
206+
Sets the propertyToRemove property.
207+
208+
A defunct property that should be removed in the next version.
209+
"""
210+
if not isinstance(propertyToRemove, bool):
211+
raise TypeError("propertyToRemove must be a 'bool'.")
212+
self.__data.setTraitProperty(self.kId, "propertyToRemove", propertyToRemove)
213+
214+
def getPropertyToRemove(self, defaultValue: bool=None) -> Union[bool, None]:
215+
"""
216+
Gets the value of the propertyToRemove property or the supplied default.
217+
218+
A defunct property that should be removed in the next version.
219+
"""
220+
value = self.__data.getTraitProperty(self.kId, "propertyToRemove")
221+
if value is None:
222+
return defaultValue
223+
224+
if not isinstance(value, bool):
225+
if defaultValue is None:
226+
raise TypeError(f"Invalid stored value type: '{type(value).__name__}' should be 'bool'.")
227+
return defaultValue
228+
return value
229+
230+
def setPropertyToRename(self, propertyToRename: bool):
231+
"""
232+
Sets the propertyToRename property.
233+
234+
A property that has an inappropriate name and should be renamed
235+
in the next version.
236+
"""
237+
if not isinstance(propertyToRename, bool):
238+
raise TypeError("propertyToRename must be a 'bool'.")
239+
self.__data.setTraitProperty(self.kId, "propertyToRename", propertyToRename)
240+
241+
def getPropertyToRename(self, defaultValue: bool=None) -> Union[bool, None]:
242+
"""
243+
Gets the value of the propertyToRename property or the supplied default.
244+
245+
A property that has an inappropriate name and should be renamed
246+
in the next version.
247+
"""
248+
value = self.__data.getTraitProperty(self.kId, "propertyToRename")
249+
if value is None:
250+
return defaultValue
251+
252+
if not isinstance(value, bool):
253+
if defaultValue is None:
254+
raise TypeError(f"Invalid stored value type: '{type(value).__name__}' should be 'bool'.")
255+
return defaultValue
256+
return value
257+
258+
259+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""
2+
An example traits schema
3+
"""
4+
5+
# WARNING: This file is auto-generated by openassetio-traitgen, do not edit.
6+
7+
from . import traits
8+
from . import specifications
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""
2+
Specifications defined in the 'openassetio-example' package.
3+
"""
4+
5+
# WARNING: This file is auto-generated by openassetio-traitgen, do not edit.
6+
7+
from . import example

0 commit comments

Comments
 (0)