Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata matching improvements #2536

Merged
merged 3 commits into from May 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions python/GafferCortexUI/FileSequenceParameterValueWidget.py
Expand Up @@ -100,5 +100,5 @@ def __includeFrameRange( plug ) :
return includeFrameRange

for nodeType in __nodeTypes :
Gaffer.Metadata.registerValue( nodeType, "parameters.*", "fileSystemPath:includeSequences", __isFileSequence )
Gaffer.Metadata.registerValue( nodeType, "parameters.*", "fileSystemPath:includeSequenceFrameRange", __includeFrameRange )
Gaffer.Metadata.registerValue( nodeType, "parameters.*...", "fileSystemPath:includeSequences", __isFileSequence )
Gaffer.Metadata.registerValue( nodeType, "parameters.*...", "fileSystemPath:includeSequenceFrameRange", __includeFrameRange )
7 changes: 1 addition & 6 deletions python/GafferCortexUI/ObjectWriterUI.py
Expand Up @@ -91,19 +91,14 @@
""",

"nodule:type", "",
"plugValueWidget:type", "GafferCortexUI.ObjectWriterUI.__createParameterWidget",

],

}

)

##########################################################################
# PlugValueWidgets
##########################################################################

def __createParameterWidget( plug ) :

return GafferCortexUI.CompoundParameterValueWidget( plug.node().parameterHandler(), collapsible=False )

GafferUI.PlugValueWidget.registerCreator( GafferCortex.ObjectWriter, "parameters", __createParameterWidget )
2 changes: 1 addition & 1 deletion python/GafferCortexUI/ParameterisedHolderUI.py
Expand Up @@ -272,7 +272,7 @@ def __plugNoduleType( plug ) :

],

"parameters.*" : [
"parameters.*..." : [

"description", __plugDescription,
"presetNames", __plugPresetNames,
Expand Down
2 changes: 1 addition & 1 deletion python/GafferCortexUI/StringParameterValueWidget.py
Expand Up @@ -101,4 +101,4 @@ def __fixedLineHeight( plug ) :
return fixedLineHeight

for nodeType in __nodeTypes:
Gaffer.Metadata.registerValue( nodeType, "*", "fixedLineHeight", __fixedLineHeight )
Gaffer.Metadata.registerValue( nodeType, "parameters.*...", "fixedLineHeight", __fixedLineHeight )
3 changes: 2 additions & 1 deletion python/GafferDispatchUI/TaskNodeUI.py
Expand Up @@ -54,7 +54,7 @@

"*" : [

"nodule:type", lambda plug : "GafferUI::StandardNodule" if isinstance( plug, GafferDispatch.TaskNode.TaskPlug ) else "",
"nodule:type", "",

],

Expand Down Expand Up @@ -112,6 +112,7 @@
""",

"plugValueWidget:type", "",
"nodule:type", "GafferUI::StandardNodule",

),

Expand Down
15 changes: 7 additions & 8 deletions python/GafferSceneUI/OutputsUI.py
Expand Up @@ -34,7 +34,6 @@
#
##########################################################################

import re
import functools
import imath

Expand Down Expand Up @@ -77,6 +76,12 @@

],

"outputs.*" : [

"plugValueWidget:type", "GafferSceneUI.OutputsUI.ChildPlugValueWidget",

],

