# HG changeset patch # User Laurent Bessard # Date 1378243973 -7200 # Node ID 7856cd7767d6e688477e447e9362b47c95d2ca20 # Parent fcca121a000f10e878b8c5a433d85bf15a99b605 Removed dictionaries storing datatypes and pous defined in project and pou and datatype using tree from model diff -r fcca121a000f -r 7856cd7767d6 PLCControler.py --- a/PLCControler.py Mon Sep 02 23:46:38 2013 +0200 +++ b/PLCControler.py Tue Sep 03 23:32:53 2013 +0200 @@ -568,7 +568,7 @@ instances.append(var_path) else: pou = project.getpou(var_type) - if pou is not None and project.ElementIsUsedBy(pou_type, var_type): + if pou is not None:# and project.ElementIsUsedBy(pou_type, var_type): instances.extend( self.RecursiveSearchPouInstances( project, pou_type, var_path, @@ -603,7 +603,7 @@ if pou_type == words[1]: instances.append(pou_path) pou = project.getpou(pou_type) - if pou is not None and project.ElementIsUsedBy(words[1], pou_type): + if pou is not None:# and project.ElementIsUsedBy(words[1], pou_type): instances.extend( self.RecursiveSearchPouInstances( project, words[1], pou_path, @@ -733,23 +733,23 @@ # Return if data type given by name is used by another data type or pou def DataTypeIsUsed(self, name, debug = False): - project = self.GetProject(debug) - if project is not None: - return project.ElementIsUsed(name) + #project = self.GetProject(debug) + #if project is not None: + # return project.ElementIsUsed(name) return False # Return if pou given by name is used by another pou def PouIsUsed(self, name, debug = False): - project = self.GetProject(debug) - if project is not None: - return project.ElementIsUsed(name) + #project = self.GetProject(debug) + #if project is not None: + # return project.ElementIsUsed(name) return False # Return if pou given by name is directly or undirectly used by the reference pou def PouIsUsedBy(self, name, reference, debug = False): - project = self.GetProject(debug) - if project is not None: - return project.ElementIsUsedBy(name, reference) + #project = self.GetProject(debug) + #if project is not None: + # return project.ElementIsUsedBy(name, reference) return False def GenerateProgram(self, filepath=None): @@ -837,7 +837,6 @@ pou = self.Project.getpou(name) if pou is not None: pou.setpouType(pou_type) - self.Project.RefreshCustomBlockTypes() self.BufferProject() def GetPouXml(self, pou_name): @@ -980,7 +979,6 @@ if datatype is not None: datatype.setname(new_name) self.Project.updateElementName(old_name, new_name) - self.Project.RefreshElementUsingTree() self.BufferProject() # Change the name of a pou @@ -991,8 +989,6 @@ if pou is not None: pou.setname(new_name) self.Project.updateElementName(old_name, new_name) - self.Project.RefreshElementUsingTree() - self.Project.RefreshCustomBlockTypes() self.BufferProject() # Change the name of a pou transition @@ -1029,7 +1025,6 @@ for var in varlist.getvariable(): if var.getname() == old_name: var.setname(new_name) - self.Project.RefreshCustomBlockTypes() self.BufferProject() # Change the name of a configuration @@ -1068,7 +1063,6 @@ pou = project.getpou(name) if pou is not None: pou.setdescription(description) - project.RefreshCustomBlockTypes() self.BufferProject() # Return the type of the pou given by its name @@ -1402,9 +1396,7 @@ if not en: tree.insert(0, ("EN", "BOOL", ([], []))) return tree, [] - datatype = project.getdataType(typename) - if datatype is None: - datatype = self.GetConfNodeDataType(typename) + datatype = self.GetDataType(typename) if datatype is not None: tree = [] basetype_content = datatype.baseType.getcontent() @@ -1463,9 +1455,7 @@ pou.interface = PLCOpenParser.CreateElement("interface", "pou") # Set Pou interface pou.setvars([varlist for varlist_type, varlist in self.ExtractVarLists(vars)]) - self.Project.RefreshElementUsingTree() - self.Project.RefreshCustomBlockTypes() - + # Replace the return type of the pou given by its name (only for functions) def SetPouInterfaceReturnType(self, name, return_type): if self.Project is not None: @@ -1488,9 +1478,7 @@ derived_type = PLCOpenParser.CreateElement("derived", "dataType") derived_type.setname(return_type) return_type.setcontent(derived_type) - self.Project.RefreshElementUsingTree() - self.Project.RefreshCustomBlockTypes() - + def UpdateProjectUsedPous(self, old_name, new_name): if self.Project is not None: self.Project.updateElementName(old_name, new_name) @@ -1529,7 +1517,8 @@ def AddConfNodeTypesList(self, typeslist): self.ConfNodeTypes.extend(typeslist) addedcat = [{"name": _("%s POUs") % confnodetypes["name"], - "list": confnodetypes["types"].GetCustomBlockTypes()} + "list": [pou.getblockInfos() + for pou in confnodetypes["types"].getpous()]} for confnodetypes in typeslist] self.TotalTypes.extend(addedcat) for cat in addedcat: @@ -1543,23 +1532,14 @@ self.TotalTypesDict = StdBlckDct.copy() self.TotalTypes = StdBlckLst[:] - def GetConfNodeBlockTypes(self): - return [{"name": _("%s POUs") % confnodetypes["name"], - "list": confnodetypes["types"].GetCustomBlockTypes()} - for confnodetypes in self.ConfNodeTypes] - def GetConfNodeDataTypes(self, exclude = None, only_locatables = False): return [{"name": _("%s Data Types") % confnodetypes["name"], - "list": [datatype["name"] for datatype in confnodetypes["types"].GetCustomDataTypes(exclude, only_locatables)]} + "list": [ + datatype.getname() + for datatype in confnodetypes["types"].getdataTypes() + if not only_locatables or self.IsLocatableDataType(datatype, debug)]} for confnodetypes in self.ConfNodeTypes] - def GetConfNodeDataType(self, typename): - for confnodetype in self.ConfNodeTypes: - datatype = confnodetype["types"].getdataType(typename) - if datatype is not None: - return datatype - return None - def GetVariableLocationTree(self): return [] @@ -1613,7 +1593,16 @@ return result_blocktype project = self.GetProject(debug) if project is not None: - return project.GetCustomBlockType(typename, inputs) + blocktype = project.getpou(typename) + if blocktype is not None: + blocktype_infos = blocktype.getblockInfos() + if inputs in [None, "undefined"]: + return blocktype_infos + + if inputs == tuple([var_type + for name, var_type, modifier in blocktype_infos["inputs"]]): + return blocktype_infos + return None # Return Block types checking for recursion @@ -1625,22 +1614,19 @@ if project is not None: pou_type = None if words[0] in ["P","T","A"]: - blocktypes = [] name = words[1] pou_type = self.GetPouType(name, debug) - if pou_type == "function": - for category in self.TotalTypes: - cat = {"name" : category["name"], "list" : []} - for block in category["list"]: - if block["type"] == "function": - cat["list"].append(block) - if len(cat["list"]) > 0: - blocktypes.append(cat) - else: - blocktypes = [category for category in self.TotalTypes] + filter = (["function"] + if pou_type == "function" or words[0] == "T" + else ["functionBlock", "function"]) + blocktypes = [ + {"name": category["name"], + "list": [block for block in category["list"] + if block["type"] in filter]} + for category in self.TotalTypes] blocktypes.append({"name" : USER_DEFINED_POUS, - "list": project.GetCustomBlockTypes(name, - pou_type == "function" or words[0] == "T")}) + "list": [pou.getblockInfos() + for pou in project.getpous(name, filter)]}) return blocktypes return self.TotalTypes @@ -1653,11 +1639,11 @@ blocktypes.append(block["name"]) project = self.GetProject(debug) if project is not None: - name = "" words = tagname.split("::") - if words[0] in ["P","T","A"]: - name = words[1] - blocktypes.extend(project.GetCustomFunctionBlockTypes(name)) + blocktypes.extend([pou.getname() + for pou in project.getpous( + words[1] if words[0] in ["P","T","A"] else None, + ["functionBlock"])]) return blocktypes # Return Block types checking for recursion @@ -1669,7 +1655,9 @@ blocktypes.append(blocktype["name"]) project = self.GetProject(debug) if project is not None: - blocktypes.extend(project.GetCustomBlockResource()) + blocktypes.extend( + [pou.getblockInfos() + for pou in project.getpous(filter=["program"])]) return blocktypes # Return Data Types checking for recursion @@ -1684,7 +1672,10 @@ words = tagname.split("::") if words[0] in ["D"]: name = words[1] - datatypes.extend([datatype["name"] for datatype in project.GetCustomDataTypes(name, only_locatables)]) + datatypes.extend([ + datatype.getname() + for datatype in project.getdataTypes(name) + if not only_locatables or self.IsLocatableDataType(datatype, debug)]) if confnodetypes: for category in self.GetConfNodeDataTypes(name, only_locatables): datatypes.extend(category["list"]) @@ -1759,23 +1750,26 @@ return not typename.startswith("ANY") return True + def IsLocatableDataType(self, datatype, debug = False): + basetype_content = datatype.baseType.getcontent() + basetype_content_type = basetype_content.getLocalTag() + if basetype_content_type in ["enum", "struct"]: + return False + elif basetype_content_type == "derived": + return self.IsLocatableType(basetype_content.getname()) + elif basetype_content_name == "array": + array_base_type = basetype_content.baseType.getcontent() + if array_base_type.getLocalTag() == "derived": + return self.IsLocatableType(array_base_type.getname(), debug) + return True + def IsLocatableType(self, typename, debug = False): - if isinstance(typename, TupleType) or self.GetBlockType(type) is not None: + if isinstance(typename, TupleType) or self.GetBlockType(typename) is not None: return False datatype = self.GetDataType(typename, debug) if datatype is not None: - basetype_content = datatype.baseType.getcontent() - basetype_content_type = basetype_content.getLocalTag() - if basetype_content_type in ["enum", "struct"]: - return False - elif basetype_content_type == "derived": - return self.IsLocatableType(basetype_content.getname()) - elif basetype_content_name == "array": - array_base_type = basetype_content.baseType.getcontent() - if array_base_type.getLocalTag() == "derived": - return self.IsLocatableType(array_base_type.getname(), debug) - + return self.IsLocatableDataType(datatype) return True def IsEnumeratedType(self, typename, debug = False): @@ -2088,7 +2082,6 @@ datatype.initialValue.setvalue(infos["initial"]) else: datatype.initialValue = None - self.Project.RefreshElementUsingTree() self.BufferProject() #------------------------------------------------------------------------------- @@ -2174,7 +2167,6 @@ element = self.GetEditedElement(tagname) if element is not None: element.settext(text) - self.Project.RefreshElementUsingTree() # Return the edited element text def GetEditedElementText(self, tagname, debug = False): @@ -2496,7 +2488,6 @@ block.setinstanceName(blockname) self.AddEditedElementPouVar(tagname, blocktype, blockname) element.addinstance(block) - self.Project.RefreshElementUsingTree() def SetEditedElementBlockInfos(self, tagname, id, infos): element = self.GetEditedElement(tagname) @@ -2563,7 +2554,6 @@ variable.addconnectionPointOut() variable.connectionPointOut.setrelPositionXY(position.x, position.y) block.tostring() - self.Project.RefreshElementUsingTree() def AddEditedElementVariable(self, tagname, id, var_type): element = self.GetEditedElement(tagname) @@ -3042,7 +3032,6 @@ if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")): self.RemoveEditedElementPouVar(tagname, instance.gettypeName(), instance.getinstanceName()) element.removeinstance(id) - self.Project.RefreshElementUsingTree() def GetEditedResourceVariables(self, tagname, debug = False): varlist = [] @@ -3155,8 +3144,6 @@ except Exception, e: return _("Project file syntax error:\n\n") + str(e) self.SetFilePath(filepath) - self.Project.RefreshElementUsingTree() - self.Project.RefreshCustomBlockTypes() ## To remove when project buffering ready self.ProjectBufferEnabled = False diff -r fcca121a000f -r 7856cd7767d6 plcopen/plcopen.py --- a/plcopen/plcopen.py Mon Sep 02 23:46:38 2013 +0200 +++ b/plcopen/plcopen.py Tue Sep 03 23:32:53 2013 +0200 @@ -241,8 +241,6 @@ cls = PLCOpenParser.GetElementClass("project") if cls: - cls.ElementUsingTree = {} - cls.CustomBlockTypes = OrderedDict() def setname(self, name): self.contentHeader.setname(name) @@ -305,10 +303,10 @@ setattr(contentheader_obj, attr, value) setattr(cls, "setcontentHeader", setcontentHeader) - def gettypeElement(self, element_type, name=None): - filter = "[@name='%s']" % name if name is not None else "" - elements = self.xpath("ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s%(filter)s" % locals(), - namespaces=PLCOpenParser.NSMAP) + def gettypeElement(self, element_type, name): + elements = self.xpath( + "ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s[@name='%(name)s']" % locals(), + namespaces=PLCOpenParser.NSMAP) if name is None: return elements elif len(elements) == 1: @@ -316,11 +314,14 @@ return None setattr(cls, "gettypeElement", gettypeElement) - def getdataTypes(self): - return self.getdataType() + def getdataTypes(self, exclude=None): + return self.xpath( + "ppx:types/ppx:dataTypes/ppx:dataType%s" % + ("[@name!='%s']" % exclude if exclude is not None else ""), + namespaces=PLCOpenParser.NSMAP) setattr(cls, "getdataTypes", getdataTypes) - def getdataType(self, name=None): + def getdataType(self, name): return self.gettypeElement("dataType", name) setattr(cls, "getdataType", getdataType) @@ -336,31 +337,32 @@ def removedataType(self, name): self.types.removedataTypeElement(name) - self.RefreshElementUsingTree() setattr(cls, "removedataType", removedataType) - def getpous(self): - return self.getpou() + def getpous(self, exclude=None, filter=None): + return self.xpath( + "ppx:types/ppx:pous/ppx:pou%s%s" % + (("[@name!='%s']" % exclude) if exclude is not None else '', + ("[%s]" % " or ".join( + map(lambda x: "@pouType='%s'" % x, filter))) + if filter is not None else ""), + namespaces=PLCOpenParser.NSMAP) setattr(cls, "getpous", getpous) - def getpou(self, name=None): + def getpou(self, name): return self.gettypeElement("pou", name) setattr(cls, "getpou", getpou) def appendpou(self, name, pou_type, body_type): self.types.appendpouElement(name, pou_type, body_type) - self.AddCustomBlockType(self.getpou(name)) setattr(cls, "appendpou", appendpou) def insertpou(self, index, pou): self.types.insertpouElement(index, pou) - self.AddCustomBlockType(pou) setattr(cls, "insertpou", insertpou) def removepou(self, name): self.types.removepouElement(name) - self.RefreshCustomBlockTypes() - self.RefreshElementUsingTree() setattr(cls, "removepou", removepou) def getconfigurations(self): @@ -458,132 +460,6 @@ configuration.removeVariableByFilter(address_model) setattr(cls, "removeVariableByFilter", removeVariableByFilter) - # Update Block types with user-defined pou added - def RefreshCustomBlockTypes(self): - # Reset the tree of user-defined pou cross-use - self.CustomBlockTypes = OrderedDict() - for pou in self.getpous(): - self.AddCustomBlockType(pou) - setattr(cls, "RefreshCustomBlockTypes", RefreshCustomBlockTypes) - - def AddCustomBlockType(self, pou): - pou_name = pou.getname() - pou_type = pou.getpouType() - block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False, - "inputs" : [], "outputs" : [], "comment" : pou.getdescription(), - "generate" : generate_block, "initialise" : initialise_block} - if pou.interface is not None: - return_type = pou.interface.getreturnType() - if return_type is not None: - var_type = return_type.getcontent() - var_type_name = var_type.getLocalTag() - if var_type_name == "derived": - block_infos["outputs"].append(("OUT", var_type.getname(), "none")) - elif var_type_name in ["string", "wstring"]: - block_infos["outputs"].append(("OUT", var_type_name.upper(), "none")) - else: - block_infos["outputs"].append(("OUT", var_type_name, "none")) - for type, varlist in pou.getvars(): - if type == "InOut": - for var in varlist.getvariable(): - var_type = var.type.getcontent() - var_type_name = var_type.getLocalTag() - if var_type_name == "derived": - block_infos["inputs"].append((var.getname(), var_type.getname(), "none")) - block_infos["outputs"].append((var.getname(), var_type.getname(), "none")) - elif var_type_name in ["string", "wstring"]: - block_infos["inputs"].append((var.getname(), var_type_name.upper(), "none")) - block_infos["outputs"].append((var.getname(), var_type_name.upper(), "none")) - else: - block_infos["inputs"].append((var.getname(), var_type_name, "none")) - block_infos["outputs"].append((var.getname(), var_type_name, "none")) - elif type == "Input": - for var in varlist.getvariable(): - var_type = var.type.getcontent() - var_type_name = var_type.getLocalTag() - if var_type_name == "derived": - block_infos["inputs"].append((var.getname(), var_type.getname(), "none")) - elif var_type_name in ["string", "wstring"]: - block_infos["inputs"].append((var.getname(), var_type_name.upper(), "none")) - else: - block_infos["inputs"].append((var.getname(), var_type_name, "none")) - elif type == "Output": - for var in varlist.getvariable(): - var_type = var.type.getcontent() - var_type_name = var_type.getLocalTag() - if var_type_name == "derived": - block_infos["outputs"].append((var.getname(), var_type.getname(), "none")) - elif var_type_name in ["string", "wstring"]: - block_infos["outputs"].append((var.getname(), var_type_name.upper(), "none")) - else: - block_infos["outputs"].append((var.getname(), var_type_name, "none")) - block_infos["usage"] = "\n (%s) => (%s)" % (", ".join(["%s:%s" % (input[1], input[0]) for input in block_infos["inputs"]]), - ", ".join(["%s:%s" % (output[1], output[0]) for output in block_infos["outputs"]])) - self.CustomBlockTypes[pou_name]=block_infos - setattr(cls, "AddCustomBlockType", AddCustomBlockType) - - def AddElementUsingTreeInstance(self, name, type_infos): - typename = type_infos.getname() - elements = self.ElementUsingTree.setdefault(typename, set()) - elements.add(name) - setattr(cls, "AddElementUsingTreeInstance", AddElementUsingTreeInstance) - - def RefreshElementUsingTree(self): - # Reset the tree of user-defined element cross-use - self.ElementUsingTree = {} - - # Analyze each datatype - for datatype in self.getdataTypes(): - name = datatype.getname() - basetype_content = datatype.baseType.getcontent() - basetype_content_name = basetype_content.getLocalTag() - if basetype_content_name == "derived": - self.AddElementUsingTreeInstance(name, basetype_content) - elif basetype_content_name in ["subrangeSigned", "subrangeUnsigned", "array"]: - base_type = basetype_content.baseType.getcontent() - if base_type.getLocalTag() == "derived": - self.AddElementUsingTreeInstance(name, base_type) - elif basetype_content_name == "struct": - for element in basetype_content.getvariable(): - type_content = element.type.getcontent() - if type_content.getLocalTag() == "derived": - self.AddElementUsingTreeInstance(name, type_content) - - # Analyze each pou - for pou in self.getpous(): - name = pou.getname() - if pou.interface is not None: - # Extract variables from every varLists - for varlist_type, varlist in pou.getvars(): - for var in varlist.getvariable(): - vartype_content = var.gettype().getcontent() - if vartype_content.getLocalTag() == "derived": - self.AddElementUsingTreeInstance(name, vartype_content) - - setattr(cls, "RefreshElementUsingTree", RefreshElementUsingTree) - - # Return if pou given by name is used by another pou - def ElementIsUsed(self, name): - elements = self.ElementUsingTree.get(name, None) - return elements is not None - setattr(cls, "ElementIsUsed", ElementIsUsed) - - # Return if pou given by name is directly or undirectly used by the reference pou - def ElementIsUsedBy(self, name, reference): - elements = self.ElementUsingTree.get(name, set()) - # Test if pou is directly used by reference - if reference in elements: - return True - else: - # Test if pou is undirectly used by reference, by testing if pous - # that directly use pou is directly or undirectly used by reference - selffn = self.ElementIsUsedBy - for element in elements: - if selffn(element, reference): - return True - return False - setattr(cls, "ElementIsUsedBy", ElementIsUsedBy) - def GetEnumeratedDataTypeValues(self): return [ value.getname() @@ -592,60 +468,6 @@ namespaces=PLCOpenParser.NSMAP)] setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues) - # Function that returns the block definition associated to the block type given - def GetCustomBlockType(self, typename, inputs = None): - customblocktype = self.CustomBlockTypes.get(typename,None) - if customblocktype is not None: - if inputs is not None and inputs != "undefined": - customblock_inputs = tuple([var_type for name, var_type, modifier in customblocktype["inputs"]]) - if inputs == customblock_inputs: - return customblocktype - else: - return customblocktype - return None - setattr(cls, "GetCustomBlockType", GetCustomBlockType) - - # Return Block types checking for recursion - def GetCustomBlockTypes(self, exclude = None, onlyfunctions = False): - if exclude is not None: - return [customblocktype for name,customblocktype in self.CustomBlockTypes.iteritems() - if (customblocktype["type"] != "program" - and name != exclude - and not self.ElementIsUsedBy(exclude, name) - and not (onlyfunctions and customblocktype["type"] != "function"))] - return [customblocktype for customblocktype in self.CustomBlockTypes.itervalues() - if (customblocktype["type"] != "program" - and not (onlyfunctions and customblocktype["type"] != "function"))] - setattr(cls, "GetCustomBlockTypes", GetCustomBlockTypes) - - # Return Function Block types checking for recursion - def GetCustomFunctionBlockTypes(self, exclude = None): - if exclude is not None: - return [name for name,customblocktype in self.CustomBlockTypes.iteritems() - if (customblocktype["type"] == "functionBlock" - and name != exclude - and not self.ElementIsUsedBy(exclude, name))] - return [name for customblocktype in self.CustomBlockTypes.itervalues() - if customblocktype["type"] == "functionBlock"] - setattr(cls, "GetCustomFunctionBlockTypes", GetCustomFunctionBlockTypes) - - # Return Block types checking for recursion - def GetCustomBlockResource(self): - return [customblocktype["name"] for customblocktype in self.CustomBlockTypes.itervalues() - if customblocktype["type"] == "program"] - setattr(cls, "GetCustomBlockResource", GetCustomBlockResource) - - # Return Data Types checking for recursion - def GetCustomDataTypes(self, exclude = "", only_locatable = False): - customdatatypes = [] - for customdatatype in self.getdataTypes(): - if not only_locatable or self.IsLocatableType(customdatatype): - customdatatype_name = customdatatype.getname() - if customdatatype_name != exclude and not self.ElementIsUsedBy(exclude, customdatatype_name): - customdatatypes.append({"name": customdatatype_name, "infos": customdatatype}) - return customdatatypes - setattr(cls, "GetCustomDataTypes", GetCustomDataTypes) - def Search(self, criteria, parent_infos=[]): result = self.types.Search(criteria, parent_infos) for configuration in self.instances.configurations.getconfiguration(): @@ -1168,9 +990,50 @@ return search_result setattr(cls, "Search", Search) +def _getvariableTypeinfos(variable_type): + type_content = variable_type.getcontent() + type_content_type = type_content.getLocalTag() + if type_content_type == "derived": + return type_content.getname() + return type_content_type.upper() + cls = PLCOpenParser.GetElementClass("pou", "pous") if cls: + def getblockInfos(self): + block_infos = { + "name" : self.getname(), + "type" : self.getpouType(), + "extensible" : False, + "inputs" : [], + "outputs" : [], + "comment" : self.getdescription(), + "generate" : generate_block, + "initialise" : initialise_block} + if self.interface is not None: + return_type = self.interface.getreturnType() + if return_type is not None: + block_infos["outputs"].append( + ("OUT", _getvariableTypeinfos(return_type), "none")) + for var in self.xpath( + "ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars]/ppx:variable", + namespaces=PLCOpenParser.NSMAP): + block_infos["inputs"].append( + (var.getname(), _getvariableTypeinfos(var.type), "none")) + for var in self.xpath( + "ppx:interface/*[self::ppx:outputVars or self::ppx:inOutVars]/ppx:variable", + namespaces=PLCOpenParser.NSMAP): + block_infos["outputs"].append( + (var.getname(), _getvariableTypeinfos(var.type), "none")) + + block_infos["usage"] = ("\n (%s) => (%s)" % + (", ".join(["%s:%s" % (input[1], input[0]) + for input in block_infos["inputs"]]), + ", ".join(["%s:%s" % (output[1], output[0]) + for output in block_infos["outputs"]]))) + return block_infos + setattr(cls, "getblockInfos", getblockInfos) + def setdescription(self, description): doc = self.getdocumentation() if doc is None: @@ -2333,7 +2196,7 @@ def getBoundingBox(self): bbox = _getBoundingBoxSingle(self) condition_connection = self.getconditionConnection() - if condition_connection: + if condition_connection is not None: bbox.union(_getConnectionsBoundingBox(condition_connection)) return bbox setattr(cls, "getBoundingBox", getBoundingBox)