def test_Basic(self): # generate a test layer with a default attr and time sample attr layer = Sdf.Layer.CreateAnonymous() prim = Sdf.PrimSpec(layer, "Sphere", Sdf.SpecifierDef) # configure a default attr defAttr = Sdf.AttributeSpec(prim, "visibility", Sdf.ValueTypeNames.Token) defAttr.default = "visible" # configure a time sampled attr sampleAttr = Sdf.AttributeSpec(prim, "xformOp:transform", Sdf.ValueTypeNames.Double) layer.SetTimeSample(sampleAttr.path, 101, 101.0) layer.SetTimeSample(sampleAttr.path, 102, 102.0) layer.SetTimeSample(sampleAttr.path, 103, 103.0) layer.SetTimeSample(sampleAttr.path, 104, 104.0) # Test time sample based API for i in range(101, 105): self.assertEqual(layer.QueryTimeSample(sampleAttr.path, i), i) layer.SetTimeSample(sampleAttr.path, i, Sdf.ValueBlock()) self.assertEqual(layer.QueryTimeSample(sampleAttr.path, i), Sdf.ValueBlock()) #Test default value API self.assertEqual(defAttr.default, 'visible') defAttr.default = Sdf.ValueBlock() self.assertEqual(defAttr.default, Sdf.ValueBlock())
def test_PropertyChanges(self): """Test that changes to properties that affect masters cause the correct notifications to be sent.""" s = OpenStage('basic/root.usda') nl = NoticeListener() ValidateExpectedInstances(s, { '/__Master_1': ['/World/sets/Set_1/Prop_1', '/World/sets/Set_1/Prop_2'] }) instancedPropLayer = Sdf.Layer.Find('basic/prop.usda') # Author to an attribute on a child of the referenced prop asset. # This should cause change notices for the corresponding attribute # on the master prim as well as any other un-instanced prim that # references that prop. print "-" * 60 print "Adding new attribute spec to child of referenced prop" primSpec = instancedPropLayer.GetPrimAtPath('/Prop/geom/Scope') attrSpec = Sdf.AttributeSpec(primSpec, "attr", Sdf.ValueTypeNames.Int) ValidateExpectedChanges(nl, ['/World/sets/Set_1/Prop_3/geom/Scope.attr', '/__Master_1/geom/Scope.attr']) print "-" * 60 print "Changing value for attribute spec on child of referenced prop" attrSpec.default = 1 ValidateExpectedChanges(nl, expectedChangedInfo = [ '/World/sets/Set_1/Prop_3/geom/Scope.attr', '/__Master_1/geom/Scope.attr']) # Author to an attribute on the referenced prop asset. This should # *not* cause change notices on the master prim, since master prims # don't have any properties. Instead, these should cause change # notices on all of the affected instances. print "-" * 60 print "Adding new attribute spec to referenced prop" primSpec = instancedPropLayer.GetPrimAtPath('/Prop') attrSpec = Sdf.AttributeSpec(primSpec, "attr", Sdf.ValueTypeNames.Int) ValidateExpectedChanges(nl, ['/World/sets/Set_1/Prop_1.attr', '/World/sets/Set_1/Prop_2.attr', '/World/sets/Set_1/Prop_3.attr']) print "-" * 60 print "Changing value for attribute spec on referenced prop" attrSpec.default = 1 ValidateExpectedChanges(nl, expectedChangedInfo = [ '/World/sets/Set_1/Prop_1.attr', '/World/sets/Set_1/Prop_2.attr', '/World/sets/Set_1/Prop_3.attr'])
def test_InertPrimRemovalChanges(self): subLayer = Sdf.Layer.CreateAnonymous() subParentSpec = Sdf.PrimSpec(subLayer, 'Parent', Sdf.SpecifierDef) subChildSpec = Sdf.PrimSpec(subParentSpec, 'Child', Sdf.SpecifierDef) subAttrSpec = Sdf.AttributeSpec(subChildSpec, 'attr', Sdf.ValueTypeNames.Double) subAttrSpec.default = 1.0 rootLayer = Sdf.Layer.CreateAnonymous() rootParentSpec = Sdf.PrimSpec(rootLayer, 'Parent', Sdf.SpecifierOver) rootChildSpec = Sdf.PrimSpec(rootParentSpec, 'Child', Sdf.SpecifierOver) rootAttrSpec = Sdf.AttributeSpec(rootChildSpec, 'attr', Sdf.ValueTypeNames.Double) rootLayer.subLayerPaths.append(subLayer.identifier) pcp = Pcp.Cache(Pcp.LayerStackIdentifier(rootLayer)) (pi, err) = pcp.ComputePrimIndex('/Parent') self.assertEqual(err, []) self.assertEqual(pi.primStack, [rootParentSpec, subParentSpec]) (pi, err) = pcp.ComputePrimIndex('/Parent/Child') self.assertEqual(err, []) self.assertEqual(pi.primStack, [rootChildSpec, subChildSpec]) (pi, err) = pcp.ComputePropertyIndex('/Parent/Child.attr') self.assertEqual(err, []) self.assertEqual(pi.propertyStack, [rootAttrSpec, subAttrSpec]) revCount = pcp.GetUsedLayersRevision() with Pcp._TestChangeProcessor(pcp) as cp: del rootLayer.pseudoRoot.nameChildren['Parent'] self.assertFalse(rootParentSpec) self.assertFalse(rootChildSpec) self.assertFalse(rootAttrSpec) self.assertEqual(cp.GetSignificantChanges(), []) self.assertEqual( cp.GetSpecChanges(), ['/Parent', '/Parent/Child', '/Parent/Child.attr']) self.assertEqual(cp.GetPrimChanges(), []) self.assertEqual(revCount, pcp.GetUsedLayersRevision()) (pi, err) = pcp.ComputePrimIndex('/Parent') self.assertEqual(err, []) self.assertEqual(pi.primStack, [subParentSpec]) (pi, err) = pcp.ComputePrimIndex('/Parent/Child') self.assertEqual(err, []) self.assertEqual(pi.primStack, [subChildSpec]) (pi, err) = pcp.ComputePropertyIndex('/Parent/Child.attr') self.assertEqual(err, []) self.assertEqual(pi.propertyStack, [subAttrSpec])
def test_InvalidName(self): layer = Sdf.Layer.CreateAnonymous() prim = Sdf.PrimSpec(layer, "test", Sdf.SpecifierDef, "bogus_type") for badName in ['', 'a.b', '<ab>', 'a[]', 'a/']: with self.assertRaises(RuntimeError): badAttr = Sdf.AttributeSpec(prim, badName, Sdf.ValueTypeNames.Int)
def test_153956(self): from pxr import Sdf # Create a crate-backed .usd file and populate it with an # attribute connection. These files do not store specs for # targets/connections, so there will be an entry in the # connectionChildren list but no corresponding spec. layer = Sdf.Layer.CreateAnonymous(".usd") primSpec = Sdf.CreatePrimInLayer(layer, "/Test") attrSpec = Sdf.AttributeSpec(primSpec, "attr", Sdf.ValueTypeNames.Float) # -- Adding item to prependedItems list..." attrSpec.connectionPathList.prependedItems.append("/Test.prependedItem") # Transfer the contents of the crate-backed .usd file into an # memory-backed .usda file. These file *do* store specs for # targets/connections. newLayer = Sdf.Layer.CreateAnonymous(".usda") newLayer.TransferContent(layer) primSpec = newLayer.GetPrimAtPath("/Test") attrSpec = primSpec.properties["attr"] # Adding an item to the explicitItems list changes to listOp to # explicit mode, but does not clear any existing connectionChildren. attrSpec.connectionPathList.explicitItems.append("/Test.explicitItem") # Prior to the fix, this caused a failed verify b/c an entry exists in # the connectionChildren list for which there is no corresponding spec. primSpec.name = "Test2"
def as_sdf(): """Run the main execution of the current script.""" layer = Sdf.Layer.CreateAnonymous() prim_spec = Sdf.CreatePrimInLayer(layer, "/root") prim_spec.specifier = Sdf.SpecifierDef attribute_spec = Sdf.AttributeSpec(prim_spec, "some_name", Sdf.ValueTypeNames.Int) attribute_spec.custom = True attribute_spec.default = 8 layer.SetTimeSample(attribute_spec.path, 10.5, 9) print(layer.ExportToString())
def _TestRoundTrippingValue(self, typeName, value): # Create a layer with custom attribute of this type, set its value, # export it to a string, reimport it from a string and assert that it # round-tripped the value correctly. layer = Sdf.Layer.CreateAnonymous() prim = Sdf.CreatePrimInLayer(layer, '/test') attrSpec = Sdf.AttributeSpec(prim, 'testAttr', Sdf.ValueTypeNames.Find(typeName)) attrSpec.default = value layerAsString = layer.ExportToString() # Now create a new layer and import it. layer = Sdf.Layer.CreateAnonymous() layer.ImportFromString(layerAsString) self.assertEqual( layer.GetAttributeAtPath('/test.testAttr').default, value)
def test_Rename(self): layer = Sdf.Layer.CreateAnonymous() prim = Sdf.PrimSpec(layer, "test", Sdf.SpecifierDef, "bogus_type") attr = Sdf.AttributeSpec(prim, 'numCrvs', Sdf.ValueTypeNames.Int) attr.name = 'numberOfCurves' self.assertEqual(attr.name, 'numberOfCurves') # Check invalid cases. for badName in ['', 'a.b', '<ab>', 'a[]', 'a/']: oldName = attr.name self.assertNotEqual(oldName, '') self.assertNotEqual(oldName, badName) with self.assertRaises(Tf.ErrorException): attr.name = badName self.assertEqual(attr.name, oldName)
def test_Path(self): layer = Sdf.Layer.CreateAnonymous() prim = Sdf.PrimSpec(layer, "test", Sdf.SpecifierDef, "bogus_type") attr = Sdf.AttributeSpec(prim, 'numCrvs', Sdf.ValueTypeNames.Int) self.assertEqual(attr.path, Sdf.Path('/' + prim.name + '.' + attr.name)) self.assertEqual(prim.GetAttributeAtPath(Sdf.Path('.' + attr.name)), attr) self.assertEqual(prim.GetObjectAtPath(Sdf.Path('.' + attr.name)), attr) self.assertEqual(layer.GetAttributeAtPath(attr.path), attr) self.assertEqual(layer.GetObjectAtPath(attr.path), attr) # Try a bad path... access a relational attribute of an attribute! self.assertEqual( prim.GetAttributeAtPath(Sdf.Path('.' + attr.name + '[targ].attr')), None) # dormant object path, for code coverage del prim.properties[attr.name] self.assertTrue(attr.expired)
def test_BasicMetadataCases(self): s = Usd.Stage.CreateInMemory() spherePrim = UsdGeom.Sphere.Define(s, '/sphere').GetPrim() radius = spherePrim.GetAttribute('radius') self.assertTrue(radius.HasMetadata('custom')) self.assertTrue(radius.HasMetadata('typeName')) self.assertTrue(radius.HasMetadata('variability')) self.assertTrue(radius.IsDefined()) self.assertTrue(not radius.IsCustom()) self.assertEqual(radius.GetTypeName(), 'double') allMetadata = radius.GetAllMetadata() self.assertEqual(allMetadata['typeName'], 'double') self.assertEqual(allMetadata['variability'], Sdf.VariabilityVarying) self.assertEqual(allMetadata['custom'], False) # Author a custom property spec. layer = s.GetRootLayer() sphereSpec = layer.GetPrimAtPath('/sphere') radiusSpec = Sdf.AttributeSpec(sphereSpec, 'radius', Sdf.ValueTypeNames.Double, variability=Sdf.VariabilityUniform, declaresCustom=True) self.assertTrue(radiusSpec.custom) self.assertEqual(radiusSpec.variability, Sdf.VariabilityUniform) # Definition should win. self.assertTrue(not radius.IsCustom()) self.assertEqual(radius.GetVariability(), Sdf.VariabilityVarying) allMetadata = radius.GetAllMetadata() self.assertEqual(allMetadata['typeName'], 'double') self.assertEqual(allMetadata['variability'], Sdf.VariabilityVarying) self.assertEqual(allMetadata['custom'], False) # List fields on 'visibility' attribute -- should include 'allowedTokens', # provided by the property definition. visibility = spherePrim.GetAttribute('visibility') self.assertTrue(visibility.IsDefined()) self.assertTrue('allowedTokens' in visibility.GetAllMetadata()) # Assert that attribute fallback values are returned for builtin attributes. do = spherePrim.GetAttribute('primvars:displayOpacity') self.assertTrue(do.IsDefined()) self.assertTrue(do.Get() is None)
def test_Inertness(self): # Test attribute-specific 'IsInert()' and 'hasOnlyRequiredFields' # behavior. # # Having any connections render the spec non-inert and having more than # only required fields. This is important due to the 'remove if inert' # cleanup step that automatically runs after any call to ClearInfo. layer = Sdf.Layer.CreateAnonymous() prim = Sdf.PrimSpec(layer, "test", Sdf.SpecifierDef, "bogus_type") attr = Sdf.AttributeSpec(prim, 'testAttr', Sdf.ValueTypeNames.Int) self.assertTrue(attr) self.assertFalse(attr.IsInert()) self.assertTrue(attr.hasOnlyRequiredFields) attr.connectionPathList.explicitItems.append('/connection.path') self.assertFalse(attr.IsInert()) self.assertFalse(attr.hasOnlyRequiredFields) attr.connectionPathList.ClearEdits() self.assertEqual(len(attr.connectionPathList.explicitItems), 0) self.assertFalse(attr.IsInert()) self.assertTrue(attr.hasOnlyRequiredFields)
def test_ReadAndSaveCrateFileVersion07And09(self): """Test that the payload conversion necessary from 07 to 08 files still happens correctly when a change requires a direct upgrade to 09""" # Copy the test file so we don't pollute other tests. filename = 'crate07SinglePayloadCopy_0709.usdc' shutil.copyfile('crate07SinglePayload.usdc', filename) # Assert the crate file we're going to open is an older version '0.7.0', # before payload list op support was added. self._VerifyCrateVersion07(filename) # Open the crate file layer and verify it matches the single payload # prims. layer = Sdf.Layer.FindOrOpen(filename) self._VerifyLayerPrims(layer) # Add a timecode valued attribute and set its default value. This will # require a crate version update. payloadNoOpinion = layer.GetPrimAtPath('/PayloadNoOpinion') attr = Sdf.AttributeSpec(payloadNoOpinion, "TimeCode", Sdf.ValueTypeNames.TimeCode) self.assertTrue(attr) attr.default = Sdf.TimeCode(10) self.assertEqual(attr.default, 10) # Save the layer and verify the 0.9 version self.assertTrue(layer.Save()) self._VerifyCrateVersion09(filename) # Force reload the saved layer and verify that we have all the prims # and all the same payloads exist and that we also have the timecode # attribute with its default. self.assertTrue(layer.Reload(force=True)) self._VerifyLayerPrims(layer) self.assertEqual( layer.GetPrimAtPath( '/PayloadNoOpinion').attributes["TimeCode"].default, 10)
def test_USD_5196(self): from pxr import Usd, Sdf, Vt, Tf import os, random # Test that usdc files corrupted by truncation (such that the table of # contents is past the end of the file) are detected and fail to open # with an error. with Tf.NamedTemporaryFile(suffix=".usdc") as f: layer = Sdf.Layer.CreateNew(f.name) foo = Sdf.CreatePrimInLayer(layer, '/foo') attr = Sdf.AttributeSpec(foo, 'attr', Sdf.ValueTypeNames.IntArray) ints = list(range(1024**2)) random.shuffle(ints) attr.default = Vt.IntArray(ints) layer.Save() del layer # Now truncate layer to corrupt it. fobj = open(f.name, "r+") size = os.path.getsize(f.name) fobj.truncate(size / 2) fobj.close() # Attempting to open the file should raise an exception. with self.assertRaises(Tf.ErrorException): layer = Sdf.Layer.FindOrOpen(f.name)
def UpdateSchemaWithSdrNode(schemaLayer, sdrNode): """ Updates the given schemaLayer with primSpec and propertySpecs from sdrNode metadata. It consume the following attributes (that manifest as Sdr metadata) in addition to many of the standard Sdr metadata specified and parsed (via its parser plugin). Node Level Metadata: - "schemaName": Name of the new schema populated from the given sdrNode (Required) - "schemaKind": Specifies the UsdSchemaKind for the schema being populated from the sdrNode. (note that this does not support multi-applied schema kinds). - "schemaBase": Base schema from which the new schema should inherit from. Note this defaults to "APISchemaBase" for an api schema or "Typed" for a concrete scheme. - "usdSchemaClass": Specified the equivalent schema directly generated by USD (sourceType: USD). This is used to make sure duplicate properties already specified in the USD schema are not populated in the new API schema. Note this is only used when we are dealing with an API schema. - "apiSchemaAutoApplyTo": The Schemas to which the sdrNode populated (API) schema will autoApply to. - "tfTypeNameSuffix": Class name which will get registered with TfType system. This gets appended to the domain name to register with TfType. Property Level Metadata: - USD_VARIABILITY: A property level metadata, which specified a specific sdrNodeProperty should its usd variability set to Uniform or Varying. - USD_SUPPRESS_PROPERTY: A property level metadata, which determines if the property should be suppressed from translation from args to property spec. """ # Early exit on invalid parameters if not schemaLayer: Tf.Warn("No Schema Layer provided") return if not sdrNode: Tf.Warn("No valid sdrNode provided") return sdrNodeMetadata = sdrNode.GetMetadata() if SchemaDefiningKeys.SCHEMA_NAME not in sdrNodeMetadata: Tf.Warn("Sdr Node does not define a schema name metadata.") return schemaName = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_NAME] if not Tf.IsValidIdentifier(schemaName): Tf.RaiseRuntimeError("schemaName (%s) is an invalid identifier; " "Provide a valid USD identifer for schemaName, example (%s) " %(schemaName, Tf.MakeValidIdentifier(schemaName))) tfTypeNameSuffix = None if SchemaDefiningKeys.TF_TYPENAME_SUFFIX in sdrNodeMetadata: tfTypeNameSuffix = sdrNodeMetadata[SchemaDefiningKeys.TF_TYPENAME_SUFFIX] if not Tf.IsValidIdentifier(tfTypeNameSuffix): Tf.RaiseRuntimeError("tfTypeNameSuffix (%s) is an invalid " \ "identifier" %(tfTypeNameSuffix)) if SchemaDefiningKeys.SCHEMA_KIND not in sdrNodeMetadata: schemaKind = SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaKind = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_KIND] # Note: We are not working on dynamic multiapply schemas right now. isAPI = schemaKind == SchemaDefiningMiscConstants.SINGLE_APPLY_SCHEMA # Fix schemaName and warn if needed if isAPI and \ not schemaName.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created is " "an API schema, fixing schemaName to reflect that") schemaName = schemaName + SchemaDefiningMiscConstants.API_STRING if isAPI and tfTypeNameSuffix and \ not tfTypeNameSuffix.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created " "is an API schema, fixing tfTypeNameSuffix to reflect that") tfTypeNameSuffix = tfTypeNameSuffix + \ SchemaDefiningMiscConstants.API_STRING if SchemaDefiningKeys.SCHEMA_BASE not in sdrNodeMetadata: Tf.Warn("No schemaBase specified in node metadata, defaulting to " "APISchemaBase for API schemas else Typed") schemaBase = SchemaDefiningMiscConstants.API_SCHEMA_BASE if isAPI \ else SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaBase = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_BASE] apiSchemaAutoApplyTo = None if SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO in sdrNodeMetadata: apiSchemaAutoApplyTo = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO] \ .split('|') usdSchemaClass = None if isAPI and SchemaDefiningKeys.USD_SCHEMA_CLASS in sdrNodeMetadata: usdSchemaClass = \ sdrNodeMetadata[SchemaDefiningKeys.USD_SCHEMA_CLASS] primSpec = schemaLayer.GetPrimAtPath(schemaName) if (primSpec): # if primSpec already exist, remove entirely and recreate using the # parsed sdr node if primSpec.nameParent: del primSpec.nameParent.nameChildren[primSpec.name] else: del primSpec.nameRoot.nameChildren[primSpec.name] primSpec = Sdf.PrimSpec(schemaLayer, schemaName, Sdf.SpecifierClass, "" if isAPI else schemaName) primSpec.inheritPathList.explicitItems = ["/" + schemaBase] primSpecCustomData = {} if isAPI: primSpecCustomData["apiSchemaType"] = schemaKind if tfTypeNameSuffix: # Defines this classname for TfType system # can help avoid duplicate prefix with domain and className # Tf type system will automatically pick schemaName as tfTypeName if # this is not set! primSpecCustomData["className"] = tfTypeNameSuffix if apiSchemaAutoApplyTo: primSpecCustomData['apiSchemaAutoApplyTo'] = \ Vt.TokenArray(apiSchemaAutoApplyTo) primSpec.customData = primSpecCustomData doc = sdrNode.GetHelp() if doc != "": primSpec.documentation = doc # gather properties from node directly generated from USD (sourceType: USD) # Use the usdSchemaClass tag when the generated schema being defined is an # API schema usdSchemaNode = None if usdSchemaClass: reg = Sdr.Registry() usdSchemaNode = reg.GetNodeByIdentifierAndType(usdSchemaClass, SchemaDefiningMiscConstants.USD_SOURCE_TYPE) # Create attrSpecs from input parameters for propName in sdrNode.GetInputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetInput(propName), usdSchemaNode) # Create attrSpecs from output parameters for propName in sdrNode.GetOutputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetOutput(propName), usdSchemaNode, False) # Extra attrSpec schemaBasePrimDefinition = \ Usd.SchemaRegistry().FindConcretePrimDefinition(schemaBase) if schemaBasePrimDefinition and \ SchemaDefiningMiscConstants.NodeDefAPI in \ schemaBasePrimDefinition.GetAppliedAPISchemas(): infoIdAttrSpec = Sdf.AttributeSpec(primSpec, \ UsdShade.Tokens.infoId, Sdf.ValueTypeNames.Token, \ Sdf.VariabilityUniform) infoIdAttrSpec.default = sdrNode.GetIdentifier() schemaLayer.Save()
def test_OutOfRangeIntSettingAndParsing(self): types = [ dict(name='uchar', min=0, max=255), dict(name='int', min=-2**31, max=2**31 - 1), dict(name='uint', min=0, max=2**32 - 1), dict(name='int64', min=-2**63, max=2**63 - 1), dict(name='uint64', min=0, max=2**64 - 1) ] layer = Sdf.Layer.CreateAnonymous() p = Sdf.CreatePrimInLayer(layer, '/p') a = Sdf.AttributeSpec(p, 'attr', Sdf.ValueTypeNames.Int) for t in types: # XXX: This test uses the SetInfo() API in a really backdoor way. We # use it to write SdfUnregisteredValue objects into layers in order to # get essentially arbitrary text output. We use that to write numerical # value strings that are out of range for given attribute types. An # alternative approach would be to provide a template string that we # attempt to parse, but that assumes the current text file format. # Overwrite scene description and attempt to write/read. a.SetInfo('typeName', t['name']) # Min and max values should come through okay. a.SetInfo('default', Sdf.UnregisteredValue(str(t['min']))) layer.ImportFromString(layer.ExportToString()) a.SetInfo('default', Sdf.UnregisteredValue(str(t['max']))) layer.ImportFromString(layer.ExportToString()) # One more than the max and one less than the min should fail. a.SetInfo('default', Sdf.UnregisteredValue(str(t['min'] - 1))) with self.assertRaises(RuntimeError): layer.ImportFromString(layer.ExportToString()) with self.assertRaises(RuntimeError): a.SetInfo('default', Sdf.UnregisteredValue(str(t['max'] + 1))) layer.ImportFromString(layer.ExportToString()) # Try setting attribute values that are out of range. l = Sdf.Layer.CreateAnonymous() q = Sdf.CreatePrimInLayer(l, '/q') b = Sdf.AttributeSpec(q, 'attr', Sdf.ValueTypeNames.Find(t['name'])) b.default = t['min'] self.assertEqual(b.default, t['min']) b.default = t['max'] self.assertEqual(b.default, t['max']) # Out of range should fail. with self.assertRaises((Tf.ErrorException, OverflowError)): b.default = t['min'] - 1 with self.assertRaises((Tf.ErrorException, OverflowError)): b.default = t['max'] + 1 # Ensure that we can read floating point values written as large integers # correctly. layer = Sdf.Layer.CreateAnonymous() layer.ImportFromString('''#sdf 1.4.32 over "Prim" { float attrf = 18446744073709551616 double attrd = 340282366920938463463374607431768211456 } ''') attrf, attrd = [ layer.GetAttributeAtPath(x) for x in ['/Prim.attrf', '/Prim.attrd'] ] self.assertEqual(attrf.default, 1.8446744073709552e+19) self.assertEqual(attrd.default, 3.402823669209385e+38)
def _CreateAttrSpecFromNodeAttribute(primSpec, prop, primDefForAttrPruning, schemaPropertyNSPrefixOverride, isInput=True): propMetadata = prop.GetMetadata() # Early out if the property should be suppressed from being translated to # propertySpec if ((PropertyDefiningKeys.USD_SUPPRESS_PROPERTY in propMetadata) and propMetadata[PropertyDefiningKeys.USD_SUPPRESS_PROPERTY] == "True"): return propertyNSPrefixOverride = schemaPropertyNSPrefixOverride if PropertyDefiningKeys.PROPERTY_NS_PREFIX_OVERRIDE in propMetadata: propertyNSPrefixOverride = \ propMetadata[PropertyDefiningKeys.PROPERTY_NS_PREFIX_OVERRIDE] propName = prop.GetName() # Error out if trying to use an explicit propertyNSPrefixOverride on an # output attr if (not isInput and propertyNSPrefixOverride is not None and \ propertyNSPrefixOverride != UsdShade.Tokens.outputs[:-1]): Tf.RaiseRuntimeError("Presence of (%s) output parameter contradicts " \ "the presence of propertyNSPrefixOverride (\"%s\"), as it is " \ "illegal for non-shader nodes to contain output parameters, or " \ "shader nodes' outputs to not have the \"outputs\" namespace " \ "prefix." %(propName, propertyNSPrefixOverride)) attrType = prop.GetTypeAsSdfType()[0] if not Sdf.Path.IsValidNamespacedIdentifier(propName): Tf.RaiseRuntimeError("Property name (%s) for schema (%s) is an " \ "invalid namespace identifier." %(propName, primSpec.name)) # if propertyNSPrefixOverride is provided and we are an output then already # thrown exception # Note that UsdShade inputs and outputs tokens contain the ":" delimiter, so # we need to strip this to be used with JoinIdentifier if propertyNSPrefixOverride is None: propertyNSPrefixOverride = UsdShade.Tokens.inputs[:-1] if isInput else \ UsdShade.Tokens.outputs[:-1] # Apply propertyNSPrefixOverride propName = Sdf.Path.JoinIdentifier([propertyNSPrefixOverride, propName]) # error and early out if duplicate property on primDefForAttrPruning exists # and has different types if primDefForAttrPruning: primDefAttr = primDefForAttrPruning.GetSchemaAttributeSpec(propName) if primDefAttr: usdAttrType = primDefAttr.typeName if (usdAttrType != attrType): Tf.Warn("Generated schema's property type '%s', " "differs usd schema's property type '%s', for " "duplicated property '%s'" %(attrType, usdAttrType, propName)) return # Copy over property parameters options = prop.GetOptions() if options and attrType == Sdf.ValueTypeNames.String: attrType = Sdf.ValueTypeNames.Token attrVariability = Sdf.VariabilityUniform \ if ((PropertyDefiningKeys.USD_VARIABILITY in propMetadata) and propMetadata[PropertyDefiningKeys.USD_VARIABILITY] == PropertyDefiningKeys.SDF_VARIABILITY_UNIFORM_STRING) \ else Sdf.VariabilityVarying attrSpec = Sdf.AttributeSpec(primSpec, propName, attrType, attrVariability) if PropertyDefiningKeys.WIDGET in prop.GetMetadata().keys(): if (prop.GetMetadata()[PropertyDefiningKeys.WIDGET] == \ PropertyDefiningKeys.NULL_VALUE): attrSpec.hidden = True if prop.GetHelp(): attrSpec.documentation = prop.GetHelp() elif prop.GetLabel(): # fallback documentation can be label attrSpec.documentation = prop.GetLabel() if prop.GetPage(): attrSpec.displayGroup = prop.GetPage() if prop.GetLabel(): attrSpec.displayName = prop.GetLabel() if options and attrType == Sdf.ValueTypeNames.Token: # If the value for token list is empty then use the name # If options list has a mix of empty and non-empty value thats an error. tokenList = [] hasEmptyValue = len(options[0][1]) == 0 for option in options: if len(option[1]) == 0: if not hasEmptyValue: Tf.Warn("Property (%s) for schema (%s) has mix of empty " \ "non-empty values for token options (%s)." \ %(propName, primSpec.name, options)) hasEmptyValue = True tokenList.append(option[0]) else: if hasEmptyValue: Tf.Warn("Property (%s) for schema (%s) has mix of empty " \ "non-empty values for token options (%s)." \ %(propName, primSpec.name, options)) hasEmptyValue = False tokenList.append(option[1]) attrSpec.allowedTokens = tokenList defaultValue = prop.GetDefaultValueAsSdfType() if (attrType == Sdf.ValueTypeNames.String or attrType == Sdf.ValueTypeNames.Token) and defaultValue is not None: attrSpec.default = defaultValue.replace('"', r'\"') else: attrSpec.default = defaultValue # The core UsdLux inputs should remain connectable (interfaceOnly) # even if sdrProperty marks the input as not connectable if isInput and not prop.IsConnectable(): attrSpec.SetInfo(PropertyDefiningKeys.CONNECTABILITY, UsdShade.Tokens.interfaceOnly)
def UpdateSchemaWithSdrNode(schemaLayer, sdrNode, renderContext="", overrideIdentifier=""): """ Updates the given schemaLayer with primSpec and propertySpecs from sdrNode metadata. A renderContext can be provided which is used in determining the shaderId namespace, which follows the pattern: "<renderContext>:<SdrShaderNodeContext>:shaderId". Note that we are using a node's context (SDR_NODE_CONTEXT_TOKENS) here to construct the shaderId namespace, so shader parsers should make sure to use appropriate SDR_NODE_CONTEXT_TOKENS in the node definitions. overrideIdentifier parameter is the identifier which should be used when the identifier of the node being processed differs from the one Sdr will discover at runtime, such as when this function is def a node constructed from an explicit asset path. This should only be used when clients know the identifier being passed is the true identifier which sdr Runtime will provide when querying using GetShaderNodeByIdentifierAndType, etc. It consumes the following attributes (that manifest as Sdr metadata) in addition to many of the standard Sdr metadata specified and parsed (via its parser plugin). Node Level Metadata: - "schemaName": Name of the new schema populated from the given sdrNode (Required) - "schemaKind": Specifies the UsdSchemaKind for the schema being populated from the sdrNode. (Note that this does not support multiple apply schema kinds). - "schemaBase": Base schema from which the new schema should inherit from. Note this defaults to "APISchemaBase" for an API schema or "Typed" for a concrete scheme. - "apiSchemasForAttrPruning": A list of core API schemas which will be composed together and any shared shader property from this prim definition is pruned from the resultant schema. - "typedSchemaForAttrPruning": A core typed schema which will be composed together with the apiSchemasForAttrPruning and any shared shader property from this prim definition is pruned from the resultant schema. If no typedSchemaForAttrPruning is provided then only the apiSchemasForAttrPruning are composed to create a prim definition. This will only be used when creating an APISchema. - "apiSchemaAutoApplyTo": The schemas to which the sdrNode populated API schema will autoApply to. - "apiSchemaCanOnlyApplyTo": If specified, the API schema generated from the sdrNode can only be validly applied to this set of schemas. - "providesUsdShadeConnectableAPIBehavior": Used to enable a connectability behavior for an API schema. - "isUsdShadeContainer": Only used when providesUsdShadeConnectableAPIBehavior is set to true. Marks the connectable prim as a UsdShade container type. - "requiresUsdShadeEncapsulation": Only used when providesUsdShadeConnectableAPIBehavior is set to true. Configures the UsdShade encapsulation rules governing its connectableBehavior. - "tfTypeNameSuffix": Class name which will get registered with TfType system. This gets appended to the domain name to register with TfType. - "schemaPropertyNSPrefixOverride": Node level metadata which can drive all node's properties namespace prefix. This can be useful for non connectable nodes which should not get UsdShade inputs and outputs namespace prefix. Property Level Metadata: - "usdVariability": Property level metadata which specifies a specific sdrNodeProperty should have its USD variability set to Uniform or Varying - "usdSuppressProperty": A property level metadata which determines if the property should be suppressed from translation from args to property spec. - "propertyNSPrefixOverride": Provides a way to override a property's namespace from the default (inputs:/outputs:) or from a node's schemaPropertyNSPrefixOverride metadata. Sdr Property Metadata to SdfPropertySpec Translations - A "null" value for Widget sdrProperty metadata translates to SdfPropertySpec Hidden metadata. - SdrProperty's Help metadata (Label metadata if Help metadata not provided) translates to SdfPropertySpec's Documentation string metadata. - SdrProperty's Page metadata translates to SdfPropertySpec's DisplayGroup metadata. - SdrProperty's Label metadata translates to SdfPropertySpec's DisplayName metadata. - SdrProperty's Options translates to SdfPropertySpec's AllowedTokens. - SdrProperty's Default value translates to SdfPropertySpec's Default value. - Connectable input properties translates to InterfaceOnly SdfPropertySpec's CONNECTABILITY. """ import distutils.util import os # Early exit on invalid parameters if not schemaLayer: Tf.Warn("No Schema Layer provided") return if sdrNode is None: # This is a workaround to iterate through invalid sdrNodes (nodes not # having any input or output properties). Currently these nodes return # false when queried for IsValid(). # Refer: pxr/usd/ndr/node.h#140-149 Tf.Warn("No valid sdrNode provided") return sdrNodeMetadata = sdrNode.GetMetadata() if SchemaDefiningKeys.SCHEMA_NAME not in sdrNodeMetadata: Tf.Warn("Sdr Node (%s) does not define a schema name metadata." \ %(sdrNode.GetName())) return schemaName = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_NAME] if not Tf.IsValidIdentifier(schemaName): Tf.RaiseRuntimeError("schemaName (%s) is an invalid identifier; " "Provide a valid USD identifer for schemaName, example (%s) " %(schemaName, Tf.MakeValidIdentifier(schemaName))) tfTypeNameSuffix = None if SchemaDefiningKeys.TF_TYPENAME_SUFFIX in sdrNodeMetadata: tfTypeNameSuffix = sdrNodeMetadata[SchemaDefiningKeys.TF_TYPENAME_SUFFIX] if not Tf.IsValidIdentifier(tfTypeNameSuffix): Tf.RaiseRuntimeError("tfTypeNameSuffix (%s) is an invalid " \ "identifier" %(tfTypeNameSuffix)) if SchemaDefiningKeys.SCHEMA_KIND not in sdrNodeMetadata: schemaKind = SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaKind = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_KIND] # Note: We are not working on dynamic multiple apply schemas right now. isAPI = schemaKind == SchemaDefiningMiscConstants.SINGLE_APPLY_SCHEMA # Fix schemaName and warn if needed if isAPI and \ not schemaName.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created is " "an API schema, fixing schemaName to reflect that") schemaName = schemaName + SchemaDefiningMiscConstants.API_STRING if isAPI and tfTypeNameSuffix and \ not tfTypeNameSuffix.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created " "is an API schema, fixing tfTypeNameSuffix to reflect that") tfTypeNameSuffix = tfTypeNameSuffix + \ SchemaDefiningMiscConstants.API_STRING if SchemaDefiningKeys.SCHEMA_BASE not in sdrNodeMetadata: Tf.Warn("No schemaBase specified in node metadata, defaulting to " "APISchemaBase for API schemas else Typed") schemaBase = SchemaDefiningMiscConstants.API_SCHEMA_BASE if isAPI \ else SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaBase = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_BASE] apiSchemaAutoApplyTo = None if SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO in sdrNodeMetadata: apiSchemaAutoApplyTo = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO] \ .split('|') apiSchemaCanOnlyApplyTo = None if SchemaDefiningKeys.API_SCHEMA_CAN_ONLY_APPLY_TO in sdrNodeMetadata: apiSchemaCanOnlyApplyTo = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMA_CAN_ONLY_APPLY_TO] \ .split('|') providesUsdShadeConnectableAPIBehavior = False if SchemaDefiningKeys.PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR in \ sdrNodeMetadata: providesUsdShadeConnectableAPIBehavior = \ distutils.util.strtobool(sdrNodeMetadata[SchemaDefiningKeys. \ PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR]) apiSchemasForAttrPruning = None if SchemaDefiningKeys.API_SCHEMAS_FOR_ATTR_PRUNING in sdrNodeMetadata: apiSchemasForAttrPruning = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMAS_FOR_ATTR_PRUNING] \ .split('|') typedSchemaForAttrPruning = "" if isAPI and \ SchemaDefiningKeys.TYPED_SCHEMA_FOR_ATTR_PRUNING in sdrNodeMetadata: typedSchemaForAttrPruning = \ sdrNodeMetadata[SchemaDefiningKeys.TYPED_SCHEMA_FOR_ATTR_PRUNING] schemaPropertyNSPrefixOverride = None if SchemaDefiningKeys.SCHEMA_PROPERTY_NS_PREFIX_OVERRIDE in sdrNodeMetadata: schemaPropertyNSPrefixOverride = \ sdrNodeMetadata[ \ SchemaDefiningKeys.SCHEMA_PROPERTY_NS_PREFIX_OVERRIDE] usdSchemaReg = Usd.SchemaRegistry() # determine if the node being processed provides UsdShade-Connectability, # this helps in determining what namespace to use and also to report error # if a non-connectable node has outputs properties, which is malformed. # - Does the node derive from a schemaBase which provides connectable # behavior. Warn if schemaPropertyNSPrefixOverride is also specified, as # these metadata won't be used. # - If no schemaBase then we default to UsdShade connectable node's # inputs:/outputs: namespace prefix, unless schemaPropertyNSPrefixOverride # is provided. # - We also report an error if schemaPropertyNSPrefixOverride is provided # and an output property is found on the node being processed. schemaBaseProvidesConnectability = UsdShade.ConnectableAPI. \ HasConnectableAPI(usdSchemaReg.GetTypeFromName(schemaBase)) if (len(sdrNode.GetOutputNames()) > 0 and \ schemaPropertyNSPrefixOverride is not None and \ not _IsNSPrefixConnectableAPICompliant( \ schemaPropertyNSPrefixOverride)): Tf.RaiseRuntimeError("Presence of (%s) output parameters contradicts " \ "the presence of schemaPropertyNSPrefixOverride (\"%s\"), as it " \ "is illegal for non-connectable nodes to contain output " \ "parameters, or shader nodes' outputs to not have the \"outputs\"" \ "namespace prefix." %(len(sdrNode.GetOutputNames()), \ schemaPropertyNSPrefixOverride)) if (schemaBaseProvidesConnectability and \ schemaPropertyNSPrefixOverride is not None and \ not _IsNSPrefixConnectableAPICompliant( \ schemaPropertyNSPrefixOverride)): Tf.Warn("Node %s provides UsdShade-Connectability as it derives from " \ "%s, schemaPropertyNSPrefixOverride \"%s\" will not be used." \ %(schemaName, schemaBase, schemaPropertyNSPrefixOverride)) # set schemaPropertyNSPrefixOverride to "inputs", assuming default # UsdShade Connectability namespace prefix schemaPropertyNSPrefixOverride = "inputs" primSpec = schemaLayer.GetPrimAtPath(schemaName) if (primSpec): # if primSpec already exist, remove entirely and recreate using the # parsed sdr node if primSpec.nameParent: del primSpec.nameParent.nameChildren[primSpec.name] else: del primSpec.nameRoot.nameChildren[primSpec.name] primSpec = Sdf.PrimSpec(schemaLayer, schemaName, Sdf.SpecifierClass, "" if isAPI else schemaName) primSpec.inheritPathList.explicitItems = ["/" + schemaBase] primSpecCustomData = {} if isAPI: primSpecCustomData["apiSchemaType"] = schemaKind if tfTypeNameSuffix: # Defines this classname for TfType system # can help avoid duplicate prefix with domain and className # Tf type system will automatically pick schemaName as tfTypeName if # this is not set! primSpecCustomData["className"] = tfTypeNameSuffix if apiSchemaAutoApplyTo: primSpecCustomData['apiSchemaAutoApplyTo'] = \ Vt.TokenArray(apiSchemaAutoApplyTo) if apiSchemaCanOnlyApplyTo: primSpecCustomData['apiSchemaCanOnlyApplyTo'] = \ Vt.TokenArray(apiSchemaCanOnlyApplyTo) if providesUsdShadeConnectableAPIBehavior: extraPlugInfo = { SchemaDefiningKeys.PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR \ : True } for propKey in [SchemaDefiningKeys.IS_USD_SHADE_CONTAINER, \ SchemaDefiningKeys.REQUIRES_USD_SHADE_ENCAPSULATION]: if propKey in sdrNodeMetadata: # Since we want to assign the types for these to bool and # because in python boolean type is a subset of int, we need to # do following instead of assign the propValue directly. propValue = distutils.util.strtobool(sdrNodeMetadata[propKey]) extraPlugInfo[propKey] = bool(propValue) primSpecCustomData['extraPlugInfo'] = extraPlugInfo primSpec.customData = primSpecCustomData doc = sdrNode.GetHelp() if doc != "": primSpec.documentation = doc # gather properties from a prim definition generated by composing apiSchemas # provided by apiSchemasForAttrPruning metadata. primDefForAttrPruning = None if apiSchemasForAttrPruning: primDefForAttrPruning = usdSchemaReg.BuildComposedPrimDefinition( typedSchemaForAttrPruning, apiSchemasForAttrPruning) # Create attrSpecs from input parameters for propName in sdrNode.GetInputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetInput(propName), primDefForAttrPruning, schemaPropertyNSPrefixOverride) # Create attrSpecs from output parameters # Note that we always want outputs: namespace prefix for output attributes. for propName in sdrNode.GetOutputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetOutput(propName), primDefForAttrPruning, UsdShade.Tokens.outputs[:-1], False) # Create token shaderId attrSpec -- only for shader nodes if (schemaBaseProvidesConnectability or \ schemaPropertyNSPrefixOverride is None or \ _IsNSPrefixConnectableAPICompliant(schemaPropertyNSPrefixOverride)): shaderIdAttrName = Sdf.Path.JoinIdentifier( \ [renderContext, sdrNode.GetContext(), PropertyDefiningKeys.SHADER_ID]) shaderIdAttrSpec = Sdf.AttributeSpec(primSpec, shaderIdAttrName, Sdf.ValueTypeNames.Token, Sdf.VariabilityUniform) # Since users shouldn't need to be aware of shaderId attribute, we put # this in "Internal" displayGroup. shaderIdAttrSpec.displayGroup = \ PropertyDefiningKeys.INTERNAL_DISPLAY_GROUP # Use the identifier if explicitly provided, (it could be a shader node # queried using an explicit path), else use sdrNode's registered # identifier. nodeIdentifier = overrideIdentifier if overrideIdentifier else \ sdrNode.GetIdentifier() shaderIdAttrSpec.default = nodeIdentifier # Extra attrSpec schemaBasePrimDefinition = \ Usd.SchemaRegistry().FindConcretePrimDefinition(schemaBase) if schemaBasePrimDefinition and \ SchemaDefiningMiscConstants.NodeDefAPI in \ schemaBasePrimDefinition.GetAppliedAPISchemas(): infoIdAttrSpec = Sdf.AttributeSpec(primSpec, \ UsdShade.Tokens.infoId, Sdf.ValueTypeNames.Token, \ Sdf.VariabilityUniform) infoIdAttrSpec.default = nodeIdentifier schemaLayer.Save()
def UpdateSchemaWithSdrNode(schemaLayer, sdrNode, renderContext="", overrideIdentifier=""): """ Updates the given schemaLayer with primSpec and propertySpecs from sdrNode metadata. A renderContext can be provided which is used in determining the shaderId namespace, which follows the pattern: "<renderContext>:<SdrShaderNodeContext>:shaderId". Note that we are using a node's context (SDR_NODE_CONTEXT_TOKENS) here to construct the shaderId namespace, so shader parsers should make sure to use appropriate SDR_NODE_CONTEXT_TOKENS in the node definitions. overrideIdentifier parameter is the identifier which should be used when the identifier of the node being processed differs from the one Sdr will discover at runtime, such as when this function is def a node constructed from an explicit asset path. This should only be used when clients know the identifier being passed is the true identifier which sdr Runtime will provide when querying using GetShaderNodeByNameAndType, etc. It consumes the following attributes (that manifest as Sdr metadata) in addition to many of the standard Sdr metadata specified and parsed (via its parser plugin). Node Level Metadata: - "schemaName": Name of the new schema populated from the given sdrNode (Required) - "schemaKind": Specifies the UsdSchemaKind for the schema being populated from the sdrNode. (Note that this does not support multiple apply schema kinds). - "schemaBase": Base schema from which the new schema should inherit from. Note this defaults to "APISchemaBase" for an API schema or "Typed" for a concrete scheme. - "usdSchemaClass": Specifies the equivalent schema directly generated by USD (sourceType: USD). This is used to make sure duplicate properties already specified in the USD schema are not populated in the new API schema. Note this is only used when we are dealing with an API schema. - "apiSchemaAutoApplyTo": The schemas to which the sdrNode populated API schema will autoApply to. - "apiSchemaCanOnlyApplyTo": If specified, the API schema generated from the sdrNode can only be validly applied to this set of schemas. - "providesUsdShadeConnectableAPIBehavior": Used to enable a connectability behavior for an API schema. - "isUsdShadeContainer": Only used when providesUsdShadeConnectableAPIBehavior is set to true. Marks the connectable prim as a UsdShade container type. - "requiresUsdShadeEncapsulation": Only used when providesUsdShadeConnectableAPIBehavior is set to true. Configures the UsdShade encapsulation rules governing its connectableBehavior. - "tfTypeNameSuffix": Class name which will get registered with TfType system. This gets appended to the domain name to register with TfType. Property Level Metadata: - USD_VARIABILITY: Property level metadata which specifies a specific sdrNodeProperty should have its USD variability set to Uniform or Varying - USD_SUPPRESS_PROPERTY: A property level metadata which determines if the property should be suppressed from translation from args to property spec. Sdr Property Metadata to SdfPropertySpec Translations - A "null" value for Widget sdrProperty metadata translates to SdfPropertySpec Hidden metadata. - SdrProperty's Help metadata (Label metadata if Help metadata not provided) translates to SdfPropertySpec's Documentation string metadata. - SdrProperty's Page metadata translates to SdfPropertySpec's DisplayGroup metadata. - SdrProperty's Label metadata translates to SdfPropertySpec's DisplayName metadata. - SdrProperty's Options translates to SdfPropertySpec's AllowedTokens. - SdrProperty's Default value translates to SdfPropertySpec's Default value. - Connectable input properties translates to InterfaceOnly SdfPropertySpec's CONNECTABILITY. """ import distutils.util import os # Early exit on invalid parameters if not schemaLayer: Tf.Warn("No Schema Layer provided") return if not sdrNode: Tf.Warn("No valid sdrNode provided") return sdrNodeMetadata = sdrNode.GetMetadata() if SchemaDefiningKeys.SCHEMA_NAME not in sdrNodeMetadata: Tf.Warn("Sdr Node (%s) does not define a schema name metadata." \ %(sdrNode.GetName())) return schemaName = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_NAME] if not Tf.IsValidIdentifier(schemaName): Tf.RaiseRuntimeError( "schemaName (%s) is an invalid identifier; " "Provide a valid USD identifer for schemaName, example (%s) " % (schemaName, Tf.MakeValidIdentifier(schemaName))) tfTypeNameSuffix = None if SchemaDefiningKeys.TF_TYPENAME_SUFFIX in sdrNodeMetadata: tfTypeNameSuffix = sdrNodeMetadata[ SchemaDefiningKeys.TF_TYPENAME_SUFFIX] if not Tf.IsValidIdentifier(tfTypeNameSuffix): Tf.RaiseRuntimeError("tfTypeNameSuffix (%s) is an invalid " \ "identifier" %(tfTypeNameSuffix)) if SchemaDefiningKeys.SCHEMA_KIND not in sdrNodeMetadata: schemaKind = SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaKind = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_KIND] # Note: We are not working on dynamic multiple apply schemas right now. isAPI = schemaKind == SchemaDefiningMiscConstants.SINGLE_APPLY_SCHEMA # Fix schemaName and warn if needed if isAPI and \ not schemaName.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created is " "an API schema, fixing schemaName to reflect that") schemaName = schemaName + SchemaDefiningMiscConstants.API_STRING if isAPI and tfTypeNameSuffix and \ not tfTypeNameSuffix.endswith(SchemaDefiningMiscConstants.API_STRING): Tf.Warn("node metadata implies the generated schema being created " "is an API schema, fixing tfTypeNameSuffix to reflect that") tfTypeNameSuffix = tfTypeNameSuffix + \ SchemaDefiningMiscConstants.API_STRING if SchemaDefiningKeys.SCHEMA_BASE not in sdrNodeMetadata: Tf.Warn("No schemaBase specified in node metadata, defaulting to " "APISchemaBase for API schemas else Typed") schemaBase = SchemaDefiningMiscConstants.API_SCHEMA_BASE if isAPI \ else SchemaDefiningMiscConstants.TYPED_SCHEMA else: schemaBase = sdrNodeMetadata[SchemaDefiningKeys.SCHEMA_BASE] apiSchemaAutoApplyTo = None if SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO in sdrNodeMetadata: apiSchemaAutoApplyTo = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMA_AUTO_APPLY_TO] \ .split('|') apiSchemaCanOnlyApplyTo = None if SchemaDefiningKeys.API_SCHEMA_CAN_ONLY_APPLY_TO in sdrNodeMetadata: apiSchemaCanOnlyApplyTo = \ sdrNodeMetadata[SchemaDefiningKeys.API_SCHEMA_CAN_ONLY_APPLY_TO] \ .split('|') providesUsdShadeConnectableAPIBehavior = False if SchemaDefiningKeys.PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR in \ sdrNodeMetadata: providesUsdShadeConnectableAPIBehavior = \ distutils.util.strtobool(sdrNodeMetadata[SchemaDefiningKeys. \ PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR]) usdSchemaClass = None if isAPI and SchemaDefiningKeys.USD_SCHEMA_CLASS in sdrNodeMetadata: usdSchemaClass = \ sdrNodeMetadata[SchemaDefiningKeys.USD_SCHEMA_CLASS] primSpec = schemaLayer.GetPrimAtPath(schemaName) if (primSpec): # if primSpec already exist, remove entirely and recreate using the # parsed sdr node if primSpec.nameParent: del primSpec.nameParent.nameChildren[primSpec.name] else: del primSpec.nameRoot.nameChildren[primSpec.name] primSpec = Sdf.PrimSpec(schemaLayer, schemaName, Sdf.SpecifierClass, "" if isAPI else schemaName) primSpec.inheritPathList.explicitItems = ["/" + schemaBase] primSpecCustomData = {} if isAPI: primSpecCustomData["apiSchemaType"] = schemaKind if tfTypeNameSuffix: # Defines this classname for TfType system # can help avoid duplicate prefix with domain and className # Tf type system will automatically pick schemaName as tfTypeName if # this is not set! primSpecCustomData["className"] = tfTypeNameSuffix if apiSchemaAutoApplyTo: primSpecCustomData['apiSchemaAutoApplyTo'] = \ Vt.TokenArray(apiSchemaAutoApplyTo) if apiSchemaCanOnlyApplyTo: primSpecCustomData['apiSchemaCanOnlyApplyTo'] = \ Vt.TokenArray(apiSchemaCanOnlyApplyTo) if providesUsdShadeConnectableAPIBehavior: extraPlugInfo = { SchemaDefiningKeys.PROVIDES_USD_SHADE_CONNECTABLE_API_BEHAVIOR \ : True } for propKey in [SchemaDefiningKeys.IS_USD_SHADE_CONTAINER, \ SchemaDefiningKeys.REQUIRES_USD_SHADE_ENCAPSULATION]: if propKey in sdrNodeMetadata: # Since we want to assign the types for these to bool and # because in python boolean type is a subset of int, we need to # do following instead of assign the propValue directly. propValue = distutils.util.strtobool(sdrNodeMetadata[propKey]) extraPlugInfo[propKey] = bool(propValue) primSpecCustomData['extraPlugInfo'] = extraPlugInfo primSpec.customData = primSpecCustomData doc = sdrNode.GetHelp() if doc != "": primSpec.documentation = doc # gather properties from node directly generated from USD (sourceType: USD) # Use the usdSchemaClass tag when the generated schema being defined is an # API schema usdSchemaNode = None if usdSchemaClass: reg = Sdr.Registry() if usdSchemaClass.endswith(SchemaDefiningMiscConstants.API_STRING): # This usd schema is an API schema, we need to extract the shader # identifier from its primDef's shaderId field. primDef = Usd.SchemaRegistry().FindAppliedAPIPrimDefinition( usdSchemaClass) if primDef: # We are dealing with USD source type here, hence no render # context is required but we can still borrow node context # information from the sdrNode in question, since the usd source # type node should also belong to the same context. shaderIdAttrName = Sdf.Path.JoinIdentifier( \ sdrNode.GetContext(), PropertyDefiningKeys.SHADER_ID) sdrIdentifier = primDef.GetAttributeFallbackValue( shaderIdAttrName) if sdrIdentifier != "": usdSchemaNode = reg.GetNodeByIdentifierAndType( sdrIdentifier, SchemaDefiningMiscConstants.USD_SOURCE_TYPE) else: Tf.Warn("No sourceId authored for '%s'." % (usdSchemaClass)) else: Tf.Warn("Illegal API schema provided for the usdSchemaClass " "metadata. No prim definition registered for '%s'" % (usdSchemaClass)) else: usdSchemaNode = reg.GetNodeByIdentifierAndType( usdSchemaClass, SchemaDefiningMiscConstants.USD_SOURCE_TYPE) # Create attrSpecs from input parameters for propName in sdrNode.GetInputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetInput(propName), usdSchemaNode) # Create attrSpecs from output parameters for propName in sdrNode.GetOutputNames(): _CreateAttrSpecFromNodeAttribute(primSpec, sdrNode.GetOutput(propName), usdSchemaNode, False) # Create token shaderId attrSpec shaderIdAttrName = Sdf.Path.JoinIdentifier( \ [renderContext, sdrNode.GetContext(), PropertyDefiningKeys.SHADER_ID]) shaderIdAttrSpec = Sdf.AttributeSpec(primSpec, shaderIdAttrName, Sdf.ValueTypeNames.Token, Sdf.VariabilityUniform) # Since users shouldn't need to be aware of shaderId attribute, we put this # in "Internal" displayGroup. shaderIdAttrSpec.displayGroup = PropertyDefiningKeys.INTERNAL_DISPLAY_GROUP # Use the identifier if explicitly provided, (it could be a shader node # queried using an explicit path), else use sdrNode's registered identifier. nodeIdentifier = overrideIdentifier if overrideIdentifier else \ sdrNode.GetIdentifier() shaderIdAttrSpec.default = nodeIdentifier # Extra attrSpec schemaBasePrimDefinition = \ Usd.SchemaRegistry().FindConcretePrimDefinition(schemaBase) if schemaBasePrimDefinition and \ SchemaDefiningMiscConstants.NodeDefAPI in \ schemaBasePrimDefinition.GetAppliedAPISchemas(): infoIdAttrSpec = Sdf.AttributeSpec(primSpec, \ UsdShade.Tokens.infoId, Sdf.ValueTypeNames.Token, \ Sdf.VariabilityUniform) infoIdAttrSpec.default = nodeIdentifier schemaLayer.Save()
def _parseInstanceJSONFile(self, jsonFilename, subInstanceStageFilePath): # type: (str, str) -> None """ Create USD Prim instances from the given Element JSON file. """ with open(jsonFilename, 'r') as f: jsonData = json.load(f) layer = Sdf.Layer.CreateAnonymous(self.USDFileExtension) # Leverage the SDF API instead of the USD API in order to batch-create # Prims. This avoids fanning out change notifications, which results in # O(n2) performance and becomes *slow* when creating a large number of # instances -- which is the case here (sometimes upwards of a million # instances). with Sdf.ChangeBlock(): instancersPrimSpecPath = '/Instancers' instancersPrimSpec = Sdf.CreatePrimInLayer(layer, instancersPrimSpecPath) instancersPrimSpec.specifier = Sdf.SpecifierDef layer.defaultPrim = 'Instancers' for name, instances in jsonData.items(): pointInstancerPrimSpecPath = instancersPrimSpecPath + '/' + self._getFileBasename( name) pointInstancerPrimSpec = Sdf.CreatePrimInLayer( layer, pointInstancerPrimSpecPath) pointInstancerPrimSpec.specifier = Sdf.SpecifierDef pointInstancerPrimSpec.typeName = 'PointInstancer' positionsBuffer = [] orientationsBuffer = [] for instanceName, instanceTransform in instances.items(): transformMatrix = Gf.Matrix4d(*instanceTransform) positionsBuffer.append( transformMatrix.ExtractTranslation()) quaternion = transformMatrix.ExtractRotation( ).GetQuaternion().GetNormalized() imaginaryComponents = quaternion.GetImaginary() orientationsBuffer.append( Gf.Quath( quaternion.GetReal(), Gf.Vec3h(imaginaryComponents[0], imaginaryComponents[1], imaginaryComponents[2]))) positionsAttribute = Sdf.AttributeSpec( pointInstancerPrimSpec, 'positions', Sdf.ValueTypeNames.Vector3fArray) positionsAttribute.default = positionsBuffer orientationsAttribute = Sdf.AttributeSpec( pointInstancerPrimSpec, 'orientations', Sdf.ValueTypeNames.QuathArray) orientationsAttribute.default = orientationsBuffer protoIndicesAttribute = Sdf.AttributeSpec( pointInstancerPrimSpec, 'protoIndices', Sdf.ValueTypeNames.IntArray) protoIndicesAttribute.default = [0] * len(instances.items()) meshReferencePrimSpecPath = pointInstancerPrimSpecPath + '/mesh' meshReferencePrimSpec = Sdf.CreatePrimInLayer( layer, meshReferencePrimSpecPath) meshReferencePrimSpec.specifier = Sdf.SpecifierDef meshReferencePrimSpec.typeName = 'Mesh' relativeAssetFilePath = './' + os.path.relpath( self._getAssetFilePathFromOBJFilePath(name), self.PrimitivesDirectory).replace('\\', '/') meshReferencePrimSpec.referenceList.Prepend( Sdf.Reference(relativeAssetFilePath)) relationshipSpec = Sdf.RelationshipSpec(pointInstancerPrimSpec, 'prototypes', custom=False) relationshipSpec.targetPathList.explicitItems.append( meshReferencePrimSpecPath) layer.Export(subInstanceStageFilePath, comment='')
def test_MutedLocalLayers(self): for fmt in allFormats: sublayer_1 = Sdf.Layer.CreateNew('localLayers_sublayer_1.' + fmt) primSpec_1 = Sdf.CreatePrimInLayer(sublayer_1, '/A') attrSpec_1 = Sdf.AttributeSpec(primSpec_1, 'attr', Sdf.ValueTypeNames.String, declaresCustom=True) attrSpec_1.default = 'from_sublayer_1' sublayer_2 = Sdf.Layer.CreateNew('localLayers_sublayer_2.' + fmt) primSpec_2 = Sdf.CreatePrimInLayer(sublayer_2, '/A') attrSpec_2 = Sdf.AttributeSpec(primSpec_2, 'attr', Sdf.ValueTypeNames.String, declaresCustom=True) attrSpec_2.default = 'from_sublayer_2' sessionLayer = Sdf.Layer.CreateNew('localLayers_session.' + fmt) primSpec_session = Sdf.CreatePrimInLayer(sessionLayer, '/A') attrSpec_session = Sdf.AttributeSpec(primSpec_session, 'attr', Sdf.ValueTypeNames.String, declaresCustom=True) attrSpec_session.default = 'from_session' rootLayer = Sdf.Layer.CreateNew('localLayers_root.' + fmt) rootLayer.subLayerPaths = [ sublayer_1.identifier, sublayer_2.identifier ] stage = Usd.Stage.Open(rootLayer, sessionLayer) prim = stage.GetPrimAtPath('/A') attr = prim.GetAttribute('attr') assert attr # Muting the stage's root layer is disallowed and results # in a coding error. with self.assertRaises(Tf.ErrorException): stage.MuteLayer(rootLayer.identifier) assert attr.Get() == 'from_session' assert (set(stage.GetUsedLayers()) == set( [sublayer_1, sublayer_2, sessionLayer, rootLayer])) assert set(stage.GetMutedLayers()) == set([]) assert not stage.IsLayerMuted(sublayer_1.identifier) assert not stage.IsLayerMuted(sublayer_2.identifier) assert not stage.IsLayerMuted(sessionLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier) stage.MuteLayer(sessionLayer.identifier) assert attr.Get() == 'from_sublayer_1' assert (set(stage.GetUsedLayers()) == set( [sublayer_1, sublayer_2, rootLayer])) assert set(stage.GetMutedLayers()) == set( [sessionLayer.identifier]) assert not stage.IsLayerMuted(sublayer_1.identifier) assert not stage.IsLayerMuted(sublayer_2.identifier) assert stage.IsLayerMuted(sessionLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier) stage.MuteLayer(sublayer_1.identifier) assert attr.Get() == 'from_sublayer_2' assert set(stage.GetUsedLayers()) == set([sublayer_2, rootLayer]) assert (set(stage.GetMutedLayers()) == set( [sessionLayer.identifier, sublayer_1.identifier])) assert stage.IsLayerMuted(sublayer_1.identifier) assert not stage.IsLayerMuted(sublayer_2.identifier) assert stage.IsLayerMuted(sessionLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier) stage.UnmuteLayer(sessionLayer.identifier) assert attr.Get() == 'from_session' assert (set(stage.GetUsedLayers()) == set( [sublayer_2, sessionLayer, rootLayer])) assert set(stage.GetMutedLayers()) == set([sublayer_1.identifier]) assert stage.IsLayerMuted(sublayer_1.identifier) assert not stage.IsLayerMuted(sublayer_2.identifier) assert not stage.IsLayerMuted(sessionLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier) stage.MuteAndUnmuteLayers( [sessionLayer.identifier, sublayer_2.identifier], [sublayer_1.identifier]) assert attr.Get() == 'from_sublayer_1' assert set(stage.GetUsedLayers()) == set([sublayer_1, rootLayer]) assert (set(stage.GetMutedLayers()) == set( [sublayer_2.identifier, sessionLayer.identifier])) assert not stage.IsLayerMuted(sublayer_1.identifier) assert stage.IsLayerMuted(sublayer_2.identifier) assert stage.IsLayerMuted(sessionLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier)
def test_MutedReferenceLayers(self): for fmt in allFormats: sublayer_1 = Sdf.Layer.CreateNew('refLayers_sublayer_1.' + fmt) primSpec_1 = Sdf.CreatePrimInLayer(sublayer_1, '/A') attrSpec_1 = Sdf.AttributeSpec(primSpec_1, 'attr', Sdf.ValueTypeNames.String, declaresCustom=True) attrSpec_1.default = 'from_sublayer_1' refLayer = Sdf.Layer.CreateNew('refLayers_ref.' + fmt) primSpec_ref = Sdf.CreatePrimInLayer(refLayer, '/A') refLayer.subLayerPaths = [sublayer_1.identifier] rootLayer = Sdf.Layer.CreateNew('refLayers_root.' + fmt) primSpec_root = Sdf.CreatePrimInLayer(rootLayer, '/A') primSpec_root.referenceList.Add( Sdf.Reference(refLayer.identifier, '/A')) stage = Usd.Stage.Open(rootLayer, sessionLayer=None) prim = stage.GetPrimAtPath('/A') attr = prim.GetAttribute('attr') assert attr assert attr.Get() == 'from_sublayer_1' assert (set(stage.GetUsedLayers()) == set( [sublayer_1, refLayer, rootLayer])) assert set(stage.GetMutedLayers()) == set([]) assert not stage.IsLayerMuted(sublayer_1.identifier) assert not stage.IsLayerMuted(refLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier) stage.MuteLayer(sublayer_1.identifier) assert attr.Get() == None assert set(stage.GetUsedLayers()) == set([refLayer, rootLayer]) assert set(stage.GetMutedLayers()) == set([sublayer_1.identifier]) assert stage.IsLayerMuted(sublayer_1.identifier) assert not stage.IsLayerMuted(refLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier) stage.UnmuteLayer(sublayer_1.identifier) assert attr.Get() == 'from_sublayer_1' assert (set(stage.GetUsedLayers()) == set( [sublayer_1, refLayer, rootLayer])) assert set(stage.GetMutedLayers()) == set([]) assert not stage.IsLayerMuted(sublayer_1.identifier) assert not stage.IsLayerMuted(refLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier) stage.MuteLayer(refLayer.identifier) assert not attr assert set(stage.GetUsedLayers()) == set([rootLayer]) assert set(stage.GetMutedLayers()) == set([refLayer.identifier]) assert not stage.IsLayerMuted(sublayer_1.identifier) assert stage.IsLayerMuted(refLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier) stage.MuteAndUnmuteLayers([sublayer_1.identifier], [refLayer.identifier]) assert attr.Get() == None assert set(stage.GetUsedLayers()) == set([refLayer, rootLayer]) assert set(stage.GetMutedLayers()) == set([sublayer_1.identifier]) assert stage.IsLayerMuted(sublayer_1.identifier) assert not stage.IsLayerMuted(refLayer.identifier) assert not stage.IsLayerMuted(rootLayer.identifier)
def test_Advanced(self): """Test using callbacks to control spec copying via advanced API""" l = Sdf.Layer.CreateAnonymous() primSpec = Sdf.PrimSpec(l, "Root", Sdf.SpecifierOver) primSpec.documentation = "prim docs" primSpec.kind = "model" # If callbacks just return True, all values and children are copied. self.assertTrue( Sdf.CopySpec(l, "/Root", l, "/Copy", shouldCopyValueFn=lambda *args: True, shouldCopyChildrenFn=lambda *args: True)) dstPrimSpec = l.GetPrimAtPath("/Copy") self._VerifyExpectedData(l, expected={ "/Copy": { "specifier": Sdf.SpecifierOver, "documentation": "prim docs", "kind": "model" } }) # Set up a value callback that skips copying a field and replaces # the value of another field during the copy. def shouldCopyValue(*args): if args[1] == "documentation": return False elif args[1] == "kind": return (True, "prop") return True self.assertTrue( Sdf.CopySpec(l, "/Root", l, "/Copy2", shouldCopyValueFn=shouldCopyValue, shouldCopyChildrenFn=lambda *args: True)) dstPrimSpec = l.GetPrimAtPath("/Copy2") self._VerifyExpectedData(l, expected={ "/Copy2": { "specifier": Sdf.SpecifierOver, "kind": "prop" } }) # Set up a children callback that skips copying properties. attrSpecA = Sdf.AttributeSpec(primSpec, "A", Sdf.ValueTypeNames.Float) attrSpecA.custom = True attrSpecA.default = 1.0 attrSpecB = Sdf.AttributeSpec(primSpec, "B", Sdf.ValueTypeNames.Float) attrSpecB.custom = True attrSpecB.default = 2.0 def shouldCopyChildren(*args): if args[0] == "properties": return False return True self.assertTrue( Sdf.CopySpec(l, "/Root", l, "/Copy3", shouldCopyValueFn=lambda *args: True, shouldCopyChildrenFn=shouldCopyChildren)) dstPrimSpec = l.GetPrimAtPath("/Copy3") self.assertEqual(list(dstPrimSpec.properties), []) # Set up a children callback that copies the property named "A" # to a property named "C" under the destination spec. def shouldCopyChildren(*args): if args[0] == "properties": return (True, ["A"], ["C"]) return True self.assertTrue( Sdf.CopySpec(l, "/Root", l, "/Copy4", shouldCopyValueFn=lambda *args: True, shouldCopyChildrenFn=shouldCopyChildren)) dstPrimSpec = l.GetPrimAtPath("/Copy4") self.assertEqual(list(dstPrimSpec.properties), [l.GetAttributeAtPath("/Copy4.C")]) self._VerifyExpectedData(l, expected={ "/Copy4.C": { "custom": True, "default": 1.0, "typeName": Sdf.ValueTypeNames.Float, "variability": Sdf.VariabilityVarying } })
def test_AttributeConnectionRemapping(self): """Tests that attribute connections that point to a child of the source path are remapped to the destination path.""" layer = Sdf.Layer.CreateAnonymous() primSpec = Sdf.CreatePrimInLayer(layer, "/Test/Child") attrSpec = Sdf.AttributeSpec(primSpec, "attr", Sdf.ValueTypeNames.Float) attrSpec.connectionPathList.explicitItems = \ [ "/Test/Child.attr2", "/Test/Child/Subchild.attr3", "/Test/Sibling.attr" ] attrSpec.SetConnectionMarker("/Test/Child.attr2", "final") Sdf.MapperSpec(attrSpec, "/Test/Child.attr2", "mapper") # Copy root prim and verify that connections on the child prim that # point to objects beneath /Test are remapped to /TestCopy. self.assertTrue(Sdf.CopySpec(layer, "/Test", layer, "/TestCopy")) dstAttrSpec = layer.GetAttributeAtPath("/TestCopy/Child.attr") self.assertTrue(dstAttrSpec) expectedListOp = Sdf.PathListOp() expectedListOp.explicitItems = \ [ "/TestCopy/Child.attr2", "/TestCopy/Child/Subchild.attr3", "/TestCopy/Sibling.attr" ] self.assertEqual(dstAttrSpec.GetInfo("connectionPaths"), expectedListOp) self.assertEqual( dstAttrSpec.connectionMarkers["/TestCopy/Child.attr2"], "final") # Copy prim with attribute and verify that connections that point # to objects beneath the source /Test/Child prim are remapped to # /Dest. self.assertTrue(Sdf.CopySpec(layer, "/Test/Child", layer, "/Dest")) dstAttrSpec = layer.GetAttributeAtPath("/Dest.attr") self.assertTrue(dstAttrSpec) expectedListOp = Sdf.PathListOp() expectedListOp.explicitItems = \ [ "/Dest.attr2", "/Dest/Subchild.attr3", "/Test/Sibling.attr" ] self.assertEqual(dstAttrSpec.GetInfo("connectionPaths"), expectedListOp) self.assertEqual(dstAttrSpec.connectionMarkers["/Dest.attr2"], "final") self.assertTrue(dstAttrSpec.connectionMappers["/Dest.attr2"].typeName, "mapper") # Same as above, but copy to variant to ensure that variant selection # paths aren't authored into the connection list. varSpec = Sdf.CreateVariantInLayer(layer, "/Variant", "version", "a") self.assertTrue( Sdf.CopySpec(layer, "/Test/Child", layer, "/Variant{version=a}")) dstAttrSpec = layer.GetAttributeAtPath("/Variant{version=a}.attr") self.assertTrue(dstAttrSpec) expectedListOp = Sdf.PathListOp() expectedListOp.explicitItems = \ [ "/Variant.attr2", "/Variant/Subchild.attr3", "/Test/Sibling.attr" ] self.assertEqual(dstAttrSpec.GetInfo("connectionPaths"), expectedListOp) self.assertEqual(dstAttrSpec.connectionMarkers["/Variant.attr2"], "final") self.assertTrue( dstAttrSpec.connectionMappers["/Variant.attr2"].typeName, "mapper") # Copy from variant to variant, again to ensure that variant selection # paths aren't authored into the connection list. varSpec2 = Sdf.CreateVariantInLayer(layer, "/Variant", "version", "b") self.assertTrue( Sdf.CopySpec(layer, "/Variant{version=a}", layer, "/Variant{version=b}")) dstAttrSpec = layer.GetAttributeAtPath("/Variant{version=b}.attr") self.assertTrue(dstAttrSpec) self.assertEqual(dstAttrSpec.GetInfo("connectionPaths"), expectedListOp) self.assertEqual(dstAttrSpec.connectionMarkers["/Variant.attr2"], "final") self.assertTrue( dstAttrSpec.connectionMappers["/Variant.attr2"].typeName, "mapper")
def test_Metadata(self): layer = Sdf.Layer.CreateAnonymous() prim = Sdf.PrimSpec(layer, "test", Sdf.SpecifierDef, "bogus_type") attr = Sdf.AttributeSpec(prim, 'numCrvs', Sdf.ValueTypeNames.Int) # assign a default value, otherwise after ClearInfo, attr will expire. attr.default = 1 self.assertEqual(attr.HasInfo('bogus_key_test'), False) with self.assertRaises(Tf.ErrorException): attr.ClearInfo('bogus_key_test') self.assertEqual(attr.custom, False) attr.custom = True self.assertEqual(attr.custom, True) attr.custom = False self.assertEqual(attr.custom, False) self.assertFalse(attr.HasInfo('customData')) self.assertTrue(len(attr.customData) == 0) attr.customData = {'attrCustomData': {'attrBool': True}} self.assertTrue(attr.HasInfo('customData')) self.assertTrue(len(attr.customData) == 1) self.assertEqual(attr.customData['attrCustomData'], {'attrBool': True}) attr.customData = {'attrCustomData': {'attrFloat': 1.0}} self.assertTrue(attr.HasInfo('customData')) self.assertTrue(len(attr.customData) == 1) self.assertEqual(attr.customData['attrCustomData'], {'attrFloat': 1.0}) attr.ClearInfo('customData') self.assertFalse(attr.HasInfo('customData')) self.assertTrue(len(attr.customData) == 0) with self.assertRaises(Tf.ErrorException): # This dict's Gf.Range1d values are not supported as metadata in # scene description. attr.customData = { 'foo': { 'bar': Gf.Range1d(1.0, 2.0) }, 'bar': Gf.Range1d(1.0, 2.0) } self.assertTrue(len(attr.customData) == 0) # Setting doc so that we can clear default without expiring. attr.documentation = 'some documentation' attr.ClearInfo('default') self.assertFalse(attr.HasInfo('default')) self.assertFalse(attr.HasDefaultValue()) self.assertTrue(attr.default is None) for val in range(-10, 10): attr.default = val attr.default = val # do this twice to cover the SetDefault # short-circuit self.assertTrue(attr.HasInfo('default')) self.assertTrue(attr.HasDefaultValue()) self.assertEqual(attr.default, val) self.assertFalse(attr.default is None) self.assertFalse(hasattr(attr.default, '_isVtArray')) attr.ClearDefaultValue() self.assertFalse(attr.HasInfo('default')) self.assertFalse(attr.HasDefaultValue()) self.assertTrue(attr.default is None) shapedAttr = Sdf.AttributeSpec(prim, 'testShapedAttr', Sdf.ValueTypeNames.IntArray) self.assertFalse(shapedAttr.HasInfo('default')) self.assertTrue(shapedAttr.default is None) # set documentation so that we can clear without expiring. shapedAttr.documentation = 'some shaped documentation' for dim in range(1, 10): val = Vt.IntArray(dim) val[...] = range(dim) self.assertEqual(len(val), dim) shapedAttr.default = val self.assertTrue(shapedAttr.HasInfo('default')) self.assertEqual(shapedAttr.default, val) self.assertFalse(shapedAttr.default is None) self.assertTrue(hasattr(shapedAttr.default, '_isVtArray')) shapedAttr.ClearInfo('default') self.assertFalse(shapedAttr.HasInfo('default')) self.assertTrue(shapedAttr.default is None) self.assertEqual(attr.comment, '') attr.comment = 'foo' self.assertEqual(attr.comment, 'foo') attr.comment = 'bar' self.assertEqual(attr.comment, 'bar') attr.comment = '' self.assertEqual(attr.comment, '') attr.ClearInfo('documentation') self.assertFalse(attr.HasInfo('documentation')) self.assertEqual(attr.documentation, '') attr.documentation = 'foo' self.assertTrue(attr.HasInfo('documentation')) self.assertEqual(attr.documentation, 'foo') attr.documentation = 'bar' self.assertTrue(attr.HasInfo('documentation')) self.assertEqual(attr.documentation, 'bar') attr.ClearInfo('documentation') self.assertFalse(attr.HasInfo('documentation')) self.assertEqual(attr.documentation, '') self.assertFalse(attr.HasInfo('displayGroup')) self.assertEqual(attr.displayGroup, '') attr.displayGroup = 'foo' self.assertTrue(attr.HasInfo('displayGroup')) self.assertEqual(attr.displayGroup, 'foo') attr.displayGroup = 'bar' self.assertTrue(attr.HasInfo('displayGroup')) self.assertEqual(attr.displayGroup, 'bar') attr.ClearInfo('displayGroup') self.assertFalse(attr.HasInfo('displayGroup')) self.assertEqual(attr.displayGroup, '')
def makePrim(name, attrDefault): primSpec = Sdf.CreatePrimInLayer(targLyr, name) primSpec.specifier = Sdf.SpecifierDef attr = Sdf.AttributeSpec(primSpec, 'attr', Sdf.ValueTypeNames.Double) attr.default = attrDefault
def _CreateAttrSpecFromNodeAttribute(primSpec, prop, usdSchemaNode, isInput=True): propName = prop.GetName() attrType = prop.GetTypeAsSdfType()[0] # error and early out if duplicate property on usdSchemaNode exists and has # different types if usdSchemaNode: usdSchemaNodeProp = usdSchemaNode.GetInput(propName) if isInput else \ usdSchemaNode.GetOutput(propName) if usdSchemaNodeProp: usdAttrType = usdSchemaNodeProp.GetTypeAsSdfType()[0] if (usdAttrType != attrType): Tf.Warn("Generated schema's property type '%s', " "differs usd schema's property type '%s', for " "duplicated property '%s'" % (attrType, usdAttrType, propName)) return propMetadata = prop.GetMetadata() if not Sdf.Path.IsValidNamespacedIdentifier(propName): Tf.RaiseRuntimeError("Property name (%s) for schema (%s) is an " \ "invalid namespace identifier." %(propName, primSpec.name)) # Apply input/output prefix # Note that UsdShade inputs and outputs tokens contain the ":" delimiter, so # we need to strip this to be used with JoinIdentifier propName = Sdf.Path.JoinIdentifier( \ [UsdShade.Tokens.inputs[:-1], propName]) \ if isInput else \ Sdf.Path.JoinIdentifier( \ [UsdShade.Tokens.outputs[:-1], propName]) # Copy over property parameters options = prop.GetOptions() if options and attrType == Sdf.ValueTypeNames.String: attrType = Sdf.ValueTypeNames.Token attrVariability = Sdf.VariabilityUniform \ if (propMetadata.has_key( PropertyDefiningKeys.USD_VARIABILITY) and \ propMetadata[PropertyDefiningKeys.USD_VARIABILITY] == PropertyDefiningKeys.SDF_VARIABILITY_UNIFORM_STRING) \ else Sdf.VariabilityVarying attrSpec = Sdf.AttributeSpec(primSpec, propName, attrType, attrVariability) if prop.GetHelp(): attrSpec.documentation = prop.GetHelp() elif prop.GetLabel(): # fallback documentation can be label attrSpec.documentation = prop.GetLabel() if prop.GetPage(): attrSpec.displayGroup = prop.GetPage() if prop.GetLabel(): attrSpec.displayName = prop.GetLabel() if options and attrType == Sdf.ValueTypeNames.Token: attrSpec.allowedTokens = [x[1] for x in options] attrSpec.default = prop.GetDefaultValue() # The core UsdLux inputs should remain connectable (interfaceOnly) # even if sdrProperty marks the input as not connectable if isInput and not prop.IsConnectable(): attrSpec.SetInfo(PropertyDefiningKeys.CONNECTABILITY, UsdShade.Tokens.interfaceOnly)
def test_Connections(self): layer = Sdf.Layer.CreateAnonymous() prim = Sdf.PrimSpec(layer, "test", Sdf.SpecifierDef, "bogus_type") attr = Sdf.AttributeSpec(prim, 'numCrvs', Sdf.ValueTypeNames.Int) self.assertFalse(attr.HasInfo('connectionPaths')) self.assertFalse(attr.connectionPathList.isExplicit) self.assertEqual(len(attr.connectionPathList.explicitItems), 0) testPath = Sdf.Path('test.attr') attr.connectionPathList.explicitItems.append(testPath) testPath = testPath.MakeAbsolutePath(attr.path.GetPrimPath()) self.assertTrue(testPath in attr.connectionPathList.explicitItems) self.assertTrue(attr.HasInfo('connectionPaths')) self.assertTrue(attr.connectionPathList.isExplicit) testPath2 = Sdf.Path('test2.attr') attr.connectionPathList.explicitItems.append(testPath2) testPath2 = testPath2.MakeAbsolutePath(attr.path.GetPrimPath()) self.assertTrue(testPath2 in attr.connectionPathList.explicitItems) self.assertEqual(attr.connectionPathList.explicitItems, [testPath, testPath2]) attr.connectionPathList.explicitItems.clear() self.assertTrue(attr.HasInfo('connectionPaths')) self.assertTrue(testPath not in attr.connectionPathList.explicitItems) self.assertTrue(testPath2 not in attr.connectionPathList.explicitItems) self.assertEqual(attr.connectionPathList.explicitItems, []) attr.connectionPathList.explicitItems[:] = [testPath, testPath2] self.assertTrue(attr.HasInfo('connectionPaths')) self.assertTrue(testPath in attr.connectionPathList.explicitItems) self.assertTrue(testPath2 in attr.connectionPathList.explicitItems) self.assertEqual(attr.connectionPathList.explicitItems, [testPath, testPath2]) # adding connection to invalid path: errors expected bogus = Sdf.Path('/Not/A{Valid=Connection}Path/to/test.attribute') self.assertTrue(bogus not in attr.connectionPathList.explicitItems) with self.assertRaises(Tf.ErrorException): attr.connectionPathList.explicitItems.append(bogus) self.assertTrue(bogus not in attr.connectionPathList.explicitItems) # inserting connection paths at various indices testPath1 = Sdf.Path('test.foo').MakeAbsolutePath( attr.path.GetPrimPath()) testPath2 = Sdf.Path('test2.foo').MakeAbsolutePath( attr.path.GetPrimPath()) attr.connectionPathList.explicitItems[:] = [testPath1, testPath2] testPath_middle = Sdf.Path('middle.foo').MakeAbsolutePath( attr.path.GetPrimPath()) attr.connectionPathList.explicitItems.insert(1, testPath_middle) testPath_first = Sdf.Path('first.foo').MakeAbsolutePath( attr.path.GetPrimPath()) attr.connectionPathList.explicitItems.insert(0, testPath_first) with self.assertRaises(IndexError): attr.connectionPathList.explicitItems.insert(1000, 'last.foo') testPath_penultimate = Sdf.Path('penultimate.foo').MakeAbsolutePath( attr.path.GetPrimPath()) attr.connectionPathList.explicitItems.insert(-1, testPath_penultimate) self.assertEqual(attr.connectionPathList.explicitItems, [ testPath_first, testPath1, testPath_middle, testPath_penultimate, testPath2 ]) # removing connection paths by value testPath_dead = Sdf.Path('dead.foo').MakeAbsolutePath( attr.path.GetPrimPath()) self.assertTrue( testPath_dead not in attr.connectionPathList.explicitItems) attr.connectionPathList.explicitItems.insert(2, testPath_dead) self.assertTrue(testPath_dead in attr.connectionPathList.explicitItems) del attr.connectionPathList.explicitItems[testPath_dead] self.assertTrue( testPath_dead not in attr.connectionPathList.explicitItems) # adding duplicate connection path: error expected testPath = attr.connectionPathList.explicitItems[0] self.assertEqual(attr.connectionPathList.explicitItems.count(testPath), 1) with self.assertRaises(Tf.ErrorException): attr.connectionPathList.explicitItems.append(testPath) self.assertEqual(attr.connectionPathList.explicitItems.count(testPath), 1) # modifying connection paths via info API (disallowed) with self.assertRaises(Tf.ErrorException): attr.SetInfo('connectionPaths', Sdf.PathListOp()) with self.assertRaises(Tf.ErrorException): attr.ClearInfo('connectionPaths') # adding variant-selection connection path: error expected varSelPath = Sdf.Path("/Variant{vset=vsel}Is/Not/Allowed") connectionPathListEditor = attr.connectionPathList.explicitItems with self.assertRaises(Tf.ErrorException): connectionPathListEditor.append(varSelPath) # changing paths for connection paths' testPath_shlep = Sdf.Path('shlep.foo').MakeAbsolutePath( attr.path.GetPrimPath()) attr.connectionPathList.explicitItems[:] = [testPath1, testPath2] attr.connectionPathList.ReplaceItemEdits(testPath1, testPath_shlep) self.assertEqual(attr.connectionPathList.explicitItems, [testPath_shlep, testPath2]) attr.connectionPathList.ClearEditsAndMakeExplicit() self.assertTrue(attr.connectionPathList.isExplicit) self.assertEqual(len(attr.connectionPathList.explicitItems), 0) self.assertEqual(len(attr.connectionPathList.addedItems), 0) self.assertEqual(len(attr.connectionPathList.deletedItems), 0) self.assertEqual(len(attr.connectionPathList.orderedItems), 0) attr.connectionPathList.ClearEdits() self.assertFalse(attr.connectionPathList.isExplicit) self.assertEqual(len(attr.connectionPathList.explicitItems), 0) self.assertEqual(len(attr.connectionPathList.addedItems), 0) self.assertEqual(len(attr.connectionPathList.deletedItems), 0) self.assertEqual(len(attr.connectionPathList.orderedItems), 0) testPath3 = Sdf.Path('test3.foo').MakeAbsolutePath( attr.path.GetPrimPath()) testPath4 = Sdf.Path('test4.foo').MakeAbsolutePath( attr.path.GetPrimPath()) testPath_shlep2 = Sdf.Path('shlep2.foo').MakeAbsolutePath( attr.path.GetPrimPath()) attr.connectionPathList.addedItems[:] = [testPath1, testPath2] attr.connectionPathList.deletedItems[:] = [testPath3, testPath4] attr.connectionPathList.orderedItems[:] = [testPath2, testPath1] attr.connectionPathList.ReplaceItemEdits(testPath2, testPath_shlep) attr.connectionPathList.ReplaceItemEdits(testPath3, testPath_shlep2) self.assertEqual(attr.connectionPathList.addedItems, [testPath1, testPath_shlep]) self.assertEqual(attr.connectionPathList.deletedItems, [testPath_shlep2, testPath4]) self.assertEqual(attr.connectionPathList.orderedItems, [testPath_shlep, testPath1]) attr.connectionPathList.ClearEdits() self.assertFalse(attr.connectionPathList.isExplicit) self.assertEqual(len(attr.connectionPathList.explicitItems), 0) self.assertEqual(len(attr.connectionPathList.addedItems), 0) self.assertEqual(len(attr.connectionPathList.deletedItems), 0) self.assertEqual(len(attr.connectionPathList.orderedItems), 0) # removing connection paths via the list editor's RemoveItemEdits API attr.connectionPathList.explicitItems[:] = [testPath1, testPath2] attr.connectionPathList.RemoveItemEdits(testPath2) self.assertEqual(attr.connectionPathList.explicitItems, [testPath1]) attr.connectionPathList.ClearEdits() attr.connectionPathList.addedItems[:] = [testPath1, testPath2] attr.connectionPathList.deletedItems[:] = [testPath1, testPath2] attr.connectionPathList.orderedItems[:] = [testPath1, testPath2] attr.connectionPathList.RemoveItemEdits(testPath1) self.assertEqual(attr.connectionPathList.addedItems, [testPath2]) self.assertEqual(attr.connectionPathList.deletedItems, [testPath2]) self.assertEqual(attr.connectionPathList.orderedItems, [testPath2]) attr.connectionPathList.ClearEdits()
def test_Creation(self): # Test SdPropertySpec abstractness with self.assertRaises(RuntimeError): nullProp = Sdf.PropertySpec() # Test SdAttributeSpec creation and name layer = Sdf.Layer.CreateAnonymous() prim = Sdf.PrimSpec(layer, "test", Sdf.SpecifierDef, "bogus_type") attr = Sdf.AttributeSpec(prim, 'numCrvs', Sdf.ValueTypeNames.Int) self.assertEqual(attr.name, 'numCrvs') self.assertEqual(attr.typeName, Sdf.ValueTypeNames.Int) self.assertEqual(attr.owner, prim) self.assertEqual(len(prim.properties), 1) self.assertTrue(attr in prim.properties) self.assertTrue(attr.name in prim.properties) self.assertEqual(prim.properties[0], attr) self.assertEqual(prim.properties[attr.name], attr) self.assertEqual(prim.properties[0].custom, False) # Test SdfJustCreatePrimAttributeInLayer self.assertTrue( Sdf.JustCreatePrimAttributeInLayer( layer=layer, attrPath='/just/an.attributeSpec', typeName=Sdf.ValueTypeNames.Float)) attr2 = layer.GetAttributeAtPath('/just/an.attributeSpec') self.assertEqual(attr2.name, 'attributeSpec') self.assertEqual(attr2.typeName, Sdf.ValueTypeNames.Float) prim = layer.GetPrimAtPath('/just/an') self.assertEqual(attr2.owner, prim) self.assertTrue(attr2 in prim.properties) self.assertTrue(attr2.name in prim.properties) self.assertEqual(prim.properties[0], attr2) self.assertEqual(prim.properties[attr2.name], attr2) self.assertEqual(attr2.variability, Sdf.VariabilityVarying) self.assertEqual(prim.properties[0].custom, False) self.assertTrue( Sdf.JustCreatePrimAttributeInLayer( layer=layer, attrPath='/just/another.attributeSpec', typeName=Sdf.ValueTypeNames.Int, variability=Sdf.VariabilityUniform, isCustom=True)) attr3 = layer.GetAttributeAtPath('/just/another.attributeSpec') self.assertEqual(attr3.name, 'attributeSpec') self.assertEqual(attr3.typeName, Sdf.ValueTypeNames.Int) prim = layer.GetPrimAtPath('/just/another') self.assertEqual(attr3.owner, prim) self.assertTrue(attr3 in prim.properties) self.assertTrue(attr3.name in prim.properties) self.assertEqual(prim.properties[0], attr3) self.assertEqual(prim.properties[attr2.name], attr3) self.assertEqual(attr3.variability, Sdf.VariabilityUniform) self.assertEqual(prim.properties[0].custom, True) # create a duplicate attribute: error expected with self.assertRaises(RuntimeError): dupe = Sdf.AttributeSpec(attr.owner, attr.name, Sdf.ValueTypeNames.Int) self.assertEqual(len(prim.properties), 1) # create a duplicate attribute via renaming: error expected dupe = Sdf.AttributeSpec(attr.owner, 'dupe', Sdf.ValueTypeNames.Int) self.assertTrue(dupe) with self.assertRaises(RuntimeError): dupe.name = attr.name self.assertEqual(dupe.name, 'dupe') # create an attribute under an expired prim: error expected prim2 = Sdf.PrimSpec(layer, "test2", Sdf.SpecifierDef, "bogus_type") self.assertEqual(prim2.name, 'test2') self.assertFalse(prim2.expired) del layer.rootPrims[prim2.name] self.assertTrue(prim2.expired) with self.assertRaises(RuntimeError): attr2 = Sdf.AttributeSpec(prim2, 'attr2', Sdf.ValueTypeNames.Int) # create an attribute on the PseudoRoot: error expected self.assertEqual(len(layer.pseudoRoot.properties), 0) with self.assertRaises(RuntimeError): bogus = Sdf.AttributeSpec(layer.pseudoRoot, 'badAttr', Sdf.ValueTypeNames.Int) self.assertEqual(len(layer.pseudoRoot.properties), 0)