1#!/pxrpythonsubst
2#
3# Copyright 2020 Pixar
4#
5# Licensed under the Apache License, Version 2.0 (the "Apache License")
6# with the following modification; you may not use this file except in
7# compliance with the Apache License and the following modification to it:
8# Section 6. Trademarks. is deleted and replaced with:
9#
10# 6. Trademarks. This License does not grant permission to use the trade
11#    names, trademarks, service marks, or product names of the Licensor
12#    and its affiliates, except as required to comply with Section 4(c) of
13#    the License and to reproduce the content of the NOTICE file.
14#
15# You may obtain a copy of the Apache License at
16#
17#     http://www.apache.org/licenses/LICENSE-2.0
18#
19# Unless required by applicable law or agreed to in writing, software
20# distributed under the Apache License with the above modification is
21# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22# KIND, either express or implied. See the Apache License for the specific
23# language governing permissions and limitations under the Apache License.
24
25import os, unittest
26from pxr import Plug, Sdf, Usd, Vt, Tf
27
28class TestUsdAppliedAPISchemas(unittest.TestCase):
29    @classmethod
30    def setUpClass(cls):
31        pr = Plug.Registry()
32        testPlugins = pr.RegisterPlugins(os.path.abspath("resources"))
33        assert len(testPlugins) == 1, \
34            "Failed to load expected test plugin"
35        assert testPlugins[0].name == "testUsdAppliedAPISchemas", \
36            "Failed to load expected test plugin"
37        cls.SingleApplyAPIType = \
38            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestSingleApplyAPI")
39        cls.MultiApplyAPIType = \
40            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestMultiApplyAPI")
41        cls.SingleCanApplyAPIType = \
42            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestSingleCanApplyAPI")
43        cls.MultiCanApplyAPIType = \
44            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestMultiCanApplyAPI")
45        cls.NestedInnerSingleApplyAPIType = \
46            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestNestedInnerSingleApplyAPI")
47        cls.NestedOuterSingleApplyAPIType = \
48            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestNestedOuterSingleApplyAPI")
49        cls.NestedCycle1APIType = \
50            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestNestedCycle1API")
51        cls.NestedCycle2APIType = \
52            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestNestedCycle2API")
53        cls.NestedCycle3APIType = \
54            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestNestedCycle3API")
55        cls.AutoAppliedToAPIType = \
56            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestAutoAppliedToAPI")
57        cls.NestedAutoAppliedToAPIType = \
58            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestNestedAutoAppliedToAPI")
59        cls.NestedAutoAppliedToAPIAppliedToPrimType = \
60            Tf.Type(Usd.SchemaBase).FindDerivedByName("TestNestedAutoAppliedToAPIAppliedToPrim")
61
62    def test_SimpleTypedSchemaPrimDefinition(self):
63        """
64        Tests the prim definition for a simple typed schema that has no
65        built-in API schemas
66        """
67        primDef = Usd.SchemaRegistry().FindConcretePrimDefinition(
68            "TestTypedSchema")
69        self.assertTrue(primDef)
70        self.assertEqual(primDef.GetPropertyNames(), ["testAttr", "testRel"])
71        self.assertEqual(primDef.GetAppliedAPISchemas(), [])
72        self.assertEqual(primDef.GetDocumentation(), "Testing typed schema")
73
74        # Verify property specs for named properties.
75        for propName in primDef.GetPropertyNames():
76            self.assertTrue(primDef.GetSchemaPropertySpec(propName))
77
78        # Verify the attribute spec and its fallback value and type
79        testAttr = primDef.GetSchemaAttributeSpec("testAttr")
80        self.assertEqual(testAttr.default, "foo")
81        self.assertEqual(testAttr.typeName.cppTypeName, "std::string")
82
83        # Verify the relationship spec
84        self.assertTrue(primDef.GetSchemaRelationshipSpec("testRel"))
85
86    def test_TypedSchemaWithBuiltinAPISchemas(self):
87        """
88        Tests the prim definition for schema prim type that has API schemas
89        applied to it in its generated schema.
90        """
91
92        # Find the prim definition for the test single apply schema. It has
93        # some properties defined.
94        singleApplyAPIDef = Usd.SchemaRegistry().FindAppliedAPIPrimDefinition(
95            "TestSingleApplyAPI")
96        self.assertTrue(singleApplyAPIDef)
97        self.assertEqual(singleApplyAPIDef.GetAppliedAPISchemas(),
98                         ["TestSingleApplyAPI"])
99        self.assertEqual(singleApplyAPIDef.GetPropertyNames(), [
100            "single:bool_attr", "single:token_attr", "single:relationship"])
101        self.assertEqual(singleApplyAPIDef.GetDocumentation(),
102            "Test single apply API schema")
103
104        # Find the prim definition for the test multi apply schema. It has
105        # some properties defined. Note that the properties in the multi apply
106        # definition are not prefixed yet.
107        multiApplyAPIDef = Usd.SchemaRegistry().FindAppliedAPIPrimDefinition(
108            "TestMultiApplyAPI")
109        self.assertTrue(multiApplyAPIDef)
110        self.assertEqual(multiApplyAPIDef.GetAppliedAPISchemas(), [])
111        self.assertEqual(multiApplyAPIDef.GetPropertyNames(), [
112            "bool_attr", "token_attr", "relationship"])
113        self.assertEqual(multiApplyAPIDef.GetDocumentation(),
114            "Test multi-apply API schema")
115
116        # Find the prim definition for the concrete prim type with built-in
117        # API schemas. You can query its API schemas and it will have properties
118        # from those schemas already.
119        primDef = Usd.SchemaRegistry().FindConcretePrimDefinition(
120            "TestWithBuiltinAppliedSchema")
121        self.assertTrue(primDef)
122        self.assertEqual(primDef.GetAppliedAPISchemas(), [
123            "TestSingleApplyAPI", "TestMultiApplyAPI:builtin"])
124        self.assertEqual(sorted(primDef.GetPropertyNames()), [
125            "multi:builtin:bool_attr",
126            "multi:builtin:relationship",
127            "multi:builtin:token_attr",
128            "single:bool_attr",
129            "single:relationship",
130            "single:token_attr",
131            "testAttr",
132            "testRel"])
133        # Note that prim def documentation does not come from the built-in API
134        # schemas.
135        self.assertEqual(primDef.GetDocumentation(),
136                         "Test with built-in API schemas")
137
138        # Verify property specs for all named properties.
139        for propName in primDef.GetPropertyNames():
140            self.assertTrue(primDef.GetSchemaPropertySpec(propName))
141
142        # Verify fallback value and type for properties defined in the
143        # concrete prim
144        testAttr = primDef.GetSchemaAttributeSpec("testAttr")
145        self.assertEqual(testAttr.default, "foo")
146        self.assertEqual(testAttr.typeName.cppTypeName, "std::string")
147
148        self.assertTrue(primDef.GetSchemaRelationshipSpec("testRel"))
149
150        # Verify fallback value and type for properties from the single applied
151        # schema. These properties will return the same property spec as the
152        # API schema prim definition.
153        singleBoolAttr = primDef.GetSchemaAttributeSpec("single:bool_attr")
154        self.assertEqual(singleBoolAttr,
155            singleApplyAPIDef.GetSchemaAttributeSpec("single:bool_attr"))
156        self.assertEqual(singleBoolAttr.default, True)
157        self.assertEqual(singleBoolAttr.typeName.cppTypeName, "bool")
158
159        singleTokenAttr = primDef.GetSchemaAttributeSpec("single:token_attr")
160        self.assertEqual(singleTokenAttr,
161            singleApplyAPIDef.GetSchemaAttributeSpec("single:token_attr"))
162        self.assertEqual(singleTokenAttr.default, "bar")
163        self.assertEqual(singleTokenAttr.typeName.cppTypeName, "TfToken")
164
165        singleRelationship = primDef.GetSchemaRelationshipSpec(
166            "single:relationship")
167        self.assertTrue(singleRelationship)
168        self.assertEqual(singleRelationship,
169            singleApplyAPIDef.GetSchemaRelationshipSpec("single:relationship"))
170
171        # Verify fallback value and type for properties from the multi applied
172        # schema. These properties will return the same property spec as the
173        # API schema prim definition even the properties on the concrete prim
174        # definion are namespace prefixed.
175        multiTokenAttr = primDef.GetSchemaAttributeSpec(
176            "multi:builtin:token_attr")
177        self.assertEqual(multiTokenAttr,
178            multiApplyAPIDef.GetSchemaAttributeSpec("token_attr"))
179        self.assertEqual(multiTokenAttr.default, "foo")
180        self.assertEqual(multiTokenAttr.typeName.cppTypeName, "TfToken")
181
182        multiRelationship = primDef.GetSchemaRelationshipSpec(
183            "multi:builtin:relationship")
184        self.assertTrue(multiRelationship)
185        self.assertEqual(multiRelationship,
186            multiApplyAPIDef.GetSchemaRelationshipSpec("relationship"))
187
188        # Verify the case where the concrete type overrides a property from
189        # one of its applied API schemas. In this case the property spec from
190        # the concrete prim is returned instead of the property spec from the
191        # API schema.
192        multiBoolAttr = primDef.GetSchemaAttributeSpec(
193            "multi:builtin:bool_attr")
194        apiBoolAttr = multiApplyAPIDef.GetSchemaAttributeSpec("bool_attr")
195        self.assertNotEqual(multiBoolAttr, apiBoolAttr)
196        self.assertEqual(multiBoolAttr.default, False)
197        self.assertEqual(apiBoolAttr.default, True)
198        self.assertEqual(multiBoolAttr.typeName.cppTypeName, "bool")
199        self.assertEqual(apiBoolAttr.typeName.cppTypeName, "bool")
200
201    def test_UntypedPrimOnStage(self):
202        """
203        Tests the fallback properties of untyped prims on a stage when API
204        schemas are applied
205        """
206        stage = Usd.Stage.CreateInMemory()
207
208        # Add a prim with no type. It has no applied schemas or properties.
209        untypedPrim = stage.DefinePrim("/Untyped")
210        self.assertEqual(untypedPrim.GetTypeName(), '')
211        self.assertEqual(untypedPrim.GetAppliedSchemas(), [])
212        self.assertEqual(untypedPrim.GetPrimTypeInfo().GetTypeName(), '')
213        self.assertEqual(untypedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
214                         [])
215        self.assertEqual(untypedPrim.GetPropertyNames(), [])
216
217        # Add an api schema to the prim's metadata.
218        untypedPrim.ApplyAPI(self.SingleApplyAPIType)
219
220        # Prim still has no type but does have applied schemas
221        self.assertEqual(untypedPrim.GetTypeName(), '')
222        self.assertEqual(untypedPrim.GetAppliedSchemas(), ["TestSingleApplyAPI"])
223        self.assertEqual(untypedPrim.GetPrimTypeInfo().GetTypeName(), '')
224        self.assertEqual(untypedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
225                         ["TestSingleApplyAPI"])
226        self.assertTrue(untypedPrim.HasAPI(self.SingleApplyAPIType))
227
228        # The prim has properties from the applied schema and value resolution
229        # returns the applied schema's property fallback value.
230        self.assertEqual(untypedPrim.GetPropertyNames(), [
231            "single:bool_attr", "single:relationship", "single:token_attr"])
232        self.assertEqual(untypedPrim.GetAttribute("single:token_attr").Get(),
233                         "bar")
234
235        # Applied schemas are unable to define fallback metadata values for
236        # prims. Just verifying that no fallback exists for "hidden" here as
237        # a contrast to the other cases below where this metadata fallback will
238        # be defined.
239        self.assertFalse("hidden" in untypedPrim.GetAllMetadata())
240        self.assertIsNone(untypedPrim.GetMetadata("hidden"))
241        self.assertFalse(untypedPrim.HasAuthoredMetadata("hidden"))
242
243        # Untyped prim still has no documentation even with API schemas applied.
244        self.assertIsNone(untypedPrim.GetMetadata("documentation"))
245
246    def test_TypedPrimOnStage(self):
247        """
248        Tests the fallback properties of typed prims on a stage when API
249        schemas are applied when the prim type does not start with API schemas.
250        """
251        stage = Usd.Stage.CreateInMemory()
252
253        # Add a typed prim. It has no API schemas but has properties from its
254        # type schema.
255        typedPrim = stage.DefinePrim("/TypedPrim", "TestTypedSchema")
256        self.assertEqual(typedPrim.GetTypeName(), 'TestTypedSchema')
257        self.assertEqual(typedPrim.GetAppliedSchemas(), [])
258        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
259                         'TestTypedSchema')
260        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
261
262        self.assertEqual(typedPrim.GetPropertyNames(), ["testAttr", "testRel"])
263
264        # Add an api schemas to the prim's metadata.
265        typedPrim.ApplyAPI(self.SingleApplyAPIType)
266        typedPrim.ApplyAPI(self.MultiApplyAPIType, "garply")
267
268        # Prim has the same type and now has API schemas. The properties have
269        # been expanded to include properties from the API schemas
270        self.assertEqual(typedPrim.GetTypeName(), 'TestTypedSchema')
271        self.assertEqual(typedPrim.GetAppliedSchemas(),
272                         ["TestSingleApplyAPI", "TestMultiApplyAPI:garply"])
273        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
274                         'TestTypedSchema')
275        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
276                         ["TestSingleApplyAPI", "TestMultiApplyAPI:garply"])
277
278        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
279        self.assertTrue(typedPrim.HasAPI(self.MultiApplyAPIType))
280        self.assertEqual(typedPrim.GetPropertyNames(), [
281            "multi:garply:bool_attr",
282            "multi:garply:relationship",
283            "multi:garply:token_attr",
284            "single:bool_attr",
285            "single:relationship",
286            "single:token_attr",
287            "testAttr",
288            "testRel"])
289
290        # Property fallback comes from TestSingleApplyAPI
291        attr = typedPrim.GetAttribute("single:token_attr")
292        self.assertEqual(attr.Get(), "bar")
293        self.assertEqual(attr.GetResolveInfo().GetSource(),
294                         Usd.ResolveInfoSourceFallback)
295        # Property fallback comes from TestMultiApplyAPI
296        attr = typedPrim.GetAttribute("multi:garply:bool_attr")
297        self.assertEqual(attr.Get(), True)
298        self.assertEqual(attr.GetResolveInfo().GetSource(),
299                         Usd.ResolveInfoSourceFallback)
300        # Property fallback comes from TestTypedSchema
301        attr = typedPrim.GetAttribute("testAttr")
302        self.assertEqual(attr.Get(), "foo")
303        self.assertEqual(attr.GetResolveInfo().GetSource(),
304                         Usd.ResolveInfoSourceFallback)
305
306        # Metadata "hidden" has a fallback value defined in TestTypedSchema. It
307        # will be returned by GetMetadata and GetAllMetadata but will return
308        # false for queries about whether it's authored
309        self.assertEqual(typedPrim.GetAllMetadata()["hidden"], True)
310        self.assertEqual(typedPrim.GetMetadata("hidden"), True)
311        self.assertFalse(typedPrim.HasAuthoredMetadata("hidden"))
312        self.assertFalse("hidden" in typedPrim.GetAllAuthoredMetadata())
313
314        # Documentation metadata comes from prim type definition even with API
315        # schemas applied.
316        self.assertEqual(typedPrim.GetMetadata("documentation"),
317                         "Testing typed schema")
318
319    def test_TypedPrimsOnStageWithBuiltinAPISchemas(self):
320        """
321        Tests the fallback properties of typed prims on a stage when new API
322        schemas are applied to a prim whose type already has built-in applied
323        API schemas.
324        """
325        stage = Usd.Stage.CreateInMemory()
326
327        # Add a typed prim. It has API schemas already from its prim definition
328        # and has properties from both its type and its APIs.
329        typedPrim = stage.DefinePrim("/TypedPrim", "TestWithBuiltinAppliedSchema")
330        self.assertEqual(typedPrim.GetTypeName(), 'TestWithBuiltinAppliedSchema')
331        self.assertEqual(typedPrim.GetAppliedSchemas(),
332                         ["TestSingleApplyAPI", "TestMultiApplyAPI:builtin"])
333        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
334                         'TestWithBuiltinAppliedSchema')
335        # Note that prim type info does NOT contain the built-in applied API
336        # schemas from the concrete type's prim definition as these are not part
337        # of the type identity.
338        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
339
340        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
341        self.assertTrue(typedPrim.HasAPI(self.MultiApplyAPIType))
342        self.assertEqual(typedPrim.GetPropertyNames(), [
343            "multi:builtin:bool_attr",
344            "multi:builtin:relationship",
345            "multi:builtin:token_attr",
346            "single:bool_attr",
347            "single:relationship",
348            "single:token_attr",
349            "testAttr",
350            "testRel"])
351
352        # Add a new api schemas to the prim's metadata.
353        typedPrim.ApplyAPI(self.MultiApplyAPIType, "garply")
354
355        # Prim has the same type and now has both its original API schemas and
356        # the new one. Note that the new schema was added using an explicit
357        # list op but was still prepended to the original list. Built-in API
358        # schemas cannot be deleted and any authored API schemas will always be
359        # prepended to the built-ins.
360        self.assertEqual(typedPrim.GetTypeName(), 'TestWithBuiltinAppliedSchema')
361        self.assertEqual(typedPrim.GetAppliedSchemas(),
362            ["TestMultiApplyAPI:garply",
363             "TestSingleApplyAPI", "TestMultiApplyAPI:builtin"])
364        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
365                         'TestWithBuiltinAppliedSchema')
366        # Note that prim type info does NOT contain the built-in applied API
367        # schemas from the concrete type's prim definition as these are not part
368        # of the type identity.
369        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
370                         ["TestMultiApplyAPI:garply"])
371
372        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
373        self.assertTrue(typedPrim.HasAPI(self.MultiApplyAPIType))
374
375        # Properties have been expanded to include the new API schema
376        self.assertEqual(typedPrim.GetPropertyNames(), [
377            "multi:builtin:bool_attr",
378            "multi:builtin:relationship",
379            "multi:builtin:token_attr",
380            "multi:garply:bool_attr",
381            "multi:garply:relationship",
382            "multi:garply:token_attr",
383            "single:bool_attr",
384            "single:relationship",
385            "single:token_attr",
386            "testAttr",
387            "testRel"])
388
389        # Property fallback comes from TestSingleApplyAPI
390        attr = typedPrim.GetAttribute("single:token_attr")
391        self.assertEqual(attr.Get(), "bar")
392        self.assertEqual(attr.GetResolveInfo().GetSource(),
393                         Usd.ResolveInfoSourceFallback)
394        # Property fallback comes from TestMultiApplyAPI
395        attr = typedPrim.GetAttribute("multi:garply:bool_attr")
396        self.assertEqual(attr.Get(), True)
397        self.assertEqual(attr.GetResolveInfo().GetSource(),
398                         Usd.ResolveInfoSourceFallback)
399        # Property fallback actually comes from TestWithBuiltinAppliedSchema as
400        # the typed schema overrides this property from its built-in API schema.
401        attr = typedPrim.GetAttribute("multi:builtin:bool_attr")
402        self.assertEqual(attr.Get(), False)
403        self.assertEqual(attr.GetResolveInfo().GetSource(),
404                         Usd.ResolveInfoSourceFallback)
405        # Property fallback comes from TestWithBuiltinAppliedSchema
406        attr = typedPrim.GetAttribute("testAttr")
407        self.assertEqual(attr.Get(), "foo")
408        self.assertEqual(attr.GetResolveInfo().GetSource(),
409                         Usd.ResolveInfoSourceFallback)
410
411        # Metadata "hidden" has a fallback value defined in
412        # TestWithBuiltinAppliedSchema. It will be returned by GetMetadata and
413        # GetAllMetadata but will return false for queries about whether it's
414        # authored
415        self.assertEqual(typedPrim.GetAllMetadata()["hidden"], False)
416        self.assertEqual(typedPrim.GetMetadata("hidden"), False)
417        self.assertFalse(typedPrim.HasAuthoredMetadata("hidden"))
418        self.assertFalse("hidden" in typedPrim.GetAllAuthoredMetadata())
419
420        # Documentation metadata comes from prim type definition even with API
421        # schemas applied.
422        self.assertEqual(typedPrim.GetMetadata("documentation"),
423                         "Test with built-in API schemas")
424
425    def test_TypedPrimsOnStageWithBuiltinReapply(self):
426        """
427        Tests the fallback properties of typed prims on a stage when the same
428        API schemas are applied again to a prim whose type already has applied
429        API schemas.
430        """
431        stage = Usd.Stage.CreateInMemory()
432
433        # Add a typed prim. It has API schemas already from its prim definition
434        # and has properties from both its type and its APIs.
435        typedPrim = stage.DefinePrim("/TypedPrim", "TestWithBuiltinAppliedSchema")
436        self.assertEqual(typedPrim.GetTypeName(), 'TestWithBuiltinAppliedSchema')
437        self.assertEqual(typedPrim.GetAppliedSchemas(),
438                         ["TestSingleApplyAPI", "TestMultiApplyAPI:builtin"])
439        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
440                         'TestWithBuiltinAppliedSchema')
441        # Note that prim type info does NOT contain the built-in applied API
442        # schemas from the concrete type's prim definition as these are not part
443        # of the type identity.
444        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
445
446        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
447        self.assertTrue(typedPrim.HasAPI(self.MultiApplyAPIType))
448        self.assertEqual(typedPrim.GetPropertyNames(), [
449            "multi:builtin:bool_attr",
450            "multi:builtin:relationship",
451            "multi:builtin:token_attr",
452            "single:bool_attr",
453            "single:relationship",
454            "single:token_attr",
455            "testAttr",
456            "testRel"])
457        # Property fallback comes from TestSingleApplyAPI
458        attr = typedPrim.GetAttribute("single:token_attr")
459        self.assertEqual(attr.Get(), "bar")
460        self.assertEqual(attr.GetResolveInfo().GetSource(),
461                         Usd.ResolveInfoSourceFallback)
462        # Property fallback actually comes from TestTypedSchema as the typed
463        # schema overrides this property from its built-in API schema.
464        attr = typedPrim.GetAttribute("multi:builtin:bool_attr")
465        self.assertEqual(attr.Get(), False)
466        self.assertEqual(attr.GetResolveInfo().GetSource(),
467                         Usd.ResolveInfoSourceFallback)
468        # Property fallback comes from TestTypedSchema
469        attr = typedPrim.GetAttribute("testAttr")
470        self.assertEqual(attr.Get(), "foo")
471        self.assertEqual(attr.GetResolveInfo().GetSource(),
472                         Usd.ResolveInfoSourceFallback)
473
474        # Add the built-in api schemas again to the prim's metadata.
475        typedPrim.ApplyAPI(self.MultiApplyAPIType, "builtin")
476        typedPrim.ApplyAPI(self.SingleApplyAPIType)
477
478        # Prim has the same type and now has both its original API schemas and
479        # plus the same schemas again appended to the list (i.e. both schemas
480        # now show up twice).
481        self.assertEqual(typedPrim.GetTypeName(), 'TestWithBuiltinAppliedSchema')
482        self.assertEqual(typedPrim.GetAppliedSchemas(),
483            ["TestMultiApplyAPI:builtin", "TestSingleApplyAPI",
484             "TestSingleApplyAPI", "TestMultiApplyAPI:builtin"])
485        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
486                         'TestWithBuiltinAppliedSchema')
487        # Note that prim type info does NOT contain the built-in applied API
488        # schemas from the concrete type's prim definition as these are not part
489        # of the type identity.
490        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
491                         ["TestMultiApplyAPI:builtin", "TestSingleApplyAPI"])
492
493        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
494        self.assertTrue(typedPrim.HasAPI(self.MultiApplyAPIType))
495
496        # The list of properties hasn't changed as there are no "new" schemas,
497        # however the defaults may have changed.
498        self.assertEqual(typedPrim.GetPropertyNames(), [
499            "multi:builtin:bool_attr",
500            "multi:builtin:relationship",
501            "multi:builtin:token_attr",
502            "single:bool_attr",
503            "single:relationship",
504            "single:token_attr",
505            "testAttr",
506            "testRel"])
507
508        # Property fallback comes from TestSingleApplyAPI - no change
509        attr = typedPrim.GetAttribute("single:token_attr")
510        self.assertEqual(attr.Get(), "bar")
511        self.assertEqual(attr.GetResolveInfo().GetSource(),
512                         Usd.ResolveInfoSourceFallback)
513        # Property fallback has now changed from False to True as the
514        # TestTypedSchema originally overrode the fallback from
515        # TestMultiApplyAPI. But by applying TestMultiApplyAPI again with the
516        # same instance, we've re-overridden the attribute getting the default
517        # from the applied schema.
518        attr = typedPrim.GetAttribute("multi:builtin:bool_attr")
519        self.assertEqual(attr.Get(), True)
520        self.assertEqual(attr.GetResolveInfo().GetSource(),
521                         Usd.ResolveInfoSourceFallback)
522        # Property fallback comes from TestTypedSchema - no change
523        attr = typedPrim.GetAttribute("testAttr")
524        self.assertEqual(attr.Get(), "foo")
525        self.assertEqual(attr.GetResolveInfo().GetSource(),
526                         Usd.ResolveInfoSourceFallback)
527
528        # Prim metadata is unchanged from the case above as there is still
529        # no way for applied API schemas to impart prim metadata defaults.
530        self.assertEqual(typedPrim.GetAllMetadata()["hidden"], False)
531        self.assertEqual(typedPrim.GetMetadata("hidden"), False)
532        self.assertFalse(typedPrim.HasAuthoredMetadata("hidden"))
533        self.assertFalse("hidden" in typedPrim.GetAllAuthoredMetadata())
534
535        # Documentation metadata comes from prim type definition even with API
536        # schemas applied.
537        self.assertEqual(typedPrim.GetMetadata("documentation"),
538                         "Test with built-in API schemas")
539
540    @unittest.skipIf(Tf.GetEnvSetting('USD_DISABLE_AUTO_APPLY_API_SCHEMAS'),
541                    "Auto apply API schemas are disabled")
542    def test_TypedPrimsOnStageWithAutoAppliedAPIs(self):
543        """
544        Tests the fallback properties of typed prims on a stage where API
545        schemas are auto applied.
546        """
547        stage = Usd.Stage.CreateInMemory()
548
549        # Add a typed prim that has two types of built-in applied schemas.
550        # TestMultiApplyAPI:builtin comes from the apiSchemas metadata defined
551        # in TestTypedSchemaForAutoApply's schema definition.
552        # TestSingleApplyAPI and TestMultiApplyAPI:autoFoo come from
553        # TestTypedSchemaForAutoApply being listed in the "AutoApplyAPISchemas"
554        # plugInfo metadata for both API schemas.
555        # The built-in applied schemas that come from the apiSchemas metadata
556        # will always be listed before (and be stronger than) any applied
557        # schemas that come from apiSchemaAutoApplyTo.
558        typedPrim = stage.DefinePrim("/TypedPrim", "TestTypedSchemaForAutoApply")
559        self.assertEqual(typedPrim.GetTypeName(), 'TestTypedSchemaForAutoApply')
560        self.assertEqual(typedPrim.GetAppliedSchemas(),
561                         ["TestMultiApplyAPI:builtin",
562                          "TestMultiApplyAPI:autoFoo",
563                          "TestSingleApplyAPI"])
564        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
565                         'TestTypedSchemaForAutoApply')
566        # Note that prim type info does NOT contain the applied API
567        # schemas from the concrete type's prim definition as these are not part
568        # of the type identity.
569        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
570
571        self.assertTrue(typedPrim.HasAPI(self.MultiApplyAPIType))
572        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
573        self.assertEqual(typedPrim.GetPropertyNames(), [
574            "multi:autoFoo:bool_attr",
575            "multi:autoFoo:relationship",
576            "multi:autoFoo:token_attr",
577            "multi:builtin:bool_attr",
578            "multi:builtin:relationship",
579            "multi:builtin:token_attr",
580            "single:bool_attr",
581            "single:relationship",
582            "single:token_attr",
583            "testAttr",
584            "testRel"])
585
586        # Add a concrete typed prim which receives an auto applied API schema.
587        # TestSingleApplyAPI comes from TestTypedSchemaForAutoApplyConcreteBase
588        # being listed in TestSingleApplyAPI's apiSchemaAutoApplyTo data.
589        typedPrim.SetTypeName("TestTypedSchemaForAutoApplyConcreteBase")
590        self.assertEqual(typedPrim.GetTypeName(),
591                         'TestTypedSchemaForAutoApplyConcreteBase')
592        self.assertEqual(typedPrim.GetAppliedSchemas(),
593                         ["TestSingleApplyAPI"])
594        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
595                         'TestTypedSchemaForAutoApplyConcreteBase')
596        # Note that prim type info does NOT contain the auto applied API
597        # schemas from the concrete type's prim definition as these are not part
598        # of the type identity.
599        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
600
601        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
602        self.assertEqual(typedPrim.GetPropertyNames(), [
603            "single:bool_attr",
604            "single:relationship",
605            "single:token_attr",
606            "testAttr",
607            "testRel"])
608
609        # Add a concrete typed prim which receives an auto applied API schema
610        # because it is derived from a base class type that does.
611        # TestSingleApplyAPI comes from the base class of this type,
612        # TestTypedSchemaForAutoApplyConcreteBase, being listed in
613        # TestSingleApplyAPI's apiSchemaAutoApplyTo data.
614        typedPrim.SetTypeName("TestDerivedTypedSchemaForAutoApplyConcreteBase")
615        self.assertEqual(typedPrim.GetTypeName(),
616                         'TestDerivedTypedSchemaForAutoApplyConcreteBase')
617        self.assertEqual(typedPrim.GetAppliedSchemas(),
618                         ["TestSingleApplyAPI"])
619        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
620                         'TestDerivedTypedSchemaForAutoApplyConcreteBase')
621        # Note that prim type info does NOT contain the auto applied API
622        # schemas from the concrete type's prim definition as these are not part
623        # of the type identity.
624        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
625
626        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
627        self.assertEqual(typedPrim.GetPropertyNames(), [
628            "single:bool_attr",
629            "single:relationship",
630            "single:token_attr",
631            "testAttr",
632            "testRel"])
633
634        # Add a concrete typed prim which receives an auto applied API schema
635        # because it is derived from a base class type that does.
636        # TestSingleApplyAPI comes from the base class of this type,
637        # TestTypedSchemaForAutoApplyAbstractBase, being listed in
638        # TestSingleApplyAPI's apiSchemaAutoApplyTo data. This is different
639        # from case above in that the base class is an abstract type and cannot
640        # be instantiated as a prim type, but API schemas can still be
641        # designated to auto apply to abstract types to have the API applied
642        # to prims of all derived types.
643        typedPrim.SetTypeName("TestDerivedTypedSchemaForAutoApplyAbstractBase")
644        self.assertEqual(typedPrim.GetTypeName(),
645                         'TestDerivedTypedSchemaForAutoApplyAbstractBase')
646        self.assertEqual(typedPrim.GetAppliedSchemas(), ['TestSingleApplyAPI'])
647        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
648                         'TestDerivedTypedSchemaForAutoApplyAbstractBase')
649        # Note that prim type info does NOT contain the auto applied API
650        # schemas from the concrete type's prim definition as these are not part
651        # of the type identity.
652        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
653
654        self.assertTrue(typedPrim.HasAPI(self.SingleApplyAPIType))
655        self.assertEqual(typedPrim.GetPropertyNames(), [
656            "single:bool_attr",
657            "single:relationship",
658            "single:token_attr",
659            "testAttr",
660            "testRel"])
661
662        # Verify that we can get the value of the auto apply API metadata for
663        # TestSingleApplyAPI from the schema registry.
664        self.assertEqual(
665            Usd.SchemaRegistry.GetAutoApplyAPISchemas()['TestSingleApplyAPI'],
666            ['TestTypedSchemaForAutoApplyConcreteBase',
667             'TestTypedSchemaForAutoApplyAbstractBase',
668             'TestAutoAppliedToAPI',
669             'TestTypedSchemaForAutoApply'])
670
671    @unittest.skipIf(not Tf.GetEnvSetting('USD_DISABLE_AUTO_APPLY_API_SCHEMAS'),
672                    "Auto apply API schemas are not disabled")
673    def test_TypedPrimsOnStageWithAutoAppliedAPIs_AutoApplyDisabled(self):
674        """
675        Tests the disabling of auto apply schemas through the environment
676        variable USD_DISABLE_AUTO_APPLY_API_SCHEMAS.
677        """
678        stage = Usd.Stage.CreateInMemory()
679
680        # Add a typed prim that has two types of built-in applied schemas.
681        # TestMultiApplyAPI:builtin comes from the apiSchemas metadata defined
682        # in TestTypedSchemaForAutoApply's schema definition and is NOT affected
683        # by disabling auto apply API schemas.
684        #
685        # TestSingleApplyAPI and TestMultiApplyAPI:autoFoo would come from
686        # TestTypedSchemaForAutoApply being listed in the "AutoApplyAPISchemas"
687        # plugInfo metadata for both API schemas, but with auto apply disabled,
688        # they are not applied to this type.
689        typedPrim = stage.DefinePrim("/TypedPrim", "TestTypedSchemaForAutoApply")
690        self.assertEqual(typedPrim.GetTypeName(),
691                         'TestTypedSchemaForAutoApply')
692        self.assertEqual(typedPrim.GetAppliedSchemas(),
693                         ["TestMultiApplyAPI:builtin"])
694
695        self.assertTrue(typedPrim.HasAPI(self.MultiApplyAPIType, 'builtin'))
696        self.assertFalse(typedPrim.HasAPI(self.MultiApplyAPIType, 'autoFoo'))
697        self.assertFalse(typedPrim.HasAPI(self.SingleApplyAPIType))
698        self.assertEqual(typedPrim.GetPropertyNames(), [
699            "multi:builtin:bool_attr",
700            "multi:builtin:relationship",
701            "multi:builtin:token_attr",
702            "testAttr",
703            "testRel"])
704
705        # Add a concrete typed prim which receives an auto applied API schema.
706        # TestSingleApplyAPI would be auto applied to this type, but with auto
707        # apply disable, this type has no applied API schemas.
708        typedPrim.SetTypeName("TestTypedSchemaForAutoApplyConcreteBase")
709        self.assertEqual(typedPrim.GetTypeName(),
710                         'TestTypedSchemaForAutoApplyConcreteBase')
711        self.assertEqual(typedPrim.GetAppliedSchemas(), [])
712
713        self.assertFalse(typedPrim.HasAPI(self.SingleApplyAPIType))
714        self.assertEqual(typedPrim.GetPropertyNames(), [
715            "testAttr",
716            "testRel"])
717
718        # Verify that the auto apply API schema dictionary is empty when auto
719        # apply is disabled..
720        self.assertEqual(Usd.SchemaRegistry.GetAutoApplyAPISchemas(), {})
721
722    def test_ApplyRemoveAPI(self):
723        """
724        Tests the detail of the Apply and Remove API for API schemas.
725        """
726        stage = Usd.Stage.CreateInMemory()
727        rootLayer = stage.GetRootLayer()
728        sessionLayer = stage.GetSessionLayer()
729        self.assertTrue(rootLayer)
730        self.assertTrue(sessionLayer)
731
732        # Add a basic prim with no type. It has no applied schemas or properties.
733        prim = stage.DefinePrim("/Prim")
734        self.assertEqual(prim.GetAppliedSchemas(), [])
735        self.assertEqual(prim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
736
737        # Helper function for verifying the state of the 'apiSchemas' list op
738        # field in the prim spec for the test prim on the specified layer.
739        def _VerifyListOp(layer, explicit = [], prepended = [],
740                          appended = [], deleted = []):
741            spec = layer.GetPrimAtPath('/Prim')
742            listOp = spec.GetInfo('apiSchemas')
743            self.assertEqual(listOp.explicitItems, explicit)
744            self.assertEqual(listOp.prependedItems, prepended)
745            self.assertEqual(listOp.appendedItems, appended)
746            self.assertEqual(listOp.deletedItems, deleted)
747
748        # Apply a single api schema withe default edit target. Adds to the end
749        # prepend list.
750        prim.ApplyAPI(self.SingleApplyAPIType)
751        self.assertEqual(prim.GetAppliedSchemas(), ["TestSingleApplyAPI"])
752        self.assertTrue(prim.HasAPI(self.SingleApplyAPIType))
753        _VerifyListOp(rootLayer, prepended = ["TestSingleApplyAPI"])
754
755        # Apply the same API schema again. This will not update the list.
756        prim.ApplyAPI(self.SingleApplyAPIType)
757        self.assertEqual(prim.GetAppliedSchemas(), ["TestSingleApplyAPI"])
758        self.assertTrue(prim.HasAPI(self.SingleApplyAPIType))
759        _VerifyListOp(rootLayer, prepended = ["TestSingleApplyAPI"])
760
761        # Remove the API schema. This removes the schema from the prepend and
762        # puts in it the deleted list.
763        prim.RemoveAPI(self.SingleApplyAPIType)
764        self.assertEqual(prim.GetAppliedSchemas(), [])
765        _VerifyListOp(rootLayer, deleted = ["TestSingleApplyAPI"])
766
767        # Remove the same API again. This is a no op.
768        prim.RemoveAPI(self.SingleApplyAPIType)
769        self.assertEqual(prim.GetAppliedSchemas(), [])
770        _VerifyListOp(rootLayer, deleted = ["TestSingleApplyAPI"])
771
772        # Remove a multi apply schema which is not currently in the list. The
773        # This schema instance name is still added to the deleted list.
774        prim.RemoveAPI(self.MultiApplyAPIType, "foo")
775        self.assertEqual(prim.GetAppliedSchemas(), [])
776        _VerifyListOp(rootLayer,
777                      deleted = ["TestSingleApplyAPI", "TestMultiApplyAPI:foo"])
778
779        # Apply the same instance of the multi-apply schema we just deleted. It
780        # is added to the prepended but is NOT removed from the deleted list.
781        # It still ends up in the composed API schemas since deletes are
782        # processed before prepends in the same list op.
783        prim.ApplyAPI(self.MultiApplyAPIType, "foo")
784        self.assertEqual(prim.GetAppliedSchemas(), ["TestMultiApplyAPI:foo"])
785        _VerifyListOp(rootLayer,
786                      prepended = ["TestMultiApplyAPI:foo"],
787                      deleted = ["TestSingleApplyAPI", "TestMultiApplyAPI:foo"])
788
789        # Apply a different instance of the multi-apply schema. Its is added to
790        # the end of the prepends list.
791        prim.ApplyAPI(self.MultiApplyAPIType, "bar")
792        self.assertEqual(prim.GetAppliedSchemas(),
793                         ["TestMultiApplyAPI:foo", "TestMultiApplyAPI:bar"])
794        _VerifyListOp(rootLayer,
795                      prepended = ["TestMultiApplyAPI:foo", "TestMultiApplyAPI:bar"],
796                      deleted = ["TestSingleApplyAPI", "TestMultiApplyAPI:foo"])
797
798        # Remove the "bar" instance of the multi-apply schema on the session
799        # layer. The schema is added to the deleted list on the session layer
800        # and root layer remains the same. It does not show up in the composed
801        # API schemas after composition
802        with Usd.EditContext(stage, sessionLayer):
803            prim.RemoveAPI(self.MultiApplyAPIType, "bar")
804        self.assertEqual(prim.GetAppliedSchemas(), ["TestMultiApplyAPI:foo"])
805        _VerifyListOp(rootLayer,
806                      prepended = ["TestMultiApplyAPI:foo", "TestMultiApplyAPI:bar"],
807                      deleted = ["TestSingleApplyAPI", "TestMultiApplyAPI:foo"])
808        _VerifyListOp(sessionLayer,
809                      deleted = ["TestMultiApplyAPI:bar"])
810
811        # Re-apply the "bar" instance of the multi-apply schema on the session
812        # layer. It is added to the prepend list in the session layer but still
813        # remains in the delete list. Note that the "bar" instance is back in
814        # the composed API schemas list but now it is first instead of second
815        # like it was before as it get deleted and prepended by the session
816        # layer.
817        with Usd.EditContext(stage, sessionLayer):
818            prim.ApplyAPI(self.MultiApplyAPIType, "bar")
819        self.assertEqual(prim.GetAppliedSchemas(),
820                         ["TestMultiApplyAPI:bar", "TestMultiApplyAPI:foo"])
821        _VerifyListOp(rootLayer,
822                      prepended = ["TestMultiApplyAPI:foo", "TestMultiApplyAPI:bar"],
823                      deleted = ["TestSingleApplyAPI", "TestMultiApplyAPI:foo"])
824        _VerifyListOp(sessionLayer,
825                      prepended = ["TestMultiApplyAPI:bar"],
826                      deleted = ["TestMultiApplyAPI:bar"])
827
828        # These next few cases verifies the behavior when the list op has
829        # appends or explicit entries. (Note that we don't define behaviors for
830        # add or reorder).
831        # Update the session layer to have an appended API schema.
832        with Usd.EditContext(stage, sessionLayer):
833            appendedListOp = Sdf.TokenListOp()
834            appendedListOp.appendedItems = ["TestMultiApplyAPI:bar"]
835            prim.SetMetadata('apiSchemas', appendedListOp)
836        # Update the root layer to have an explicit list op.
837        explicitListOp = Sdf.TokenListOp()
838        explicitListOp.explicitItems = ["TestMultiApplyAPI:foo"]
839        prim.SetMetadata('apiSchemas', explicitListOp)
840        # Verify the initial authored and composed lists.
841        self.assertEqual(prim.GetAppliedSchemas(),
842                         ["TestMultiApplyAPI:foo", "TestMultiApplyAPI:bar"])
843        _VerifyListOp(rootLayer,
844                      explicit = ["TestMultiApplyAPI:foo"])
845        _VerifyListOp(sessionLayer,
846                      appended = ["TestMultiApplyAPI:bar"])
847
848        # On the session and root layers, try to apply the API schema that
849        # is already in each respective list. This will be a no op even though
850        # the schemas aren't in the prepended lists.
851        with Usd.EditContext(stage, sessionLayer):
852            prim.ApplyAPI(self.MultiApplyAPIType, "bar")
853        prim.ApplyAPI(self.MultiApplyAPIType, "foo")
854        self.assertEqual(prim.GetAppliedSchemas(),
855                         ["TestMultiApplyAPI:foo", "TestMultiApplyAPI:bar"])
856        _VerifyListOp(rootLayer,
857                      explicit = ["TestMultiApplyAPI:foo"])
858        _VerifyListOp(sessionLayer,
859                      appended = ["TestMultiApplyAPI:bar"])
860
861        # Apply the single apply schema to both layers. The root layer adds it
862        # to the end of its explicit list while the session layer will add it
863        # the prepends. The composed API schemas will only contain the schema
864        # once with the prepend from the stronger session layer winning for
865        # ordering.
866        with Usd.EditContext(stage, sessionLayer):
867            prim.ApplyAPI(self.SingleApplyAPIType)
868        prim.ApplyAPI(self.SingleApplyAPIType)
869        self.assertEqual(prim.GetAppliedSchemas(),
870                         ["TestSingleApplyAPI", "TestMultiApplyAPI:foo",
871                          "TestMultiApplyAPI:bar"])
872        _VerifyListOp(rootLayer,
873                      explicit = ["TestMultiApplyAPI:foo", "TestSingleApplyAPI"])
874        _VerifyListOp(sessionLayer,
875                      prepended = ["TestSingleApplyAPI"],
876                      appended = ["TestMultiApplyAPI:bar"])
877
878        # Remove the starting API schemas from the root and session layers. In
879        # the root layer it is just removed from the explicit list. In the
880        # session layer it is removed from appends and added to the deletes.
881        with Usd.EditContext(stage, sessionLayer):
882            prim.RemoveAPI(self.MultiApplyAPIType, "bar")
883        prim.RemoveAPI(self.MultiApplyAPIType, "foo")
884        self.assertEqual(prim.GetAppliedSchemas(),
885                         ["TestSingleApplyAPI"])
886        _VerifyListOp(rootLayer,
887                      explicit = ["TestSingleApplyAPI"])
888        _VerifyListOp(sessionLayer,
889                      prepended = ["TestSingleApplyAPI"],
890                      deleted = ["TestMultiApplyAPI:bar"])
891
892        # Clear the apiSchemas in both layers for the next tests.
893        # XXX: Should we have additional API for clearing the list op like we
894        # do for other list op fields?
895        with Usd.EditContext(stage, sessionLayer):
896            prim.SetMetadata('apiSchemas', Sdf.TokenListOp())
897        prim.SetMetadata('apiSchemas', Sdf.TokenListOp())
898        self.assertEqual(prim.GetAppliedSchemas(), [])
899        _VerifyListOp(rootLayer)
900        _VerifyListOp(sessionLayer)
901
902        # Trying to apply or remove a multi-apply schema with no instance name
903        # is an error.
904        with self.assertRaises(Tf.ErrorException):
905            prim.ApplyAPI(self.MultiApplyAPIType)
906        self.assertEqual(prim.GetAppliedSchemas(), [])
907        _VerifyListOp(rootLayer)
908        with self.assertRaises(Tf.ErrorException):
909            prim.RemoveAPI(self.MultiApplyAPIType)
910        self.assertEqual(prim.GetAppliedSchemas(), [])
911        _VerifyListOp(rootLayer)
912
913        # Trying to apply or remove a single apply schema with an instance name
914        # is an error.
915        with self.assertRaises(Tf.ErrorException):
916            prim.ApplyAPI(self.SingleApplyAPIType, "foo")
917        self.assertEqual(prim.GetAppliedSchemas(), [])
918        _VerifyListOp(rootLayer)
919        with self.assertRaises(Tf.ErrorException):
920            prim.RemoveAPI(self.SingleApplyAPIType, "foo")
921        self.assertEqual(prim.GetAppliedSchemas(), [])
922        _VerifyListOp(rootLayer)
923
924        # Trying to apply or remove a no apply schema is an error.
925        with self.assertRaises(Tf.ErrorException):
926            prim.ApplyAPI(Usd.ModelAPI)
927        self.assertEqual(prim.GetAppliedSchemas(), [])
928        _VerifyListOp(rootLayer)
929        with self.assertRaises(Tf.ErrorException):
930            prim.RemoveAPI(Usd.ModelAPI)
931        self.assertEqual(prim.GetAppliedSchemas(), [])
932        _VerifyListOp(rootLayer)
933
934        # AddAPITypeName will just add by schema type name with no validity
935        # checks. But it still won't add duplicates.
936        #
937        # Valid type names
938        prim.AddAppliedSchema("TestSingleApplyAPI")
939        prim.AddAppliedSchema("TestMultiApplyAPI:bar")
940        # Invalid type names.
941        prim.AddAppliedSchema("BogusTypeName")
942        prim.AddAppliedSchema("TestMultiApplyAPI")
943        # Duplicate.
944        prim.AddAppliedSchema("TestSingleApplyAPI")
945        # Even though invalid type names get added to the apiSchemas metadata,
946        # they won't show up in GetAppliedSchemas as they won't be composed into
947        # the prim's UsdPrimDefinition.
948        self.assertEqual(prim.GetAppliedSchemas(),
949                         ["TestSingleApplyAPI", "TestMultiApplyAPI:bar"])
950        _VerifyListOp(rootLayer,
951                      prepended = ["TestSingleApplyAPI", "TestMultiApplyAPI:bar",
952                                   "BogusTypeName", "TestMultiApplyAPI"])
953
954        # RemoveAPITypeName will just delete by schema type name with no
955        # validity checks. But it still won't add duplicate delete entries.
956        #
957        # Valid type names
958        prim.RemoveAppliedSchema("TestSingleApplyAPI")
959        prim.RemoveAppliedSchema("TestMultiApplyAPI:bar")
960        # Invalid type names.
961        prim.RemoveAppliedSchema("BogusTypeName")
962        prim.RemoveAppliedSchema("TestMultiApplyAPI")
963        # Duplicate.
964        prim.RemoveAppliedSchema("TestSingleApplyAPI")
965        self.assertEqual(prim.GetAppliedSchemas(), [])
966        _VerifyListOp(rootLayer,
967                      deleted = ["TestSingleApplyAPI", "TestMultiApplyAPI:bar",
968                                 "BogusTypeName", "TestMultiApplyAPI"])
969
970    def test_CanApplyAPI(self):
971        """
972        Tests the details of the Usd.Prim.CanApplyAPI.
973        """
974        stage = Usd.Stage.CreateInMemory()
975        rootLayer = stage.GetRootLayer()
976        sessionLayer = stage.GetSessionLayer()
977        self.assertTrue(rootLayer)
978        self.assertTrue(sessionLayer)
979
980        # Add prims of various types to test CanApplyAPI.
981        prim = stage.DefinePrim(
982            "/Prim")
983        prim2 = stage.DefinePrim(
984            "/Prim2", "TestTypedSchema")
985        prim3 = stage.DefinePrim(
986            "/Prim3", "TestTypedSchemaForAutoApply")
987        prim4 = stage.DefinePrim(
988            "/Prim4", "TestDerivedTypedSchemaForAutoApplyConcreteBase")
989        prim5 = stage.DefinePrim(
990            "/Prim5", "TestDerivedTypedSchemaForAutoApplyAbstractBase")
991
992        # Single apply schema with no specified "apiSchemaCanOnlyApplyTo"
993        # metadata. Can apply to all prims.
994        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
995            "TestSingleApplyAPI"), [])
996        self.assertTrue(prim.CanApplyAPI(self.SingleApplyAPIType))
997        self.assertTrue(prim2.CanApplyAPI(self.SingleApplyAPIType))
998        self.assertTrue(prim3.CanApplyAPI(self.SingleApplyAPIType))
999        self.assertTrue(prim4.CanApplyAPI(self.SingleApplyAPIType))
1000        self.assertTrue(prim5.CanApplyAPI(self.SingleApplyAPIType))
1001
1002        # Multiple apply schema with no specified "apiSchemaCanOnlyApplyTo"
1003        # metadata and no "allowedInstanceNames". Can apply to all prims with
1004        # all instance names (with the notable exception of instance names that
1005        # match a property name from the schema).
1006        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1007            "TestMultiApplyAPI", "foo"), [])
1008        self.assertTrue(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1009            "TestMultiApplyAPI", "foo"))
1010        self.assertTrue(prim.CanApplyAPI(self.MultiApplyAPIType, "foo"))
1011        self.assertTrue(prim2.CanApplyAPI(self.MultiApplyAPIType, "foo"))
1012        self.assertTrue(prim3.CanApplyAPI(self.MultiApplyAPIType, "foo"))
1013        self.assertTrue(prim4.CanApplyAPI(self.MultiApplyAPIType, "foo"))
1014        self.assertTrue(prim5.CanApplyAPI(self.MultiApplyAPIType, "foo"))
1015
1016        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1017            "TestMultiApplyAPI", "bar"), [])
1018        self.assertTrue(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1019            "TestMultiApplyAPI", "bar"))
1020        self.assertTrue(prim.CanApplyAPI(self.MultiApplyAPIType, "bar"))
1021        self.assertTrue(prim2.CanApplyAPI(self.MultiApplyAPIType, "bar"))
1022        self.assertTrue(prim3.CanApplyAPI(self.MultiApplyAPIType, "bar"))
1023        self.assertTrue(prim4.CanApplyAPI(self.MultiApplyAPIType, "bar"))
1024        self.assertTrue(prim5.CanApplyAPI(self.MultiApplyAPIType, "bar"))
1025
1026        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1027            "TestMultiApplyAPI", "baz"), [])
1028        self.assertTrue(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1029            "TestMultiApplyAPI", "baz"))
1030        self.assertTrue(prim.CanApplyAPI(self.MultiApplyAPIType, "baz"))
1031        self.assertTrue(prim2.CanApplyAPI(self.MultiApplyAPIType, "baz"))
1032        self.assertTrue(prim3.CanApplyAPI(self.MultiApplyAPIType, "baz"))
1033        self.assertTrue(prim4.CanApplyAPI(self.MultiApplyAPIType, "baz"))
1034        self.assertTrue(prim5.CanApplyAPI(self.MultiApplyAPIType, "baz"))
1035
1036        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1037            "TestMultiApplyAPI", "Bar"), [])
1038        self.assertTrue(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1039            "TestMultiApplyAPI", "Bar"))
1040        self.assertTrue(prim.CanApplyAPI(self.MultiApplyAPIType, "Bar"))
1041        self.assertTrue(prim2.CanApplyAPI(self.MultiApplyAPIType, "Bar"))
1042        self.assertTrue(prim3.CanApplyAPI(self.MultiApplyAPIType, "Bar"))
1043        self.assertTrue(prim4.CanApplyAPI(self.MultiApplyAPIType, "Bar"))
1044        self.assertTrue(prim5.CanApplyAPI(self.MultiApplyAPIType, "Bar"))
1045
1046        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1047            "TestMultiApplyAPI", "qux"), [])
1048        self.assertTrue(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1049            "TestMultiApplyAPI", "qux"))
1050        self.assertTrue(prim.CanApplyAPI(self.MultiApplyAPIType, "qux"))
1051        self.assertTrue(prim2.CanApplyAPI(self.MultiApplyAPIType, "qux"))
1052        self.assertTrue(prim3.CanApplyAPI(self.MultiApplyAPIType, "qux"))
1053        self.assertTrue(prim4.CanApplyAPI(self.MultiApplyAPIType, "qux"))
1054        self.assertTrue(prim5.CanApplyAPI(self.MultiApplyAPIType, "qux"))
1055
1056        # As mentioned above, property names of the API schema are not valid
1057        # instance names and will return false for CanApplyAPI
1058        self.assertFalse(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1059            "TestMultiApplyAPI", "bool_attr"))
1060        self.assertFalse(prim.CanApplyAPI(self.MultiApplyAPIType, "bool_attr"))
1061        self.assertFalse(prim2.CanApplyAPI(self.MultiApplyAPIType, "bool_attr"))
1062        self.assertFalse(prim3.CanApplyAPI(self.MultiApplyAPIType, "bool_attr"))
1063        self.assertFalse(prim4.CanApplyAPI(self.MultiApplyAPIType, "bool_attr"))
1064        self.assertFalse(prim5.CanApplyAPI(self.MultiApplyAPIType, "bool_attr"))
1065
1066        self.assertFalse(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1067            "TestMultiApplyAPI", "relationship"))
1068        self.assertFalse(prim.CanApplyAPI(self.MultiApplyAPIType, "relationship"))
1069        self.assertFalse(prim2.CanApplyAPI(self.MultiApplyAPIType, "relationship"))
1070        self.assertFalse(prim3.CanApplyAPI(self.MultiApplyAPIType, "relationship"))
1071        self.assertFalse(prim4.CanApplyAPI(self.MultiApplyAPIType, "relationship"))
1072        self.assertFalse(prim5.CanApplyAPI(self.MultiApplyAPIType, "relationship"))
1073
1074        # Single apply API schema that does specify an "apiSchemaCanOnlyApplyTo"
1075        # list. prim3 is a type in the list and prim4 derives from a type in the
1076        # list so only these return true.
1077        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1078            "TestSingleCanApplyAPI"),
1079            ["TestTypedSchemaForAutoApply",
1080             "TestTypedSchemaForAutoApplyConcreteBase"])
1081        self.assertFalse(prim.CanApplyAPI(self.SingleCanApplyAPIType))
1082        self.assertFalse(prim2.CanApplyAPI(self.SingleCanApplyAPIType))
1083        self.assertTrue(prim3.CanApplyAPI(self.SingleCanApplyAPIType))
1084        self.assertTrue(prim4.CanApplyAPI(self.SingleCanApplyAPIType))
1085        self.assertFalse(prim5.CanApplyAPI(self.SingleCanApplyAPIType))
1086
1087        # Multiple apply API schema that specifies allow instance names
1088        # "foo", "bar", and "baz". All other instance names aren't allowed
1089        # and will return false.
1090        self.assertFalse(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1091            "TestMultiCanApplyAPI", "Bar"))
1092        self.assertFalse(prim.CanApplyAPI(self.MultiCanApplyAPIType, "Bar"))
1093        self.assertFalse(prim2.CanApplyAPI(self.MultiCanApplyAPIType, "Bar"))
1094        self.assertFalse(prim3.CanApplyAPI(self.MultiCanApplyAPIType, "Bar"))
1095        self.assertFalse(prim4.CanApplyAPI(self.MultiCanApplyAPIType, "Bar"))
1096        self.assertFalse(prim5.CanApplyAPI(self.MultiCanApplyAPIType, "Bar"))
1097
1098        self.assertFalse(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1099            "TestMultiCanApplyAPI", "qux"))
1100        self.assertFalse(prim.CanApplyAPI(self.MultiCanApplyAPIType, "qux"))
1101        self.assertFalse(prim2.CanApplyAPI(self.MultiCanApplyAPIType, "qux"))
1102        self.assertFalse(prim3.CanApplyAPI(self.MultiCanApplyAPIType, "qux"))
1103        self.assertFalse(prim4.CanApplyAPI(self.MultiCanApplyAPIType, "qux"))
1104        self.assertFalse(prim5.CanApplyAPI(self.MultiCanApplyAPIType, "qux"))
1105
1106        # Same multiple apply API schema with allowed instance name "baz".
1107        # The API schema type specifies an "apiSchemaCanOnlyApplyTo" list so
1108        # this instance can only be applied to those types. prim3 is a type in
1109        # the list and prim5 derives from a type in the list so only these
1110        # return true.
1111        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1112            "TestMultiCanApplyAPI", "baz"),
1113            ["TestTypedSchemaForAutoApply",
1114             "TestTypedSchemaForAutoApplyAbstractBase"])
1115        self.assertEqual(
1116            Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1117                "TestMultiCanApplyAPI", "baz"),
1118            Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1119                "TestMultiCanApplyAPI"))
1120        self.assertTrue(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1121            "TestMultiCanApplyAPI", "baz"))
1122        self.assertFalse(prim.CanApplyAPI(self.MultiCanApplyAPIType, "baz"))
1123        self.assertFalse(prim2.CanApplyAPI(self.MultiCanApplyAPIType, "baz"))
1124        self.assertTrue(prim3.CanApplyAPI(self.MultiCanApplyAPIType, "baz"))
1125        self.assertFalse(prim4.CanApplyAPI(self.MultiCanApplyAPIType, "baz"))
1126        self.assertTrue(prim5.CanApplyAPI(self.MultiCanApplyAPIType, "baz"))
1127
1128        # Same multiple apply API schema with allowed instance name "foo".
1129        # The API schema type specifies an "apiSchemaCanOnlyApplyTo" list
1130        # specifically for "foo" so this instance can only be applied to those
1131        # types. prim3 is a type in the list and prim4 derives from a type in
1132        # the list so only these return true.
1133        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1134            "TestMultiCanApplyAPI", "foo"),
1135            ["TestTypedSchemaForAutoApply",
1136             "TestTypedSchemaForAutoApplyConcreteBase"])
1137        self.assertNotEqual(
1138            Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1139                "TestMultiCanApplyAPI", "foo"),
1140            Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1141                "TestMultiCanApplyAPI"))
1142        self.assertTrue(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1143            "TestMultiCanApplyAPI", "foo"))
1144        self.assertFalse(prim.CanApplyAPI(self.MultiCanApplyAPIType, "foo"))
1145        self.assertFalse(prim2.CanApplyAPI(self.MultiCanApplyAPIType, "foo"))
1146        self.assertTrue(prim3.CanApplyAPI(self.MultiCanApplyAPIType, "foo"))
1147        self.assertTrue(prim4.CanApplyAPI(self.MultiCanApplyAPIType, "foo"))
1148        self.assertFalse(prim5.CanApplyAPI(self.MultiCanApplyAPIType, "foo"))
1149
1150        # Same multiple apply API schema with allowed instance name "bar".
1151        # The API schema type specifies yet another "apiSchemaCanOnlyApplyTo"
1152        # list specifically for "bar" so this instance can only be applied to
1153        # those types. prim4 and prim5 each derive from a different type in
1154        # the list so only these return true.
1155        self.assertEqual(Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1156            "TestMultiCanApplyAPI", "bar"),
1157            ["TestTypedSchemaForAutoApplyAbstractBase",
1158             "TestTypedSchemaForAutoApplyConcreteBase"])
1159        self.assertNotEqual(
1160            Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1161                "TestMultiCanApplyAPI", "bar"),
1162            Usd.SchemaRegistry.GetAPISchemaCanOnlyApplyToTypeNames(
1163                "TestMultiCanApplyAPI"))
1164        self.assertTrue(Usd.SchemaRegistry.IsAllowedAPISchemaInstanceName(
1165            "TestMultiCanApplyAPI", "bar"))
1166        self.assertFalse(prim.CanApplyAPI(self.MultiCanApplyAPIType, "bar"))
1167        self.assertFalse(prim2.CanApplyAPI(self.MultiCanApplyAPIType, "bar"))
1168        self.assertFalse(prim3.CanApplyAPI(self.MultiCanApplyAPIType, "bar"))
1169        self.assertTrue(prim4.CanApplyAPI(self.MultiCanApplyAPIType, "bar"))
1170        self.assertTrue(prim5.CanApplyAPI(self.MultiCanApplyAPIType, "bar"))
1171
1172        # Error conditions
1173        # Coding error if called on single apply schema with an instance name.
1174        with self.assertRaises(Tf.ErrorException):
1175            self.assertFalse(prim.CanApplyAPI(self.SingleApplyAPIType, "foo"))
1176        # Coding error if called on multiple apply schema without an instance
1177        # name.
1178        with self.assertRaises(Tf.ErrorException):
1179            self.assertFalse(prim.CanApplyAPI(self.MultiApplyAPIType))
1180        # Coding error if called on multiple apply schema with an empty instance
1181        # name.
1182        with self.assertRaises(Tf.ErrorException):
1183            self.assertFalse(prim.CanApplyAPI(self.MultiApplyAPIType, ""))
1184
1185        # Verify whyNot annotations when CanApplyAPI is false.
1186        result = prim4.CanApplyAPI(self.MultiCanApplyAPIType, "bar")
1187        self.assertTrue(result)
1188        self.assertEqual(result.whyNot, "")
1189
1190        result = prim.CanApplyAPI(self.MultiCanApplyAPIType, "qux")
1191        self.assertFalse(result)
1192        self.assertEqual(result.whyNot,
1193                         "'qux' is not an allowed instance name for multiple "
1194                         "apply API schema 'TestMultiCanApplyAPI'.")
1195
1196        result = prim.CanApplyAPI(self.MultiCanApplyAPIType, "bar")
1197        self.assertFalse(result)
1198        self.assertEqual(result.whyNot,
1199                         "API schema 'TestMultiCanApplyAPI:bar' can only be "
1200                         "applied to prims of the following types: "
1201                         "TestTypedSchemaForAutoApplyAbstractBase, "
1202                         "TestTypedSchemaForAutoApplyConcreteBase.")
1203
1204        result = prim.CanApplyAPI(self.MultiApplyAPIType, "bool_attr")
1205        self.assertFalse(result)
1206        self.assertEqual(result.whyNot,
1207                         "'bool_attr' is not an allowed instance name for "
1208                         "multiple apply API schema 'TestMultiApplyAPI'.")
1209
1210    def test_NestedAPISchemas(self):
1211        """
1212        Tests the application of API schemas that have nested built-in API
1213        schemas
1214        """
1215        stage = Usd.Stage.CreateInMemory()
1216
1217        # Simple helper for testing that a prim has expected attributes that
1218        # resolve to expected values.
1219        def _VerifyAttrValues(prim, expectedAttrValues):
1220            values = {name : prim.GetAttribute(name).Get()
1221                         for name in expectedAttrValues.keys()}
1222            self.assertEqual(values, expectedAttrValues)
1223
1224        # Add a prim with no type and apply the TestNestedInnerSingleApplyAPI.
1225        innerSinglePrim = stage.DefinePrim("/InnerSingle")
1226        innerSinglePrim.ApplyAPI(self.NestedInnerSingleApplyAPIType)
1227
1228        # The authored applied API schemas for the prim is only the applied
1229        # TestNestedInnerSingleApplyAPI.
1230        self.assertEqual(innerSinglePrim.GetPrimTypeInfo().GetTypeName(), '')
1231        self.assertEqual(innerSinglePrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
1232                         ["TestNestedInnerSingleApplyAPI"])
1233
1234        # The composed applied API schemas however also contain the
1235        # TestSingleApplyAPI and the "bar" instance of TestMultiApplyAPI as
1236        # these are built-in APIs of TestNestedInnerSingleApplyAPI
1237        expectedAPISchemas = [
1238            "TestNestedInnerSingleApplyAPI",
1239            "TestSingleApplyAPI",
1240            "TestMultiApplyAPI:bar"]
1241        self.assertEqual(innerSinglePrim.GetAppliedSchemas(),
1242                         expectedAPISchemas)
1243        # The prim "has" all these built-in APIs as well.
1244        self.assertTrue(innerSinglePrim.HasAPI(self.NestedInnerSingleApplyAPIType))
1245        self.assertTrue(innerSinglePrim.HasAPI(self.SingleApplyAPIType))
1246        self.assertTrue(innerSinglePrim.HasAPI(self.MultiApplyAPIType))
1247        self.assertTrue(innerSinglePrim.HasAPI(self.MultiApplyAPIType, "bar"))
1248
1249        # Properties come from all composed built-in APIs
1250        expectedPropNames = [
1251            # Properties from TestNestedInnerSingleApplyAPI
1252            "innerSingle:int_attr",
1253            "innerSingle:relationship",
1254            "innerSingle:token_attr",
1255            # Properties from TestMultiApplyAPI:bar
1256            "multi:bar:bool_attr",
1257            "multi:bar:relationship",
1258            "multi:bar:token_attr",
1259            # Properties from TestSingleApplyAPI
1260            "single:bool_attr",
1261            "single:relationship",
1262            "single:token_attr"]
1263        self.assertEqual(innerSinglePrim.GetPropertyNames(), expectedPropNames)
1264
1265        # Verify that the attribute fallback values come from the API schemas
1266        # that define them. The attribute "multi:bar:token_attr" is defined in
1267        # TestNestedInnerSingleApplyAPI and overrides the attr fallback value
1268        # defined in TestMultiApplyAPI:bar
1269        expectedAttrValues = {
1270            "multi:bar:token_attr" : "inner_override",
1271            "multi:bar:bool_attr" : True,
1272            "innerSingle:token_attr" : "inner",
1273            "innerSingle:int_attr" : 3,
1274            "single:token_attr" : "bar",
1275            "single:bool_attr" : True}
1276        _VerifyAttrValues(innerSinglePrim, expectedAttrValues)
1277
1278        # Get the prim definition for the API schema and verify its applied
1279        # API schemas and properties match what was imparted on the prim.
1280        innerSingleApplyAPIDef = \
1281            Usd.SchemaRegistry().FindAppliedAPIPrimDefinition(
1282                "TestNestedInnerSingleApplyAPI")
1283        self.assertTrue(innerSingleApplyAPIDef)
1284        self.assertEqual(innerSingleApplyAPIDef.GetAppliedAPISchemas(),
1285                         expectedAPISchemas)
1286        self.assertEqual(sorted(innerSingleApplyAPIDef.GetPropertyNames()),
1287                         expectedPropNames)
1288        self.assertEqual(innerSingleApplyAPIDef.GetDocumentation(),
1289            "Test nested single apply API schema: inner schema")
1290
1291        # Add a prim with no type and apply the TestNestedOuterSingleApplyAPI.
1292        outerSinglePrim = stage.DefinePrim("/OuterSingle")
1293        outerSinglePrim.ApplyAPI(self.NestedOuterSingleApplyAPIType)
1294
1295        # The authored applied API schemas for the prim is only the applied
1296        # TestNestedOuterSingleApplyAPI.
1297        self.assertEqual(outerSinglePrim.GetPrimTypeInfo().GetTypeName(), '')
1298        self.assertEqual(outerSinglePrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
1299                         ["TestNestedOuterSingleApplyAPI"])
1300
1301        # The composed applied API schemas however also contain the
1302        # the "foo" instance of TestMultiApplyAPI and
1303        # TestNestedInnerSingleApplyAPI and as these are built-in APIs of
1304        # TestNestedOuterSingleApplyAPI. However, because
1305        # TestNestedInnerSingleApplyAPI has its own built-in API schemas, those
1306        # are also pulled into the composed applied API schemas for this prim
1307        self.assertEqual(outerSinglePrim.GetTypeName(), '')
1308        expectedAPISchemas = [
1309            "TestNestedOuterSingleApplyAPI",
1310            "TestMultiApplyAPI:foo",
1311            "TestNestedInnerSingleApplyAPI",
1312            "TestSingleApplyAPI",
1313            "TestMultiApplyAPI:bar"]
1314        self.assertEqual(outerSinglePrim.GetAppliedSchemas(),
1315                         expectedAPISchemas)
1316
1317        # Properties come from all composed built-in APIs
1318        expectedPropNames = [
1319            "innerSingle:int_attr",
1320            "innerSingle:relationship",
1321            "innerSingle:token_attr",
1322            # Properties from TestMultiApplyAPI:bar (included from
1323            # TestNestedInnerSingleApplyAPI)
1324            "multi:bar:bool_attr",
1325            "multi:bar:relationship",
1326            "multi:bar:token_attr",
1327            # Properties from TestMultiApplyAPI:foo
1328            "multi:foo:bool_attr",
1329            "multi:foo:relationship",
1330            "multi:foo:token_attr",
1331            # Properties from TestNestedOuterSingleApplyAPI
1332            "outerSingle:int_attr",
1333            "outerSingle:relationship",
1334            "outerSingle:token_attr",
1335            # Properties from TestSingleApplyAPI (included from
1336            # TestNestedInnerSingleApplyAPI)
1337            "single:bool_attr",
1338            "single:relationship",
1339            "single:token_attr"]
1340        self.assertEqual(outerSinglePrim.GetPropertyNames(), expectedPropNames)
1341
1342        # Verify that the attribute fallback values come from the API schemas
1343        # that define them. The attribute override for "multi:bar:token_attr"
1344        # from TestNestedInnerSingleApplyAPI still comes through.
1345        # Also The attribute "single:token_attr" is defined in
1346        # TestNestedOuterSingleApplyAPI and overrides the attr fallback value
1347        # defined in TestSingleApplyAPI
1348        expectedAttrValues = {
1349            "innerSingle:token_attr" : "inner",
1350            "innerSingle:int_attr" : 3,
1351            "multi:bar:token_attr" : "inner_override",
1352            "multi:bar:bool_attr" : True,
1353            "multi:foo:token_attr" : "foo",
1354            "multi:foo:bool_attr" : True,
1355            "outerSingle:token_attr" : "outer",
1356            "outerSingle:int_attr" : 4,
1357            "single:token_attr" : "outer_override",
1358            "single:bool_attr" : True}
1359        _VerifyAttrValues(outerSinglePrim, expectedAttrValues)
1360
1361        # Get the prim definition for the API schema and verify its applied
1362        # API schemas and properties match what was imparted on the prim.
1363        outerSingleApplyAPIDef = \
1364            Usd.SchemaRegistry().FindAppliedAPIPrimDefinition(
1365                "TestNestedOuterSingleApplyAPI")
1366        self.assertTrue(outerSingleApplyAPIDef)
1367        self.assertEqual(outerSingleApplyAPIDef.GetAppliedAPISchemas(),
1368                         expectedAPISchemas)
1369        self.assertEqual(sorted(outerSingleApplyAPIDef.GetPropertyNames()),
1370                         expectedPropNames)
1371        self.assertEqual(outerSingleApplyAPIDef.GetDocumentation(),
1372            "Test nested single apply API schema: outer schema")
1373
1374        # Apply the TestNestedInnerSingleApplyAPI to the same prim. This API
1375        # is already included through the TestNestedOuterSingleApplyAPI.
1376        outerSinglePrim.ApplyAPI(self.NestedInnerSingleApplyAPIType)
1377
1378        # The authored applied API schemas for the prim now contain both the
1379        # applied APIs.
1380        self.assertEqual(outerSinglePrim.GetPrimTypeInfo().GetTypeName(), '')
1381        self.assertEqual(outerSinglePrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
1382                         ["TestNestedOuterSingleApplyAPI",
1383                          "TestNestedInnerSingleApplyAPI"])
1384
1385        # The composed applied API schemas are fully expanded from both authored
1386        # APIs and will contain duplicates. We don't check for duplicates that
1387        # occur because different authored APIs include the same applied schema
1388        # even though we do remove duplicates when determining what API schemas
1389        # a single API includes.
1390        self.assertEqual(outerSinglePrim.GetTypeName(), '')
1391        expectedAPISchemas = [
1392            # API schemas from expanded TestNestedOuterSingleApplyAPI
1393            "TestNestedOuterSingleApplyAPI",
1394            "TestMultiApplyAPI:foo",
1395            "TestNestedInnerSingleApplyAPI",
1396            "TestSingleApplyAPI",
1397            "TestMultiApplyAPI:bar",
1398            # API schemas from expanded TestNestedInnerSingleApplyAPI (even
1399            # though they're already in the list)
1400            "TestNestedInnerSingleApplyAPI",
1401            "TestSingleApplyAPI",
1402            "TestMultiApplyAPI:bar"]
1403        self.assertEqual(outerSinglePrim.GetAppliedSchemas(),
1404                         expectedAPISchemas)
1405
1406        # The properties list and attribute values haven't changed though
1407        # because no actual new API schemas were added and the strength order
1408        # of the APIs haven't changed.
1409        self.assertEqual(outerSinglePrim.GetPropertyNames(), expectedPropNames)
1410        _VerifyAttrValues(outerSinglePrim, expectedAttrValues)
1411
1412        # Now let's swap the order of these two APIs so that the inner comes
1413        # before the outer.
1414        outerSinglePrim.RemoveAPI(self.NestedOuterSingleApplyAPIType)
1415        outerSinglePrim.ApplyAPI(self.NestedOuterSingleApplyAPIType)
1416        self.assertEqual(outerSinglePrim.GetPrimTypeInfo().GetAppliedAPISchemas(),
1417                         ["TestNestedInnerSingleApplyAPI",
1418                          "TestNestedOuterSingleApplyAPI"])
1419
1420        # The order of the expanded API schemas has now changed too.
1421        expectedAPISchemas = [
1422            # API schemas from expanded TestNestedInnerSingleApplyAPI
1423            "TestNestedInnerSingleApplyAPI",
1424            "TestSingleApplyAPI",
1425            "TestMultiApplyAPI:bar",
1426            # API schemas from expanded TestNestedOuterSingleApplyAPI
1427            "TestNestedOuterSingleApplyAPI",
1428            "TestMultiApplyAPI:foo",
1429            "TestNestedInnerSingleApplyAPI",
1430            "TestSingleApplyAPI",
1431            "TestMultiApplyAPI:bar"]
1432        self.assertEqual(outerSinglePrim.GetAppliedSchemas(),
1433                         expectedAPISchemas)
1434
1435        # Once again The properties list doesn't change.
1436        self.assertEqual(outerSinglePrim.GetPropertyNames(), expectedPropNames)
1437        # However, the attribute value for single:token_attr has changed
1438        # because the override from TestNestedOuterSingleApplyAPI is no longer
1439        # stronger than the value from TestSingleApplyAPI as the first instance
1440        # of TestSingleApplyAPI now comes before it.
1441        expectedAttrValues["single:token_attr"] = "bar"
1442        _VerifyAttrValues(outerSinglePrim, expectedAttrValues)
1443
1444
1445    def test_NestedCycleAPISchema(self):
1446        """
1447        Tests the application of API schemas that have nested built-in API
1448        schemas that would cause an inclusion cycle
1449        """
1450        stage = Usd.Stage.CreateInMemory()
1451
1452        # Simple helper for testing that a prim has expected attributes that
1453        # resolve to expected values.
1454        def _VerifyAttrValues(prim, expectedAttrValues):
1455            values = {name : prim.GetAttribute(name).Get()
1456                         for name in expectedAttrValues.keys()}
1457            self.assertEqual(values, expectedAttrValues)
1458
1459        # Test behavior when nested API schema form a cycle. In this example
1460        # TestNestedCycle1API includes TestNestedCycle2API which includes
1461        # TestNestedCycle3API which includes TestNestedCycle1API again. Create
1462        # three prims, each applying one of the API schemas.
1463        nestedCyclePrim1 = stage.DefinePrim("/Cycle1")
1464        nestedCyclePrim2 = stage.DefinePrim("/Cycle2")
1465        nestedCyclePrim3 = stage.DefinePrim("/Cycle3")
1466        nestedCyclePrim1.ApplyAPI(self.NestedCycle1APIType)
1467        nestedCyclePrim2.ApplyAPI(self.NestedCycle2APIType)
1468        nestedCyclePrim3.ApplyAPI(self.NestedCycle3APIType)
1469
1470        # For each prim the authored applied API schemas for the prim are still
1471        # only the single API that was applied.
1472        self.assertEqual(nestedCyclePrim1.GetPrimTypeInfo().GetTypeName(), '')
1473        self.assertEqual(nestedCyclePrim1.GetPrimTypeInfo().GetAppliedAPISchemas(),
1474                         ["TestNestedCycle1API"])
1475        self.assertEqual(nestedCyclePrim2.GetPrimTypeInfo().GetTypeName(), '')
1476        self.assertEqual(nestedCyclePrim2.GetPrimTypeInfo().GetAppliedAPISchemas(),
1477                         ["TestNestedCycle2API"])
1478        self.assertEqual(nestedCyclePrim3.GetPrimTypeInfo().GetTypeName(), '')
1479        self.assertEqual(nestedCyclePrim3.GetPrimTypeInfo().GetAppliedAPISchemas(),
1480                         ["TestNestedCycle3API"])
1481
1482        # The composed applied API schemas all contain all three API schemas,
1483        # however the order is different based on which schema was actually
1484        # the authored one. Note that during API schema expansion we don't try
1485        # to include the same API schema more than once which allows us to
1486        # handle cycles in this way.
1487        self.assertEqual(nestedCyclePrim1.GetTypeName(), '')
1488        self.assertEqual(nestedCyclePrim1.GetAppliedSchemas(), [
1489            "TestNestedCycle1API",
1490            "TestNestedCycle2API",
1491            "TestNestedCycle3API"])
1492        self.assertEqual(nestedCyclePrim2.GetTypeName(), '')
1493        self.assertEqual(nestedCyclePrim2.GetAppliedSchemas(), [
1494            "TestNestedCycle2API",
1495            "TestNestedCycle3API",
1496            "TestNestedCycle1API"])
1497        self.assertEqual(nestedCyclePrim3.GetTypeName(), '')
1498        self.assertEqual(nestedCyclePrim3.GetAppliedSchemas(), [
1499            "TestNestedCycle3API",
1500            "TestNestedCycle1API",
1501            "TestNestedCycle2API"])
1502        # All three prims "has" all three built-in APIs as well.
1503        self.assertTrue(nestedCyclePrim1.HasAPI(self.NestedCycle1APIType))
1504        self.assertTrue(nestedCyclePrim1.HasAPI(self.NestedCycle2APIType))
1505        self.assertTrue(nestedCyclePrim1.HasAPI(self.NestedCycle3APIType))
1506
1507        self.assertTrue(nestedCyclePrim2.HasAPI(self.NestedCycle1APIType))
1508        self.assertTrue(nestedCyclePrim2.HasAPI(self.NestedCycle2APIType))
1509        self.assertTrue(nestedCyclePrim2.HasAPI(self.NestedCycle3APIType))
1510
1511        self.assertTrue(nestedCyclePrim3.HasAPI(self.NestedCycle1APIType))
1512        self.assertTrue(nestedCyclePrim3.HasAPI(self.NestedCycle2APIType))
1513        self.assertTrue(nestedCyclePrim3.HasAPI(self.NestedCycle3APIType))
1514
1515        # All three prims have all the same properties since they all have all
1516        # three API schemas applied.
1517        expectedPropNames = [
1518            "cycle1:token_attr",
1519            "cycle2:token_attr",
1520            "cycle3:token_attr",
1521            "cycle:int_attr"]
1522        self.assertEqual(nestedCyclePrim1.GetPropertyNames(), expectedPropNames)
1523        self.assertEqual(nestedCyclePrim2.GetPropertyNames(), expectedPropNames)
1524        self.assertEqual(nestedCyclePrim3.GetPropertyNames(), expectedPropNames)
1525
1526        # For the three token attributes, each is only defined in its respective
1527        # API schema so they have the same fallback in each prim.
1528        # 'cycle:int_attr' is defined in all three of the cycle API schemas but
1529        # with different default values. Here the order of the applied schemas
1530        # matters and the strongest applied API's value wins.
1531        expectedAttrValues = {
1532            "cycle1:token_attr" : "cycle1",
1533            "cycle2:token_attr" : "cycle2",
1534            "cycle3:token_attr" : "cycle3"}
1535        expectedAttrValues["cycle:int_attr"] = 1
1536        _VerifyAttrValues(nestedCyclePrim1, expectedAttrValues)
1537        expectedAttrValues["cycle:int_attr"] = 2
1538        _VerifyAttrValues(nestedCyclePrim2, expectedAttrValues)
1539        expectedAttrValues["cycle:int_attr"] = 3
1540        _VerifyAttrValues(nestedCyclePrim3, expectedAttrValues)
1541
1542        # Get the prim definitions for each of these API schemas and verify its
1543        # applied API schemas and properties match what was imparted on the
1544        # prims.
1545        cycle1APIDef = Usd.SchemaRegistry().FindAppliedAPIPrimDefinition(
1546            "TestNestedCycle1API")
1547        self.assertTrue(cycle1APIDef)
1548        self.assertEqual(cycle1APIDef.GetAppliedAPISchemas(),
1549            ["TestNestedCycle1API",
1550             "TestNestedCycle2API",
1551             "TestNestedCycle3API"])
1552        self.assertEqual(sorted(cycle1APIDef.GetPropertyNames()),
1553                         expectedPropNames)
1554        self.assertEqual(cycle1APIDef.GetDocumentation(),
1555            "Test nested single apply API schema with a cycle #1")
1556
1557        cycle2APIDef = Usd.SchemaRegistry().FindAppliedAPIPrimDefinition(
1558            "TestNestedCycle2API")
1559        self.assertTrue(cycle2APIDef)
1560        self.assertEqual(cycle2APIDef.GetAppliedAPISchemas(),
1561            ["TestNestedCycle2API",
1562             "TestNestedCycle3API",
1563             "TestNestedCycle1API"])
1564        self.assertEqual(sorted(cycle2APIDef.GetPropertyNames()),
1565                         expectedPropNames)
1566        self.assertEqual(cycle2APIDef.GetDocumentation(),
1567            "Test nested single apply API schema with a cycle #2")
1568
1569        cycle3APIDef = Usd.SchemaRegistry().FindAppliedAPIPrimDefinition(
1570            "TestNestedCycle3API")
1571        self.assertTrue(cycle3APIDef)
1572        self.assertEqual(cycle3APIDef.GetAppliedAPISchemas(),
1573            ["TestNestedCycle3API",
1574             "TestNestedCycle1API",
1575             "TestNestedCycle2API"])
1576        self.assertEqual(sorted(cycle3APIDef.GetPropertyNames()),
1577                         expectedPropNames)
1578        self.assertEqual(cycle3APIDef.GetDocumentation(),
1579            "Test nested single apply API schema with a cycle #3")
1580
1581    def test_ConcreteTypeWithBuiltinNestedAPISchemas(self):
1582        """
1583        Tests a concrete schema type with built-in API schemas that include
1584        other API schemas.
1585        """
1586        stage = Usd.Stage.CreateInMemory()
1587
1588        # Simple helper for testing that a prim has expected attributes that
1589        # resolve to expected values.
1590        def _VerifyAttrValues(prim, expectedAttrValues):
1591            values = {name : prim.GetAttribute(name).Get()
1592                         for name in expectedAttrValues.keys()}
1593            self.assertEqual(values, expectedAttrValues)
1594
1595        # Test a typed prim whose concrete typed schema has built-in API schemas
1596        # that nest other API schemas.
1597        typedPrim = stage.DefinePrim(
1598            "/TypedPrim", "TestWithBuiltinNestedAppliedSchema")
1599
1600        # The prim has a type but no authored API schemas.
1601        self.assertEqual(typedPrim.GetPrimTypeInfo().GetTypeName(),
1602                         "TestWithBuiltinNestedAppliedSchema")
1603        self.assertEqual(typedPrim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
1604
1605        # The composed API schemas are fully expanded from the two built-in API
1606        # schemas of the TestWithBuiltinNestedAppliedSchema type.
1607        expectedAPISchemas = [
1608            # Expanded API schemas from built-in TestNestedOuterSingleApplyAPI
1609            "TestNestedOuterSingleApplyAPI",
1610            "TestMultiApplyAPI:foo",
1611            "TestNestedInnerSingleApplyAPI",
1612            "TestSingleApplyAPI",
1613            "TestMultiApplyAPI:bar",
1614            # Expanded API schemas from built-in TestNestedCycle1API
1615            "TestNestedCycle1API",
1616            "TestNestedCycle2API",
1617            "TestNestedCycle3API"]
1618        self.assertEqual(typedPrim.GetAppliedSchemas(),
1619                         expectedAPISchemas)
1620
1621        # Properties come from the type and all composed built-in APIs
1622        expectedPropNames = [
1623            # Properties from expanded built-in TestNestedCycle1API
1624            "cycle1:token_attr",
1625            "cycle2:token_attr",
1626            "cycle3:token_attr",
1627            "cycle:int_attr",
1628            # Properties from expanded built-in TestNestedOuterSingleApplyAPI
1629            "innerSingle:int_attr",
1630            "innerSingle:relationship",
1631            "innerSingle:token_attr",
1632            "multi:bar:bool_attr",
1633            "multi:bar:relationship",
1634            "multi:bar:token_attr",
1635            "multi:foo:bool_attr",
1636            "multi:foo:relationship",
1637            "multi:foo:token_attr",
1638            "outerSingle:int_attr",
1639            "outerSingle:relationship",
1640            "outerSingle:token_attr",
1641            "single:bool_attr",
1642            "single:relationship",
1643            "single:token_attr",
1644            # Properties from the prim type TestWithBuiltinNestedAppliedSchema
1645            "testAttr",
1646            "testRel"]
1647        self.assertEqual(typedPrim.GetPropertyNames(), expectedPropNames)
1648
1649        # Get the prim definition for the concrete typed schema and verify its
1650        # applied API schemas and properties match what was imparted on the
1651        # prim.
1652        typedPrimDef = \
1653            Usd.SchemaRegistry().FindConcretePrimDefinition(
1654                "TestWithBuiltinNestedAppliedSchema")
1655        self.assertTrue(typedPrimDef)
1656        self.assertEqual(typedPrimDef.GetAppliedAPISchemas(),
1657                         expectedAPISchemas)
1658        self.assertEqual(sorted(typedPrimDef.GetPropertyNames()),
1659                         expectedPropNames)
1660        self.assertEqual(typedPrimDef.GetDocumentation(),
1661            "Test with built-in nested API schemas")
1662
1663    @unittest.skipIf(Tf.GetEnvSetting('USD_DISABLE_AUTO_APPLY_API_SCHEMAS'),
1664                    "Auto apply API schemas are disabled")
1665    def test_APISchemasAutoAppliedToAPISchemas(self):
1666        """
1667        Tests the behaviors of API schemas that are auto applied to other API
1668        schemas.
1669        """
1670        stage = Usd.Stage.CreateInMemory()
1671
1672        # Define a prim with an empty type name and apply TestAutoAppliedToAPI.
1673        # TestAutoAppliedToAPI includes other API schemas through a combination
1674        # of built-in APIs and auto applied APIs.
1675        prim = stage.DefinePrim("/Prim")
1676        prim.ApplyAPI(self.AutoAppliedToAPIType)
1677        self.assertEqual(prim.GetTypeName(), '')
1678        self.assertEqual(prim.GetAppliedSchemas(), [
1679            # Authored applied API
1680            "TestAutoAppliedToAPI",
1681            # Built-in API of 'TestAutoAppliedToAPI'
1682            "TestMultiApplyAPI:builtin",
1683            # Defined in plugin metadata that 'TestMultiApplyAPI:autoFoo' auto
1684            # applies to 'TestAutoAppliedToAPI'
1685            "TestMultiApplyAPI:autoFoo",
1686            # 'TestSingleApplyAPI' defines in its schema def that it auto
1687            # applies to 'TestAutoAppliedToAPI'
1688            "TestSingleApplyAPI"])
1689        self.assertTrue(prim.HasAPI(self.AutoAppliedToAPIType))
1690        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "builtin"))
1691        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "autoFoo"))
1692        self.assertTrue(prim.HasAPI(self.SingleApplyAPIType))
1693
1694        # Prim's authored type is empty and its authored API schemas is just the
1695        # single authored schema.
1696        self.assertEqual(prim.GetPrimTypeInfo().GetTypeName(), '')
1697        self.assertEqual(prim.GetPrimTypeInfo().GetAppliedAPISchemas(),
1698                         ["TestAutoAppliedToAPI"])
1699
1700        # Prim's built-in properties come from all of the applied API schemas.
1701        self.assertEqual(prim.GetPropertyNames(), [
1702            "multi:autoFoo:bool_attr",
1703            "multi:autoFoo:relationship",
1704            "multi:autoFoo:token_attr",
1705            "multi:builtin:bool_attr",
1706            "multi:builtin:relationship",
1707            "multi:builtin:token_attr",
1708            "single:bool_attr",
1709            "single:relationship",
1710            "single:token_attr",
1711            "testAttr",
1712            "testRel"])
1713
1714        # Define a prim with an empty type name and apply
1715        # TestNestedAutoAppliedToAPI.
1716        # TestAutoAppliedToAPI auto applies to TestNestedAutoAppliedToAPI and
1717        # brings with it all of the API schemas that are built-in to it and auto
1718        # applied to it.
1719        prim = stage.DefinePrim("/Prim2")
1720        prim.ApplyAPI(self.NestedAutoAppliedToAPIType)
1721        self.assertEqual(prim.GetTypeName(), '')
1722        self.assertEqual(prim.GetAppliedSchemas(), [
1723            # Authored applied API
1724            "TestNestedAutoAppliedToAPI",
1725            # Built-in API of 'TestNestedAutoAppliedToAPI'
1726            "TestMultiApplyAPI:foo",
1727            # 'TestAutoAppliedToAPI' defines in its schema def that it auto
1728            # applies to 'TestNestedAutoAppliedToAPI'
1729            "TestAutoAppliedToAPI",
1730            # Built-in API of 'TestAutoAppliedToAPI'
1731            "TestMultiApplyAPI:builtin",
1732            # Defined in plugin metadata that 'TestMultiApplyAPI:autoFoo' auto
1733            # applies to 'TestAutoAppliedToAPI'
1734            "TestMultiApplyAPI:autoFoo",
1735            # 'TestSingleApplyAPI' defines in its schema def that it auto
1736            # applies to 'TestAutoAppliedToAPI'
1737            "TestSingleApplyAPI"])
1738        self.assertTrue(prim.HasAPI(self.NestedAutoAppliedToAPIType))
1739        self.assertTrue(prim.HasAPI(self.AutoAppliedToAPIType))
1740        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "foo"))
1741        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "builtin"))
1742        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "autoFoo"))
1743        self.assertTrue(prim.HasAPI(self.SingleApplyAPIType))
1744
1745        # Prim's authored type is empty and its authored API schemas is just the
1746        # single authored schema.
1747        self.assertEqual(prim.GetPrimTypeInfo().GetTypeName(), '')
1748        self.assertEqual(prim.GetPrimTypeInfo().GetAppliedAPISchemas(),
1749                         ["TestNestedAutoAppliedToAPI"])
1750
1751        # Prim's built-in properties come from all of the applied API schemas.
1752        self.assertEqual(prim.GetPropertyNames(), [
1753            "multi:autoFoo:bool_attr",
1754            "multi:autoFoo:relationship",
1755            "multi:autoFoo:token_attr",
1756            "multi:builtin:bool_attr",
1757            "multi:builtin:relationship",
1758            "multi:builtin:token_attr",
1759            "multi:foo:bool_attr",
1760            "multi:foo:relationship",
1761            "multi:foo:token_attr",
1762            "single:bool_attr",
1763            "single:relationship",
1764            "single:token_attr",
1765            "testAttr",
1766            "testRel"])
1767
1768        # Define a prim with type name TestNestedAutoAppliedToAPIAppliedToPrim.
1769        # TestNestedAutoAppliedToAPI is defined to auto apply to this prim type
1770        # and brings with it all of the API schemas that are built-in to it and
1771        # auto applied to it.
1772        prim = stage.DefinePrim("/Prim3",
1773                                "TestNestedAutoAppliedToAPIAppliedToPrim")
1774        self.assertEqual(prim.GetTypeName(),
1775                         'TestNestedAutoAppliedToAPIAppliedToPrim')
1776        self.assertEqual(prim.GetAppliedSchemas(), [
1777            # 'TestNestedAutoAppliedToAPI' defines in its schema def that it
1778            # auto applies to 'TestNestedAutoAppliedToAPIAppliedToPrim'
1779            "TestNestedAutoAppliedToAPI",
1780            # Built-in API of 'TestNestedAutoAppliedToAPI'
1781            "TestMultiApplyAPI:foo",
1782            # 'TestAutoAppliedToAPI' defines in its schema def that it auto
1783            # applies to 'TestNestedAutoAppliedToAPI'
1784            "TestAutoAppliedToAPI",
1785            # Built-in API of 'TestAutoAppliedToAPI'
1786            "TestMultiApplyAPI:builtin",
1787            # Defined in plugin metadata that 'TestMultiApplyAPI:autoFoo' auto
1788            # applies to 'TestAutoAppliedToAPI'
1789            "TestMultiApplyAPI:autoFoo",
1790            # 'TestSingleApplyAPI' defines in its schema def that it auto
1791            # applies to 'TestAutoAppliedToAPI'
1792            "TestSingleApplyAPI"])
1793
1794        # Prim's authored applied API schemas is empty as the API schemas are
1795        # part of the type (through auto apply).
1796        self.assertEqual(prim.GetPrimTypeInfo().GetTypeName(),
1797                         'TestNestedAutoAppliedToAPIAppliedToPrim')
1798        self.assertEqual(prim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
1799
1800        # Prim's built-in properties come from all of the applied API schemas.
1801        self.assertTrue(prim.HasAPI(self.NestedAutoAppliedToAPIType))
1802        self.assertTrue(prim.HasAPI(self.AutoAppliedToAPIType))
1803        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "foo"))
1804        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "builtin"))
1805        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "autoFoo"))
1806        self.assertTrue(prim.HasAPI(self.SingleApplyAPIType))
1807        self.assertEqual(prim.GetPropertyNames(), [
1808            "multi:autoFoo:bool_attr",
1809            "multi:autoFoo:relationship",
1810            "multi:autoFoo:token_attr",
1811            "multi:builtin:bool_attr",
1812            "multi:builtin:relationship",
1813            "multi:builtin:token_attr",
1814            "multi:foo:bool_attr",
1815            "multi:foo:relationship",
1816            "multi:foo:token_attr",
1817            "single:bool_attr",
1818            "single:relationship",
1819            "single:token_attr",
1820            "testAttr",
1821            "testRel"])
1822
1823    @unittest.skipIf(not Tf.GetEnvSetting('USD_DISABLE_AUTO_APPLY_API_SCHEMAS'),
1824                    "Auto apply API schemas are NOT disabled")
1825    def test_APISchemasAutoAppliedToAPISchemas_AutoApplyDisabled(self):
1826        """
1827        Tests the behaviors of API schemas that are auto applied to other API
1828        schemas.
1829        """
1830        stage = Usd.Stage.CreateInMemory()
1831
1832        # Define a prim with an empty type name and apply TestAutoAppliedToAPI.
1833        # TestAutoAppliedAPI includes other API schemas through a combination of
1834        # built-in APIs and auto applied APIs. The auto applied schemas are
1835        # disabled in the this test case.
1836        prim = stage.DefinePrim("/Prim")
1837        prim.ApplyAPI(self.AutoAppliedToAPIType)
1838        self.assertEqual(prim.GetTypeName(), '')
1839        self.assertEqual(prim.GetAppliedSchemas(), [
1840            # Authored applied API
1841            "TestAutoAppliedToAPI",
1842            # Built-in API of 'TestAutoAppliedToAPI'
1843            "TestMultiApplyAPI:builtin"
1844            # 'TestMultiApplyAPI:autoFoo' and 'TestSingleApplyAPI' would be
1845            # auto applied so they do not show up when auto apply is disabled
1846            ])
1847        self.assertTrue(prim.HasAPI(self.AutoAppliedToAPIType))
1848        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "builtin"))
1849        self.assertFalse(prim.HasAPI(self.MultiApplyAPIType, "autoFoo"))
1850        self.assertFalse(prim.HasAPI(self.SingleApplyAPIType))
1851
1852        # Prim's authored type is empty and its authored API schemas is just the
1853        # single authored schema.
1854        self.assertEqual(prim.GetPrimTypeInfo().GetTypeName(), '')
1855        self.assertEqual(prim.GetPrimTypeInfo().GetAppliedAPISchemas(),
1856                         ["TestAutoAppliedToAPI"])
1857
1858        # Prim's built-in properties come from all of the applied API schemas.
1859        self.assertEqual(prim.GetPropertyNames(), [
1860            "multi:builtin:bool_attr",
1861            "multi:builtin:relationship",
1862            "multi:builtin:token_attr",
1863            "testAttr",
1864            "testRel"])
1865
1866        # Define a prim with an empty type name and apply
1867        # TestNestedAutoAppliedToAPI.
1868        # TestAutoAppliedAPI auto applies to TestNestedAutoAppliedToAPI but
1869        # auto apply is disabled in this test case.
1870        prim = stage.DefinePrim("/Prim2")
1871        prim.ApplyAPI(self.NestedAutoAppliedToAPIType)
1872        self.assertEqual(prim.GetTypeName(), '')
1873        self.assertEqual(prim.GetAppliedSchemas(), [
1874            # Authored applied API
1875            "TestNestedAutoAppliedToAPI",
1876            # Built-in API of 'TestNestedAutoAppliedToAPI'
1877            "TestMultiApplyAPI:foo",
1878            # 'TestAutoAppliedToAPI' would be auto applied it doesn't show up
1879            # when auto apply is disabled, nor do any of the API schemas that
1880            # would be included by it.
1881            ])
1882        self.assertTrue(prim.HasAPI(self.NestedAutoAppliedToAPIType))
1883        self.assertFalse(prim.HasAPI(self.AutoAppliedToAPIType))
1884        self.assertTrue(prim.HasAPI(self.MultiApplyAPIType, "foo"))
1885        self.assertFalse(prim.HasAPI(self.MultiApplyAPIType, "builtin"))
1886        self.assertFalse(prim.HasAPI(self.MultiApplyAPIType, "autoFoo"))
1887        self.assertFalse(prim.HasAPI(self.SingleApplyAPIType))
1888
1889        # Prim's authored type is empty and its authored API schemas is just the
1890        # single authored schema.
1891        self.assertEqual(prim.GetPrimTypeInfo().GetTypeName(), '')
1892        self.assertEqual(prim.GetPrimTypeInfo().GetAppliedAPISchemas(),
1893                         ["TestNestedAutoAppliedToAPI"])
1894
1895        # Prim's built-in properties come from all of the applied API schemas.
1896        self.assertEqual(prim.GetPropertyNames(), [
1897            "multi:foo:bool_attr",
1898            "multi:foo:relationship",
1899            "multi:foo:token_attr"])
1900
1901        # Define a prim with type name TestNestedAutoAppliedToAPIAppliedToPrim.
1902        # TestNestedAutoAppliedToAPI is defined to auto apply to this prim type
1903        # auto apply is disabled in this test case.
1904        prim = stage.DefinePrim("/Prim3",
1905                                "TestNestedAutoAppliedToAPIAppliedToPrim")
1906        self.assertEqual(prim.GetTypeName(),
1907                         'TestNestedAutoAppliedToAPIAppliedToPrim')
1908        # 'TestNestedAutoAppliedToAPI' would be auto applied so it doesn't show
1909        # up when auto apply is disabled, nor do any of the API schemas that
1910        # would be included by it.
1911        self.assertEqual(prim.GetAppliedSchemas(), [])
1912
1913        self.assertEqual(prim.GetPrimTypeInfo().GetTypeName(),
1914                         'TestNestedAutoAppliedToAPIAppliedToPrim')
1915        self.assertEqual(prim.GetPrimTypeInfo().GetAppliedAPISchemas(), [])
1916        self.assertEqual(prim.GetPropertyNames(), [])
1917
1918
1919if __name__ == "__main__":
1920    unittest.main()
1921