"outputs.*.parameters.quantize.value" : [

"description",
Expand Down Expand Up @@ -172,7 +177,7 @@ def __addMenuDefinition( self ) :
return m

# A widget for representing an individual output.
class _ChildPlugWidget( GafferUI.PlugValueWidget ) :
class ChildPlugValueWidget( GafferUI.PlugValueWidget ) :

def __init__( self, childPlug ) :

Expand Down Expand Up @@ -254,9 +259,3 @@ def __deleteButtonClicked( self, button ) :

with Gaffer.UndoScope( self.getPlug().ancestor( Gaffer.ScriptNode ) ) :
self.getPlug().parent().removeChild( self.getPlug() )

## \todo This regex is an interesting case to be considered during the string matching unification for #707. Once that
# is done, intuitively we want to use an "outputs.*" glob expression, but because the "*" will match anything
# at all, including ".", it will match the children of what we want too. We might want to prevent wildcards from
# matching "." when we come to use them in this context.
GafferUI.PlugValueWidget.registerCreator( GafferScene.Outputs, re.compile( "outputs\.[^\.]+$" ), _ChildPlugWidget )
77 changes: 77 additions & 0 deletions python/GafferTest/MetadataTest.py
Expand Up @@ -1022,6 +1022,83 @@ def testPythonUnload() :

subprocess.check_call( [ "gaffer", "python", os.path.dirname( __file__ ) + "/pythonScripts/unloadExceptionScript.py" ] )

def testWildcardsAndDot( self ) :

class MetadataTestNodeE( Gaffer.Node ) :

def __init__( self, name = "MetadataTestNodeE" ) :

Gaffer.Node.__init__( self, name )

self["p"] = Gaffer.Plug()
self["p"]["a"] = Gaffer.IntPlug()
self["p"]["b"] = Gaffer.Plug()
self["p"]["b"]["c"] = Gaffer.IntPlug()
self["p"]["b"]["d"] = Gaffer.IntPlug()

IECore.registerRunTimeTyped( MetadataTestNodeE )

Gaffer.Metadata.registerNode(

MetadataTestNodeE,

# '*' should not match '.', and `...` should
# match any number of components, including 0.
plugs = {
"*" : [
"root", True,
],
"*.a" : [
"a", True,
],
"*.b" : [
"b", True,
],
"*.b.*" : [
"cd", True,
],
"...c" : [
"c", True,
],
"p...d" : [
"d", True,
],
"...[cd]" : [
"cd2", True,
],
"..." : [
"all", True,
],
"p.b..." : [
"allB", True,
],
}

)

n = MetadataTestNodeE()
allPlugs = { n["p"], n["p"]["a"], n["p"]["b"], n["p"]["b"]["c"], n["p"]["b"]["d"] }

for key, plugs in (
( "root", { n["p"] } ),
( "a", { n["p"]["a"] } ),
( "b", { n["p"]["b"] } ),
( "cd", { n["p"]["b"]["c"], n["p"]["b"]["d"] } ),
( "c", { n["p"]["b"]["c"] } ),
( "d", { n["p"]["b"]["d"] } ),
( "cd2", { n["p"]["b"]["c"], n["p"]["b"]["d"] } ),
( "all", allPlugs ),
( "allB", { n["p"]["b"], n["p"]["b"]["c"], n["p"]["b"]["d"] } )
) :

for plug in allPlugs :

if plug in plugs :
self.assertEqual( Gaffer.Metadata.value( plug, key ), True )
self.assertIn( key, Gaffer.Metadata.registeredValues( plug ) )
else :
self.assertEqual( Gaffer.Metadata.value( plug, key ), None )
self.assertNotIn( key, Gaffer.Metadata.registeredValues( plug ) )

if __name__ == "__main__":
unittest.main()
57 changes: 0 additions & 57 deletions python/GafferUI/BoxUI.py
Expand Up @@ -34,7 +34,6 @@
#
##########################################################################

import re
import os
import functools

Expand Down Expand Up @@ -194,62 +193,6 @@ def __upgradeToUseBoxIO( node ) :
with Gaffer.UndoScope( node.scriptNode() ) :
Gaffer.BoxIO.insert( node )

# PlugValueWidget registrations
##########################################################################

GafferUI.PlugValueWidget.registerCreator( Gaffer.Box, re.compile( "in[0-9]*" ), None )
GafferUI.PlugValueWidget.registerCreator( Gaffer.Box, re.compile( "out[0-9]*" ), None )

def __correspondingInternalPlug( plug ) :

node = plug.node()
if plug.direction() == plug.Direction.In :
for output in plug.outputs() :
if node.isAncestorOf( output.node() ) :
return output
elif plug.direction() == plug.Direction.Out :
input = plug.getInput()
if input is not None and node.isAncestorOf( input.node() ) :
return input

return None

def __plugValueWidgetCreator( plug ) :

# When a plug has been promoted, we get the widget that would
# have been used to represent the internal plug, and then
# call setPlug() with the external plug. This allows us to
# transfer custom uis from inside the node to outside the node.
#
# But If the types don't match, we can't expect the
# UI for the internal plug to work with the external
# plug. Typically the types will match, because the
# external plug was created by PlugAlgo.promote(), but
# it's possible to use scripting to connect different
# types, for instance to drive an internal IntPlug with
# an external BoolPlug. In this case we make no attempt
# to transfer the internal UI.
#
# \todo A better solution may be to mandate the use of Metadata to
# choose a widget type for each plug, and then just make sure we
# pass on the internal Metadata.
internalPlug = __correspondingInternalPlug( plug )
if type( internalPlug ) is type( plug ) :
widget = GafferUI.PlugValueWidget.create( internalPlug )
if widget is not None :
widget.setPlug( plug )
return widget

return GafferUI.PlugValueWidget.create( plug, useTypeOnly=True )

## \todo We're registering the Box PlugValueWidget creator for the Reference node too, because
# we want the two to have the same appearance. We perhaps should just have one registration for
# the SubGraph (the base class for Box and Reference) instead, but it's not yet totally clear
# whether or not we'll have future SubGraph subclasses that will want a different behaviour.
for nodeType in ( Gaffer.Box, Gaffer.Reference ) :

GafferUI.PlugValueWidget.registerCreator( nodeType, "*" , __plugValueWidgetCreator )

# Shared menu code
##########################################################################

Expand Down
2 changes: 1 addition & 1 deletion python/GafferUI/NodeUI.py
Expand Up @@ -89,7 +89,7 @@ def __documentationURL( node ) :

"*" : (

"layout:section", lambda plug : "Settings" if isinstance( plug.parent(), Gaffer.Node ) else ""
"layout:section", "Settings"

),

Expand Down
48 changes: 2 additions & 46 deletions python/GafferUI/PlugValueWidget.py
Expand Up @@ -35,8 +35,6 @@
#
##########################################################################

import re
import fnmatch
import functools
import warnings

Expand Down Expand Up @@ -364,9 +362,8 @@ def popupMenuSignal( cls ) :
# "plugValueWidget:type" metadata value, specifying the fully qualified
# python type name for a widget class. To suppress the creation of a widget,
# a value of "" may be registered - in this case None will be returned from
# create(). If useTypeOnly is True, then custom registrations made by
# registerCreator() will be ignored and only the plug type will be taken into
# account in creating a PlugValueWidget.
# create(). If useTypeOnly is True, then the metadata will be ignored and
# only the plug type will be taken into account in creating a PlugValueWidget.
@classmethod
def create( cls, plug, useTypeOnly=False ) :

Expand All @@ -390,20 +387,6 @@ def create( cls, plug, useTypeOnly=False ) :
widgetClass = getattr( widgetClass, n )
return widgetClass( plug )

node = plug.node()
if node is not None :
plugPath = plug.relativeName( node )
nodeHierarchy = IECore.RunTimeTyped.baseTypeIds( node.typeId() )
for nodeTypeId in [ node.typeId() ] + nodeHierarchy :
creators = cls.__nodeTypesToCreators.get( nodeTypeId, None )
if creators :
for creator in creators :
if creator.plugPathMatcher.match( plugPath ) :
if creator.creator is not None :
return creator.creator( plug, **(creator.creatorKeywordArgs) )
else :
return None

# if that failed, then just create something based on the type of the plug
typeId = plug.typeId()
for plugTypeId in [ plug.typeId() ] + IECore.RunTimeTyped.baseTypeIds( plug.typeId() ) :
Expand All @@ -427,34 +410,7 @@ def registerType( cls, plugClassOrTypeId, creator ) :

cls.__plugTypesToCreators[plugTypeId] = creator

## \deprecated
## \todo Use "plugValueWidget:type" metadata everywhere instead of
# using this. Then remove this method.
@classmethod
def registerCreator( cls, nodeClassOrTypeId, plugPath, creator, **creatorKeywordArgs ) :

if isinstance( nodeClassOrTypeId, IECore.TypeId ) :
nodeTypeId = nodeClassOrTypeId
else :
nodeTypeId = nodeClassOrTypeId.staticTypeId()

if isinstance( plugPath, basestring ) :
plugPath = re.compile( fnmatch.translate( plugPath ) )
else :
assert( type( plugPath ) is type( re.compile( "" ) ) )

creators = cls.__nodeTypesToCreators.setdefault( nodeTypeId, [] )

creator = IECore.Struct(
plugPathMatcher = plugPath,
creator = creator,
creatorKeywordArgs = creatorKeywordArgs,
)

creators.insert( 0, creator )

__plugTypesToCreators = {}
__nodeTypesToCreators = {}

def __plugDirtied( self, plug ) :

Expand Down
2 changes: 1 addition & 1 deletion python/GafferUITest/StandardNodeGadgetTest.py
Expand Up @@ -86,7 +86,7 @@ def noduleType( plug ) :
else :
return "GafferUI::StandardNodule"

Gaffer.Metadata.registerValue( DeeplyNestedNode, "*", "nodule:type", noduleType )
Gaffer.Metadata.registerValue( DeeplyNestedNode, "...", "nodule:type", noduleType )

g = GafferUI.StandardNodeGadget( n )

Expand Down