def testRefresh(self): fileName = self.temporaryDirectory() + "/refreshTest.abc" shutil.copyfile( os.path.dirname(__file__) + "/alembicFiles/cube.abc", fileName) a = GafferScene.AlembicSource() a["fileName"].setValue(fileName) a["refreshCount"].setValue(self.uniqueInt(fileName)) self.assertSceneValid(a["out"]) self.assertEqual(a["out"].childNames("/"), IECore.InternedStringVectorData(["group1"])) shutil.copyfile( os.path.dirname(__file__) + "/alembicFiles/animatedCube.abc", fileName) self.assertSceneValid(a["out"]) self.assertEqual(a["out"].childNames("/"), IECore.InternedStringVectorData(["group1"])) a["refreshCount"].setValue(self.uniqueInt(fileName)) # We have to skip the test of built in sets, because our alembic file contains cameras # and alembic doesn't provide a means of flagging them upfront. self.assertSceneValid(a["out"], assertBuiltInSetsComplete=False) self.assertEqual( a["out"].childNames("/"), IECore.InternedStringVectorData( ["front", "pCube1", "persp", "side", "top"]))
def testCube( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/cube.abc" ) self.assertSceneValid( a["out"] ) self.assertEqual( a["out"].object( "/" ), IECore.NullObject() ) self.assertEqual( a["out"].transform( "/" ), IECore.M44f() ) self.assertEqual( a["out"].bound( "/" ), IECore.Box3f( IECore.V3f( -2 ), IECore.V3f( 2 ) ) ) self.assertEqual( a["out"].attributes( "/" ), IECore.CompoundObject() ) self.assertEqual( a["out"].childNames( "/" ), IECore.InternedStringVectorData( [ "group1"] ) ) self.assertEqual( a["out"].object( "/group1" ), IECore.NullObject() ) self.assertEqual( a["out"].transform( "/group1" ), IECore.M44f.createScaled( IECore.V3f( 2 ) ) * IECore.M44f.createTranslated( IECore.V3f( 2, 0, 0 ) ) ) self.assertEqual( a["out"].bound( "/group1" ), IECore.Box3f( IECore.V3f( -2, -1, -1 ), IECore.V3f( 0, 1, 1 ) ) ) self.assertEqual( a["out"].attributes( "/group1" ), IECore.CompoundObject() ) self.assertEqual( a["out"].childNames( "/group1" ), IECore.InternedStringVectorData( [ "pCube1"] ) ) self.assertEqual( a["out"].object( "/group1/pCube1" ), IECore.NullObject() ) self.assertEqual( a["out"].transform( "/group1/pCube1" ), IECore.M44f.createTranslated( IECore.V3f( -1, 0, 0 ) ) ) self.assertEqual( a["out"].bound( "/group1/pCube1" ), IECore.Box3f( IECore.V3f( -1 ), IECore.V3f( 1 ) ) ) self.assertEqual( a["out"].attributes( "/group1/pCube1" ), IECore.CompoundObject() ) self.assertEqual( a["out"].childNames( "/group1/pCube1" ), IECore.InternedStringVectorData( [ "pCubeShape1"] ) ) self.assertTrue( isinstance( a["out"].object( "/group1/pCube1/pCubeShape1" ), IECore.MeshPrimitive ) ) self.assertEqual( a["out"].transform( "/group1/pCube1/pCubeShape1" ), IECore.M44f() ) self.assertEqual( a["out"].bound( "/group1/pCube1/pCubeShape1" ), IECore.Box3f( IECore.V3f( -1 ), IECore.V3f( 1 ) ) ) self.assertEqual( a["out"].attributes( "/group1/pCube1/pCubeShape1" ), IECore.CompoundObject() ) self.assertEqual( a["out"].childNames( "/group1/pCube1/pCubeShape1" ), IECore.InternedStringVectorData( [] ) )
def testEmptyFileName( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( "" ) self.assertSceneValid( a["out"] ) self.assertTrue( a["out"].bound( "/" ).isEmpty() )
def __init__( self, path ) : column = GafferUI.SplitContainer( GafferUI.SplitContainer.Orientation.Vertical ) GafferUI.PathPreviewWidget.__init__( self, column, path ) self.__script = Gaffer.ScriptNode( "scenePreview" ) # for reading IECore.SceneInterface files (scc, lscc) self.__script["SceneReader"] = GafferScene.SceneReader() # for reading Alembic files (abc) self.__script["AlembicSource"] = GafferScene.AlembicSource() # for reading more generic single object files (cob, ptc, pdc, etc) ## \todo: can we unify all file input to SceneReader by creating a SceneInterface that makes # single object scenes using Reader ops behind the scenes? self.__script["ObjectPreview"] = _ObjectPreview() # display points and curves GL style rather than disks and ribbons self.__script["OpenGLAttributes"] = GafferScene.OpenGLAttributes( "OpenGLAttributes" ) self.__script["OpenGLAttributes"]["attributes"]["pointsPrimitiveUseGLPoints"]["value"].setValue( 'forAll' ) self.__script["OpenGLAttributes"]["attributes"]["pointsPrimitiveUseGLPoints"]["enabled"].setValue( True ) self.__script["OpenGLAttributes"]["attributes"]["curvesPrimitiveUseGLLines"]["enabled"].setValue( True ) self.__script["camera"] = _Camera() self.__script["camera"]["in"].setInput( self.__script["OpenGLAttributes"]["out"] ) self.__viewer = GafferUI.Viewer( self.__script ) column.append( self.__viewer ) column.append( GafferUI.Timeline( self.__script ) ) self.__script.selection().add( self.__script["camera"] ) self._updateFromPath()
def testAnimation(self): a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname(__file__) + "/alembicFiles/animatedCube.abc") self.assertSceneValid(a["out"]) b = IECoreAlembic.AlembicInput( os.path.dirname(__file__) + "/alembicFiles/animatedCube.abc") c = b.child("pCube1").child("pCubeShape1") numSamples = b.numSamples() startTime = b.timeAtSample(0) endTime = b.timeAtSample(numSamples - 1) for i in range(0, numSamples * 2): time = startTime + (endTime - startTime) * float(i) / (numSamples * 2 - 1) c = Gaffer.Context() c.setFrame(time * 24) with c: self.assertBoxesAlmostEqual(a["out"].bound("/"), b.boundAtTime(time), 6) self.assertBoxesAlmostEqual( a["out"].bound("/pCube1/pCubeShape1"), b.boundAtTime(time), 6)
def testRefresh(self): shutil.copyfile( os.path.dirname(__file__) + "/alembicFiles/cube.abc", self.__refreshTestFileName) a = GafferScene.AlembicSource() a["fileName"].setValue(self.__refreshTestFileName) self.assertSceneValid(a["out"]) self.assertEqual(a["out"].childNames("/"), IECore.InternedStringVectorData(["group1"])) shutil.copyfile( os.path.dirname(__file__) + "/alembicFiles/animatedCube.abc", self.__refreshTestFileName) self.assertSceneValid(a["out"]) self.assertEqual(a["out"].childNames("/"), IECore.InternedStringVectorData(["group1"])) a["refreshCount"].setValue(a["refreshCount"].getValue() + 1) self.assertSceneValid(a["out"]) self.assertEqual( a["out"].childNames("/"), IECore.InternedStringVectorData( ["front", "pCube1", "persp", "side", "top"]))
def testAnimation(self): a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname(__file__) + "/alembicFiles/animatedCube.abc") # We have to skip the test of built in sets, because our alembic file contains cameras # and alembic doesn't provide a means of flagging them upfront. self.assertSceneValid(a["out"], assertBuiltInSetsComplete=False) b = IECoreAlembic.AlembicInput( os.path.dirname(__file__) + "/alembicFiles/animatedCube.abc") c = b.child("pCube1").child("pCubeShape1") numSamples = b.numSamples() startTime = b.timeAtSample(0) endTime = b.timeAtSample(numSamples - 1) for i in range(0, numSamples * 2): time = startTime + (endTime - startTime) * float(i) / (numSamples * 2 - 1) c = Gaffer.Context() c.setTime(time) with c: self.assertBoxesAlmostEqual(a["out"].bound("/"), b.boundAtTime(time), 6) self.assertBoxesAlmostEqual( a["out"].bound("/pCube1/pCubeShape1"), b.boundAtTime(time), 6)
def testFullTransform( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/cube.abc" ) self.assertEqual( a["out"].fullTransform( "/" ), IECore.M44f() ) self.assertEqual( a["out"].fullTransform( "/group1" ), IECore.M44f.createScaled( IECore.V3f( 2 ) ) * IECore.M44f.createTranslated( IECore.V3f( 2, 0, 0 ) ) ) self.assertEqual( a["out"].fullTransform( "/group1/pCube1" ), IECore.M44f.createTranslated( IECore.V3f( -1, 0, 0 ) ) * a["out"].fullTransform( "/group1" ) ) self.assertEqual( a["out"].fullTransform( "/group1/pCube1/pCubeShape1" ), a["out"].fullTransform( "/group1/pCube1" ) )
def test( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/cube.abc" ) p = GafferScene.ScenePath( a["out"], Gaffer.Context(), "/" ) c = p.children() self.assertEqual( len( c ), 1 ) self.assertEqual( str( c[0] ), "/group1" )
def testRootHashesEqual(self): a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname(__file__) + "/alembicFiles/animatedCube.abc") s = GafferScene.SubTree() s["in"].setInput(a["out"]) self.assertSceneValid(s["out"]) self.assertPathHashesEqual(a["out"], "/", s["out"], "/")
def testRootHashesEqual( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/animatedCube.abc" ) s = GafferScene.SubTree() s["in"].setInput( a["out"] ) # We have to skip the test of built in sets, because our alembic file contains cameras # and alembic doesn't provide a means of flagging them upfront. self.assertSceneValid( s["out"], assertBuiltInSetsComplete = False ) self.assertPathHashesEqual( a["out"], "/", s["out"], "/" )
def testSubTree( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/animatedCube.abc" ) s = GafferScene.SubTree() s["in"].setInput( a["out"] ) s["root"].setValue( "/pCube1" ) self.assertSceneValid( s["out"] ) self.assertScenesEqual( s["out"], a["out"], scenePlug2PathPrefix = "/pCube1" ) self.assertTrue( a["out"].object( "/pCube1/pCubeShape1", _copy = False ).isSame( s["out"].object( "/pCubeShape1", _copy = False ) ) )
def testRelative( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/cube.abc" ) p = GafferScene.ScenePath( a["out"], Gaffer.Context(), "group1" ) self.assertEqual( str( p ), "group1" ) self.assertEqual( p.root(), "" ) self.assertEqual( [ str( c ) for c in p.children() ], [ "group1/pCube1" ] ) p2 = p.copy() self.assertEqual( str( p2 ), "group1" ) self.assertEqual( p2.root(), "" ) self.assertEqual( [ str( c ) for c in p2.children() ], [ "group1/pCube1" ] )
def testPassThrough( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/animatedCube.abc" ) s = GafferScene.SubTree() s["in"].setInput( a["out"] ) # We have to skip the test of built in sets, because our alembic file contains cameras # and alembic doesn't provide a means of flagging them upfront. self.assertSceneValid( s["out"], assertBuiltInSetsComplete = False ) self.assertScenesEqual( a["out"], s["out"] ) self.assertSceneHashesEqual( a["out"], s["out"] ) self.assertTrue( a["out"].object( "/pCube1/pCubeShape1", _copy = False ).isSame( s["out"].object( "/pCube1/pCubeShape1", _copy = False ) ) )
def testIncludeRoot( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/animatedCube.abc" ) s = GafferScene.SubTree() s["in"].setInput( a["out"] ) s["root"].setValue( "/pCube1" ) s["includeRoot"].setValue( True ) self.assertSceneValid( s["out"] ) self.assertScenesEqual( s["out"], a["out"], pathsToIgnore = [ "/", ] ) self.assertEqual( s["out"].childNames( "/" ), IECore.InternedStringVectorData( [ "pCube1" ] ) ) self.assertEqual( s["out"].bound( "/" ), a["out"].bound( "/pCube1" ) ) self.assertTrue( a["out"].object( "/pCube1/pCubeShape1", _copy = False ).isSame( s["out"].object( "/pCube1/pCubeShape1", _copy = False ) ) )
def testRootBoundWithTransformedChild( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname( __file__ ) + "/alembicFiles/animatedCube.abc" ) s = GafferScene.SubTree() s["in"].setInput( a["out"] ) s["root"].setValue( "/pCube1" ) s["includeRoot"].setValue( True ) with Gaffer.Context() as c : c.setFrame( 10 ) expectedRootBound = a["out"].bound( "/pCube1" ) expectedRootBound = expectedRootBound.transform( a["out"].transform( "/pCube1" ) ) self.assertEqual( s["out"].bound( "/" ), expectedRootBound )
def testIncludeRootPassesThroughWhenNoRootSpecified(self): a = GafferScene.AlembicSource() a["fileName"].setValue( os.path.dirname(__file__) + "/alembicFiles/animatedCube.abc") s = GafferScene.SubTree() s["in"].setInput(a["out"]) s["root"].setValue("") s["includeRoot"].setValue(True) self.assertSceneValid(s["out"]) self.assertScenesEqual(a["out"], s["out"]) self.assertSceneHashesEqual(a["out"], s["out"]) self.assertTrue(a["out"].object( "/pCube1/pCubeShape1", _copy=False).isSame(s["out"].object("/pCube1/pCubeShape1", _copy=False)))
def compute(self, plug, context): #print 'compute', plug, context assert (plug.isSame(self["out"])) self.op = assetUtils.assetOP(self['asset'].getValue()) if not self.op.data: raise Exception("Asset %s doesn't exist!", self['asset'].getValue()) ret = [x.getValue() for x in self['in'] if x.getValue().strip()] if not self['enabled'].getValue(): # if not enable, we disable everything that is connected to a model/animation # that way we prevent shaders and other model setups to be loaded! if [x for x in ['SAManimation', 'SAMmodel'] if x in str(self)]: ret = [] # if self['enabled'].getValue(): # if 'SAMcamera' in str(type(self)): # ret += [ '[ { "op" : assetUtils.assetOP("%s","@app@"), "node":"%s", "enable": %s, "camera": True } ]' % ( self['asset'].getValue(), self['asset'].getValue(), self['enabled'].getValue()) ] # else: # ret += [ '[ { "op" : assetUtils.assetOP("%s","@app@"), "node":"%s", "enable": %s } ]' % ( self['asset'].getValue(), self['asset'].getValue(), self['enabled'].getValue()) ] ret += [ '[ { "op" : assetUtils.assetOP("%s","@app@"), "node":"%s", "enable": %s, "frame" : %s} ]' % (self['asset'].getValue(), self['asset'].getValue(), self['enabled'].getValue(), context.getTime()) ] ret = '+'.join(ret) plug.setValue(ret) if self.op.data.has_key('multiplePublishedFiles'): self.alembic = [] for each in self.op.data['multiplePublishedFiles']: if '.abc' in each: self.alembic += [GafferScene.AlembicSource()] self.alembic[-1]['fileName'].setValue(each)
def __init__(self, name="none"): GafferScene.SceneNode.__init__(self, name) self['asset'] = Gaffer.StringPlug('asset', Gaffer.Plug.Direction.In, '') Gaffer.MetadataAlgo.setReadOnly(self['asset'], True) self['name'] = Gaffer.StringPlug() Gaffer.MetadataAlgo.setReadOnly(self['name'], True) self['camera'] = Gaffer.StringVectorDataPlug( 'camera', Gaffer.Plug.Direction.In, IECore.StringVectorData([])) Gaffer.MetadataAlgo.setReadOnly(self['name'], True) self['alembic'] = Gaffer.StringPlug() Gaffer.MetadataAlgo.setReadOnly(self['name'], True) self['overrideAssetMask'] = Gaffer.StringPlug() Gaffer.MetadataAlgo.setReadOnly(self['overrideAssetMask'], True) self['previewAlembic'] = Gaffer.BoolPlug('previewAlembic', Gaffer.Plug.Direction.In, True) # a input scene nodule, so we can connect another asset to this one # useful to connect shader to model/animation self['in'] = Gaffer.ArrayPlug("in", Gaffer.Plug.Direction.In, element=GafferScene.ScenePlug("in0")) # we use this to convert the asset parameter to a gaffer name class logic(genericComputeNode): ''' we use this small python compute node to do some logic in the sceneNode. Basically it works like an expression, which uses the value of "asset" plug to setup the internal alembicSource node so alembic shows up in the viewer. it also sets the name of our node, so it shows up in the hierarchy list. ''' def _init(self): # self.add( GafferScene.ScenePlug( "inScene", Gaffer.Plug.Direction.In ) ) self.add( GafferScene.ScenePlug("alembic", Gaffer.Plug.Direction.In)) self.add( GafferScene.ScenePlug("enable", Gaffer.Plug.Direction.In)) self.add( Gaffer.StringPlug("inAsset", Gaffer.Plug.Direction.In, "")) self.add( Gaffer.StringPlug("out", Gaffer.Plug.Direction.Out, "")) self.add( Gaffer.StringPlug("outABC", Gaffer.Plug.Direction.Out, "")) self.add( Gaffer.StringPlug("outCAMERA", Gaffer.Plug.Direction.Out, "")) self.add( Gaffer.StringVectorDataPlug("outCAMERAs", Gaffer.Plug.Direction.Out, IECore.StringVectorData([]))) self.add( Gaffer.BoolPlug("outCAMERAenable", Gaffer.Plug.Direction.Out)) self.add( Gaffer.StringPlug("outCAMERA_proj", Gaffer.Plug.Direction.Out, "")) self.add( Gaffer.FloatPlug("outCAMERA_fov", Gaffer.Plug.Direction.Out)) self.add( Gaffer.FloatPlug("outModelAsset", Gaffer.Plug.Direction.Out)) # self.add( Gaffer.StringPlug( "out2", Gaffer.Plug.Direction.Out, "" ) ) # self.add( GafferScene.ScenePlug( "outScene", Gaffer.Plug.Direction.Out ) ) def _compute(cls, plug, context): import utils # print '===>',cls['in'].getValue() assetPath = str(cls['inAsset'].getValue()) asset = assetPath.split('/') def getCameras(scene, path, l=[]): for childName in scene.childNames(path): if scene.object(path + '/' + str(childName)).typeName() == 'Camera': l += [path + '/' + str(childName)] l[-1] = l[-1].replace('//', '/') getCameras(scene, path + '/' + str(childName), l) return l if not asset[0]: asset = ['unnamed', 'unnamed', 'unnamed'] node = self["__alembic"] # if plug.isSame( self['out'] ) : if plug.isSame(cls['out']): cls['out'].setValue(utils.samAssetToGaffer(assetPath)) elif plug.isSame(cls['outCAMERAenable']): cls['outCAMERAenable'].setValue(False) if asset[1] in ['alembic'] and asset[0] in ['camera']: for camera in getCameras(node["out"], "/"): cls['outCAMERAenable'].setValue(True) elif plug.isSame(cls['outCAMERA']): if asset[1] in ['alembic'] and asset[0] in ['camera']: cameras = [] for camera in getCameras(node["out"], "/"): cameras += [ utils.samAssetToGaffer(assetPath) + '/' + camera ] cls['outCAMERA'].setValue(cameras[-1]) else: cls['outCAMERA'].setValue('no camera found') elif plug.isSame(cls['outCAMERAs']): cameras = [] if asset[1] in ['alembic'] and asset[0] in ['camera']: for camera in getCameras(node["out"], "/"): cameras += [camera] cls['outCAMERAs'].setValue( IECore.StringVectorData(cameras)) elif plug.isSame(cls['outCAMERA_proj']): if asset[1] in ['alembic'] and asset[0] in ['camera']: for camera in getCameras(node["out"], "/"): cls['outCAMERA_proj'].setValue( str(node["out"].object(camera).parameters() ['projection'])) elif plug.isSame(cls['outCAMERA_fov']): if asset[1] in ['alembic'] and asset[0] in ['camera']: for camera in getCameras(node["out"], "/"): cls['outCAMERA_fov'].setValue( float(node["out"].object(camera).parameters() ['projection:fov'])) elif plug.isSame(cls['outABC']): if asset[1] in ['alembic']: cls['outABC'].setValue( assetUtils.assetOP( assetPath).data['multiplePublishedFiles'][0]) else: cls['outABC'].setValue("") elif plug.isSame(cls['outModelAsset']): if asset[0] in ['model']: cls['outModelAsset'].setValue(0) else: cls['outModelAsset'].setValue(1) self["__computeNode"] = logic(self.getName() + '_computeNode') self["__computeNode"]['inAsset'].setInput(self['asset']) # self["__computeNode"]['inScene'].setInput( self['in'] ) # self["__computeNode"]._compute = _compute #lambda cls, plug, context: self["__computeNode"]['out'].setValue(str( self['in'][0].getValue() ).replace('/',' | ')) self['name'].setInput(self["__computeNode"]['out']) self['camera'].setInput(self["__computeNode"]['outCAMERAs']) self['alembic'].setInput(self["__computeNode"]['outABC']) self["__alembic"] = GafferScene.AlembicSource() self["__alembic"]["enabled"].setInput(self["previewAlembic"]) self["__alembic"]['fileName'].setInput(self["__computeNode"]['outABC']) self["__alembicTimeWarp"] = GafferScene.SceneTimeWarp() self["__alembicTimeWarp"]['speed'].setInput( self["__computeNode"]['outModelAsset']) self["__alembicTimeWarp"]['in'].setInput(self['__alembic']['out']) self["__cameraSet"] = GafferScene.Set() self["__cameraSet"]['mode'].setValue(1) self["__cameraSet"]['name'].setValue('__cameras') self["__cameraSet"]['paths'].setInput( self["__computeNode"]['outCAMERAs']) self["__cameraSet"]['in'].setInput(self['__alembicTimeWarp']['out']) self["__obj"] = GafferScene.ObjectToScene() self["__obj"]["enabled"].setInput(self["enabled"]) self["__obj"]['name'].setInput(self["__computeNode"]['out']) self["__obj"]['sets'].setValue("assetList") self["__parent"] = GafferScene.Parent() self["__parent"]['in'].setInput(self['__obj']['out']) self["__parent"]['child'].setInput(self['__cameraSet']['out']) self["__parent"]['parent'].setInput(self["__computeNode"]['out']) # we use this group0/subtree0 to connect the compound input of this node into our sub network self["__group0"] = GafferScene.Group() self["__group0"]["enabled"].setInput(self["enabled"]) self["__group0"]["in"].setInput(self["in"]) # remove the group and parent the nodes back to root self["__subtree0"] = GafferScene.SubTree() self["__subtree0"]["enabled"].setInput(self["enabled"]) self["__subtree0"]['root'].setValue('/group') self["__subtree0"]['in'].setInput(self["__group0"]['out']) # group1/subtree1 merges the inputs with the internal network scene self["__group1"] = GafferScene.Group() self["__group1"]["enabled"].setInput(self["enabled"]) self["__group1"]["in"][0].setInput(self["__subtree0"]['out']) self["__group1"]["in"][1].setInput(self["__parent"]["out"]) # self["__group0"]["in"][2].setInput( self["__alembic"]['out'] ) # remove the group and parent the nodes back to root self["__subtree1"] = GafferScene.SubTree() self["__subtree1"]["enabled"].setInput(self["enabled"]) self["__subtree1"]['root'].setValue('/group') self["__subtree1"]['in'].setInput(self["__group1"]['out']) self["out"].setInput(self["__subtree1"]["out"])
def testInvalidFileName( self ) : a = GafferScene.AlembicSource() a["fileName"].setValue( "nonexistent.abc" ) self.assertRaises( RuntimeError, a["out"].childNames, "/" )