lbessard@2: #!/usr/bin/env python lbessard@2: # -*- coding: utf-8 -*- lbessard@2: lbessard@2: #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor lbessard@2: #based on the plcopen standard. lbessard@2: # lbessard@58: #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD lbessard@2: # lbessard@2: #See COPYING file for copyrights details. lbessard@2: # lbessard@2: #This library is free software; you can redistribute it and/or lbessard@2: #modify it under the terms of the GNU General Public lbessard@2: #License as published by the Free Software Foundation; either lbessard@2: #version 2.1 of the License, or (at your option) any later version. lbessard@2: # lbessard@2: #This library is distributed in the hope that it will be useful, lbessard@2: #but WITHOUT ANY WARRANTY; without even the implied warranty of lbessard@2: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU lbessard@58: #General Public License for more details. lbessard@2: # lbessard@2: #You should have received a copy of the GNU General Public lbessard@2: #License along with this library; if not, write to the Free Software lbessard@2: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA lbessard@2: lbessard@2: from xml.dom import minidom lbessard@2: import sys,re lbessard@2: from types import * lbessard@2: from datetime import * lbessard@2: lbessard@2: """ lbessard@2: Time and date definitions lbessard@2: """ lbessard@2: TimeType = time(0,0,0).__class__ lbessard@2: DateType = date(1,1,1).__class__ lbessard@2: DateTimeType = datetime(1,1,1,0,0,0).__class__ lbessard@2: lbessard@2: """ lbessard@2: Regular expression models for extracting dates and times from a string lbessard@2: """ lbessard@24: time_model = re.compile('([0-9]{2}):([0-9]{2}):([0-9]{2}(?:.[0-9]*)?)') lbessard@2: date_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})') lbessard@24: datetime_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})[ T]([0-9]{2}):([0-9]{2}):([0-9]{2}(?:.[0-9]*)?)') lbessard@2: lbessard@2: """ lbessard@2: Dictionaries for stocking Classes and Types created from XML lbessard@2: """ lbessard@2: XMLClasses = {} lbessard@2: lbessard@2: """ lbessard@2: This function calculates the number of whitespace for indentation lbessard@2: """ lbessard@2: def getIndent(indent, balise): lbessard@2: first = indent * 2 lbessard@2: second = first + len(balise) + 1 lbessard@2: return "\t".expandtabs(first), "\t".expandtabs(second) lbessard@2: lbessard@2: """ lbessard@2: This function opens the xsd file and generate the classes from the xml tree lbessard@2: """ lbessard@2: def GenerateClassesFromXSD(filename): lbessard@2: xsdfile = open(filename, 'r') lbessard@2: Generate_xsd_classes(minidom.parse(xsdfile), None) lbessard@2: xsdfile.close() lbessard@2: lbessard@2: """ lbessard@2: This function recursively creates a definition of the classes and their attributes lbessard@2: for plcopen from the xsd file of plcopen opened in a DOM model lbessard@2: """ lbessard@2: def Generate_xsd_classes(tree, parent, sequence = False): lbessard@2: attributes = {} lbessard@2: inheritance = [] lbessard@2: if sequence: lbessard@2: order = [] lbessard@2: # The lists of attributes and inheritance of the node are generated from the childrens lbessard@2: for node in tree.childNodes: lbessard@2: # We make fun of #text elements and all other tags that don't are xsd tags lbessard@2: if node.nodeName != "#text" and node.nodeName.startswith("xsd:"): lbessard@2: recursion = False lbessard@2: name = node.nodeName[4:].encode() lbessard@2: lbessard@2: # This tags defines an attribute of the class lbessard@2: if name in ["element", "attribute"]: lbessard@2: nodename = GetAttributeValue(node._attrs["name"]) lbessard@2: if "type" in node._attrs: lbessard@2: nodetype = GetAttributeValue(node._attrs["type"]) lbessard@2: if nodetype.startswith("xsd"): lbessard@2: nodetype = nodetype.replace("xsd", "bse") lbessard@2: elif nodetype.startswith("ppx"): lbessard@2: nodetype = nodetype.replace("ppx", "cls") lbessard@2: else: lbessard@2: # The type of attribute is defines in the child tree so we generate a new class lbessard@2: # No name is defined so we create one from nodename and parent class name lbessard@2: # (because some different nodes can have the same name) lbessard@2: if parent: lbessard@2: classname = "%s_%s"%(parent, nodename) lbessard@2: else: lbessard@2: classname = nodename lbessard@2: Generate_xsd_classes(node, classname) lbessard@2: nodetype = "cls:%s"%classname lbessard@2: if name == "attribute": lbessard@2: if "use" in node._attrs: lbessard@2: use = GetAttributeValue(node._attrs["use"]) lbessard@2: else: lbessard@2: use = "optional" lbessard@2: if name == "element": lbessard@2: # If a tag can be written more than one time we define a list attribute lbessard@2: if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": lbessard@2: nodetype = "%s[]"%nodetype lbessard@2: if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": lbessard@2: use = "optional" lbessard@2: else: lbessard@2: use = "required" lbessard@2: attributes[nodename] = (nodetype, name, use) lbessard@2: if sequence: lbessard@2: order.append(nodename) lbessard@2: lbessard@2: # This tag defines a new class lbessard@2: elif name == "complexType" or name == "simpleType": lbessard@2: if "name" in node._attrs: lbessard@2: classname = GetAttributeValue(node._attrs["name"]) lbessard@2: super, attrs = Generate_xsd_classes(node, classname) lbessard@2: else: lbessard@2: classname = parent lbessard@2: super, attrs = Generate_xsd_classes(node, classname.split("_")[-1]) lbessard@2: # When all attributes and inheritances have been extracted, the lbessard@2: # values are added in the list of classes to create lbessard@2: if classname not in XMLClasses: lbessard@2: XMLClasses[classname] = (super, attrs) lbessard@2: elif XMLClasses[classname] != (super, attrs): lbessard@2: print "A different class has already got %s for name"%classname lbessard@2: lbessard@2: # This tag defines an attribute that can have different types lbessard@2: elif name == "choice": lbessard@2: super, attrs = Generate_xsd_classes(node, parent) lbessard@2: if "ref" in attrs.keys(): lbessard@2: choices = attrs lbessard@2: else: lbessard@2: choices = {} lbessard@2: for attr, (attr_type, xml_type, write_type) in attrs.items(): lbessard@2: choices[attr] = attr_type lbessard@2: if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": lbessard@2: attributes["multichoice_content"] = choices lbessard@2: if sequence: lbessard@2: order.append("multichoice_content") lbessard@2: else: lbessard@2: attributes["choice_content"] = choices lbessard@2: if sequence: lbessard@2: order.append("choice_content") lbessard@2: lbessard@2: # This tag defines the order in which class attributes must be written lbessard@2: # in plcopen xml file. We have to store this order like an attribute lbessard@2: elif name in "sequence": lbessard@2: super, attrs, order = Generate_xsd_classes(node, parent, True) lbessard@2: if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": lbessard@2: for attr, (attr_type, xml_type, write_type) in attrs.items(): lbessard@2: attrs[attr] = ("%s[]"%attr_type, xml_type, write_type) lbessard@2: if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": lbessard@2: for attr, (attr_type, xml_type, write_type) in attrs.items(): lbessard@2: attrs[attr] = (attr_type, xml_type, "optional") lbessard@2: inheritance.extend(super) lbessard@2: attributes.update(attrs) lbessard@2: attributes["order"] = order lbessard@2: lbessard@2: # This tag defines of types lbessard@2: elif name == "group": lbessard@2: if "name" in node._attrs: lbessard@2: nodename = GetAttributeValue(node._attrs["name"]) lbessard@2: super, attrs = Generate_xsd_classes(node, None) lbessard@2: XMLClasses[nodename] = (super, {"group":attrs["choice_content"]}) lbessard@2: elif "ref" in node._attrs: lbessard@2: if "ref" not in attributes: lbessard@2: attributes["ref"] = [GetAttributeValue(node._attrs["ref"])] lbessard@2: else: lbessard@2: attributes["ref"].append(GetAttributeValue(node._attrs["ref"])) lbessard@2: lbessard@2: # This tag define a base class for the node lbessard@2: elif name == "extension": lbessard@2: super = GetAttributeValue(node._attrs["base"]) lbessard@2: if super.startswith("xsd"): lbessard@2: super = super.replace("xsd", "bse") lbessard@2: elif super.startswith("ppx"): lbessard@2: super = super.replace("ppx", "cls") lbessard@2: inheritance.append(super[4:]) lbessard@2: recursion = True lbessard@2: lbessard@2: # This tag defines a restriction on the type of attribute lbessard@2: elif name == "restriction": lbessard@2: basetype = GetAttributeValue(node._attrs["base"]) lbessard@2: if basetype.startswith("xsd"): lbessard@2: basetype = basetype.replace("xsd", "bse") lbessard@2: elif basetype.startswith("ppx"): lbessard@2: basetype = basetype.replace("ppx", "cls") lbessard@2: attributes["basetype"] = basetype lbessard@2: recursion = True lbessard@2: lbessard@2: # This tag defines an enumerated type lbessard@2: elif name == "enumeration": lbessard@2: if "enum" not in attributes: lbessard@2: attributes["enum"] = [GetAttributeValue(node._attrs["value"])] lbessard@2: else: lbessard@2: attributes["enum"].append(GetAttributeValue(node._attrs["value"])) lbessard@2: lbessard@2: # This tags defines a restriction on a numerical value lbessard@2: elif name in ["minInclusive","maxInclusive"]: lbessard@2: if "limit" not in attributes: lbessard@2: attributes["limit"] = {} lbessard@2: if name == "minInclusive": lbessard@2: attributes["limit"]["min"] = eval(GetAttributeValue(node._attrs["value"])) lbessard@2: elif name == "maxInclusive": lbessard@2: attributes["limit"]["max"] = eval(GetAttributeValue(node._attrs["value"])) lbessard@2: lbessard@2: # This tag are not important but their childrens are. The childrens are then parsed. lbessard@2: elif name in ["complexContent", "schema"]: lbessard@2: recursion = True lbessard@2: lbessard@2: # We make fun of xsd documentation lbessard@2: elif name in ["annotation"]: lbessard@2: pass lbessard@2: lbessard@2: else: lbessard@2: #print name lbessard@2: Generate_xsd_classes(node, parent) lbessard@2: lbessard@2: # Parse the childrens of node lbessard@2: if recursion: lbessard@2: super, attrs = Generate_xsd_classes(node, parent) lbessard@2: inheritance.extend(super) lbessard@2: attributes.update(attrs) lbessard@2: lbessard@2: # if sequence tag have been found, order is returned lbessard@2: if sequence: lbessard@2: return inheritance, attributes, order lbessard@2: else: lbessard@2: return inheritance, attributes lbessard@2: """ lbessard@2: Function that extracts data from a node lbessard@2: """ lbessard@2: def GetAttributeValue(attr): lbessard@2: if len(attr.childNodes) == 1: lbessard@2: return attr.childNodes[0].data.encode() lbessard@2: else: lbessard@67: text = "" lbessard@67: for node in attr.childNodes: lbessard@67: if node.nodeName != "#text": lbessard@67: text += node.data.encode() lbessard@67: return text lbessard@2: lbessard@2: """ lbessard@2: Funtion that returns the Python type and default value for a given type lbessard@2: """ lbessard@2: def GetTypeInitialValue(attr_type): lbessard@2: type_compute = attr_type[4:].replace("[]", "") lbessard@2: if attr_type.startswith("bse:"): lbessard@2: if type_compute == "boolean": lbessard@2: return BooleanType, "False" lbessard@2: elif type_compute in ["decimal","unsignedLong","long","integer"]: lbessard@2: return IntType, "0" lbessard@2: elif type_compute in ["string","anyURI","NMTOKEN"]: lbessard@2: return StringType, "\"\"" lbessard@2: elif type_compute == "time": lbessard@24: return TimeType, "time(0,0,0,0)" lbessard@2: elif type_compute == "date": lbessard@2: return DateType, "date(1,1,1)" lbessard@2: elif type_compute == "dateTime": lbessard@24: return DateTimeType, "datetime(1,1,1,0,0,0,0)" lbessard@2: elif type_compute == "language": lbessard@2: return StringType, "\"en-US\"" lbessard@2: else: lbessard@2: print "Can't affect: %s"%type_compute lbessard@2: elif attr_type.startswith("cls:"): lbessard@2: if type_compute in XMLClasses: lbessard@2: return XMLClasses[type_compute],"%s()"%type_compute lbessard@2: lbessard@2: """ lbessard@2: Function that computes value from a python type (Only Boolean are critical because lbessard@2: there is no uppercase in plcopen) lbessard@2: """ lbessard@2: def ComputeValue(value): lbessard@2: if type(value) == BooleanType: lbessard@2: if value: lbessard@2: return "true" lbessard@2: else: lbessard@2: return "false" lbessard@2: else: lbessard@2: return str(value) lbessard@2: lbessard@2: """ lbessard@2: Function that extracts a value from a string following the xsd type given lbessard@2: """ lbessard@2: def GetComputedValue(attr_type, value): lbessard@2: type_compute = attr_type[4:].replace("[]", "") lbessard@2: if type_compute == "boolean": lbessard@2: if value == "true": lbessard@2: return True lbessard@2: elif value == "false": lbessard@2: return False lbessard@2: else: lbessard@2: raise ValueError, "\"%s\" is not a valid boolean!"%value lbessard@2: elif type_compute in ["decimal","unsignedLong","long","integer"]: lbessard@2: return int(value) lbessard@2: elif type_compute in ["string","anyURI","NMTOKEN","language"]: lbessard@2: return value lbessard@2: elif type_compute == "time": lbessard@2: result = time_model.match(value) lbessard@2: if result: lbessard@24: values = result.groups() lbessard@24: time_values = [int(v) for v in values[:2]] lbessard@24: seconds = float(values[2]) lbessard@24: time_values.extend([int(seconds), int((seconds % 1) * 1000000)]) lbessard@2: return time(*time_values) lbessard@2: else: lbessard@2: raise ValueError, "\"%s\" is not a valid time!"%value lbessard@2: elif type_compute == "date": lbessard@2: result = date_model.match(value) lbessard@2: if result: lbessard@2: date_values = [int(v) for v in result.groups()] lbessard@2: return date(*date_values) lbessard@2: else: lbessard@2: raise ValueError, "\"%s\" is not a valid date!"%value lbessard@2: elif type_compute == "dateTime": lbessard@2: result = datetime_model.match(value) lbessard@2: if result: lbessard@24: values = result.groups() lbessard@24: datetime_values = [int(v) for v in values[:5]] lbessard@24: seconds = float(values[5]) lbessard@24: datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)]) lbessard@2: return datetime(*datetime_values) lbessard@2: else: lbessard@2: raise ValueError, "\"%s\" is not a valid datetime!"%value lbessard@2: else: lbessard@2: print "Can't affect: %s"%type_compute lbessard@2: return None lbessard@2: lbessard@2: """ lbessard@2: This is the Metaclass for PLCOpen element classes. It generates automatically lbessard@2: the basic useful methods for manipulate the differents attributes of the classes lbessard@2: """ lbessard@2: class MetaClass(type): lbessard@2: lbessard@2: def __init__(cls, name, bases, dict, user_classes): lbessard@2: super(MetaClass, cls).__init__(name, bases, {}) lbessard@2: #print name, bases, dict, "\n" lbessard@2: initialValues = {} lbessard@2: for attr, values in dict.items(): lbessard@2: if attr in ["order", "basetype"]: lbessard@2: pass lbessard@2: lbessard@2: # Class is a enumerated type lbessard@2: elif attr == "enum": lbessard@2: value_type, initial = GetTypeInitialValue(dict["basetype"]) lbessard@2: initialValues["value"] = "\"%s\""%values[0] lbessard@2: setattr(cls, "value", values[0]) lbessard@2: setattr(cls, "setValue", MetaClass.generateSetEnumMethod(cls, values, value_type)) lbessard@2: setattr(cls, "getValue", MetaClass.generateGetMethod(cls, "value")) lbessard@2: lbessard@2: # Class is a limited type lbessard@2: elif attr == "limit": lbessard@2: value_type, initial = GetTypeInitialValue(dict["basetype"]) lbessard@2: initial = 0 lbessard@2: if "min" in values: lbessard@2: initial = max(initial, values["min"]) lbessard@2: if "max" in values: lbessard@2: initial = min(initial, values["max"]) lbessard@2: initialValues["value"] = "%d"%initial lbessard@2: setattr(cls, "value", initial) lbessard@2: setattr(cls, "setValue", MetaClass.generateSetLimitMethod(cls, values, value_type)) lbessard@2: setattr(cls, "getValue", MetaClass.generateGetMethod(cls, "value")) lbessard@2: lbessard@2: # Class has an attribute that can have different value types lbessard@2: elif attr == "choice_content": lbessard@2: setattr(cls, "content", None) lbessard@2: initialValues["content"] = "None" lbessard@2: setattr(cls, "deleteContent", MetaClass.generateDeleteMethod(cls, "content")) lbessard@2: setattr(cls, "setContent", MetaClass.generateSetChoiceMethod(cls, values)) lbessard@2: setattr(cls, "getContent", MetaClass.generateGetMethod(cls, "content")) lbessard@2: elif attr == "multichoice_content": lbessard@2: setattr(cls, "content", []) lbessard@2: initialValues["content"] = "[]" lbessard@2: setattr(cls, "appendContent", MetaClass.generateAppendChoiceMethod(cls, values)) lbessard@2: setattr(cls, "insertContent", MetaClass.generateInsertChoiceMethod(cls, values)) lbessard@2: setattr(cls, "removeContent", MetaClass.generateRemoveMethod(cls, "content")) lbessard@2: setattr(cls, "countContent", MetaClass.generateCountMethod(cls, "content")) lbessard@2: setattr(cls, "setContent", MetaClass.generateSetMethod(cls, "content", ListType)) lbessard@2: setattr(cls, "getContent", MetaClass.generateGetMethod(cls, "content")) lbessard@2: lbessard@2: # It's an attribute of the class lbessard@2: else: lbessard@2: attrname = attr[0].upper()+attr[1:] lbessard@2: attr_type, xml_type, write_type = values lbessard@2: value_type, initial = GetTypeInitialValue(attr_type) lbessard@2: # Value of the attribute is a list lbessard@2: if attr_type.endswith("[]"): lbessard@2: setattr(cls, attr, []) lbessard@2: initialValues[attr] = "[]" lbessard@2: setattr(cls, "append"+attrname, MetaClass.generateAppendMethod(cls, attr, value_type)) lbessard@2: setattr(cls, "insert"+attrname, MetaClass.generateInsertMethod(cls, attr, value_type)) lbessard@2: setattr(cls, "remove"+attrname, MetaClass.generateRemoveMethod(cls, attr)) lbessard@2: setattr(cls, "count"+attrname, MetaClass.generateCountMethod(cls, attr)) lbessard@2: setattr(cls, "set"+attrname, MetaClass.generateSetMethod(cls, attr, ListType)) lbessard@2: else: lbessard@2: if write_type == "optional": lbessard@2: setattr(cls, attr, None) lbessard@2: initialValues[attr] = "None" lbessard@2: setattr(cls, "add"+attrname, MetaClass.generateAddMethod(cls, attr, initial, user_classes)) lbessard@2: setattr(cls, "delete"+attrname, MetaClass.generateDeleteMethod(cls, attr)) lbessard@2: else: lbessard@2: setattr(cls, attr, initial) lbessard@2: initialValues[attr] = initial lbessard@2: setattr(cls, "set"+attrname, MetaClass.generateSetMethod(cls, attr, value_type)) lbessard@2: setattr(cls, "get"+attrname, MetaClass.generateGetMethod(cls, attr)) lbessard@2: setattr(cls, "__init__", MetaClass.generateInitMethod(cls, bases, initialValues, user_classes)) lbessard@2: setattr(cls, "loadXMLTree", MetaClass.generateLoadXMLTree(cls, bases, dict, user_classes)) lbessard@2: setattr(cls, "generateXMLText", MetaClass.generateGenerateXMLText(cls, bases, dict)) lbessard@2: setattr(cls, "singleLineAttributes", True) lbessard@2: lbessard@2: """ lbessard@2: Method that generate the method for loading an xml tree by following the lbessard@2: attributes list defined lbessard@2: """ lbessard@2: def generateLoadXMLTree(cls, bases, dict, user_classes): lbessard@2: def loadXMLTreeMethod(self, tree): lbessard@2: # If class is derived, values of inheritance classes are loaded lbessard@2: for base in bases: lbessard@2: base.loadXMLTree(self, tree) lbessard@2: # Class is a enumerated or limited value lbessard@2: if "enum" in dict.keys() or "limit" in dict.keys(): lbessard@2: attr_value = GetAttributeValue(tree) lbessard@2: attr_type = dict["basetype"] lbessard@2: val = GetComputedValue(attr_type, attr_value) lbessard@2: self.setValue(val) lbessard@2: else: lbessard@2: lbessard@2: # Load the node attributes if they are defined in the list lbessard@2: for attrname, attr in tree._attrs.items(): lbessard@2: if attrname in dict.keys(): lbessard@2: attr_type, xml_type, write_type = dict[attrname] lbessard@2: attr_value = GetAttributeValue(attr) lbessard@2: if write_type != "optional" or attr_value != "": lbessard@2: # Extracts the value lbessard@2: if attr_type.startswith("bse:"): lbessard@2: val = GetComputedValue(attr_type, attr_value) lbessard@2: elif attr_type.startswith("cls:"): lbessard@2: val = eval("%s()"%attr_type[4:], globals().update(user_classes)) lbessard@2: val.loadXMLTree(attr) lbessard@2: setattr(self, attrname, val) lbessard@2: lbessard@2: # Load the node childs if they are defined in the list lbessard@2: for node in tree.childNodes: lbessard@2: name = node.nodeName lbessard@2: # We make fun of #text elements lbessard@2: if name != "#text": lbessard@2: lbessard@2: # Class has an attribute that can have different value types lbessard@2: if "choice_content" in dict.keys() and name in dict["choice_content"].keys(): lbessard@2: attr_type = dict["choice_content"][name] lbessard@2: # Extracts the value lbessard@2: if attr_type.startswith("bse:"): lbessard@2: attr_value = GetAttributeValue(node) lbessard@2: if write_type != "optional" or attr_value != "": lbessard@2: val = GetComputedValue(attr_type.replace("[]",""), attr_value) lbessard@2: else: lbessard@2: val = None lbessard@2: elif attr_type.startswith("cls:"): lbessard@2: val = eval("%s()"%attr_type[4:].replace("[]",""), globals().update(user_classes)) lbessard@2: val.loadXMLTree(node) lbessard@2: # Stock value in content attribute lbessard@2: if val: lbessard@2: if attr_type.endswith("[]"): lbessard@2: if self.content: lbessard@2: self.content["value"].append(val) lbessard@2: else: lbessard@2: self.content = {"name":name,"value":[val]} lbessard@2: else: lbessard@2: self.content = {"name":name,"value":val} lbessard@2: lbessard@2: # Class has a list of attributes that can have different value types lbessard@2: elif "multichoice_content" in dict.keys() and name in dict["multichoice_content"].keys(): lbessard@2: attr_type = dict["multichoice_content"][name] lbessard@2: # Extracts the value lbessard@2: if attr_type.startswith("bse:"): lbessard@2: attr_value = GetAttributeValue(node) lbessard@2: if write_type != "optional" or attr_value != "": lbessard@2: val = GetComputedValue(attr_type, attr_value) lbessard@2: else: lbessard@2: val = None lbessard@2: elif attr_type.startswith("cls:"): lbessard@2: val = eval("%s()"%attr_type[4:], globals().update(user_classes)) lbessard@2: val.loadXMLTree(node) lbessard@2: # Add to content attribute list lbessard@2: if val: lbessard@2: self.content.append({"name":name,"value":val}) lbessard@2: lbessard@2: # The node child is defined in the list lbessard@2: elif name in dict.keys(): lbessard@2: attr_type, xml_type, write_type = dict[name] lbessard@2: # Extracts the value lbessard@2: if attr_type.startswith("bse:"): lbessard@2: attr_value = GetAttributeValue(node) lbessard@2: if write_type != "optional" or attr_value != "": lbessard@2: val = GetComputedValue(attr_type.replace("[]",""), attr_value) lbessard@2: else: lbessard@2: val = None lbessard@2: elif attr_type.startswith("cls:"): lbessard@2: val = eval("%s()"%attr_type[4:].replace("[]",""), globals().update(user_classes)) lbessard@2: val.loadXMLTree(node) lbessard@2: # Stock value in attribute lbessard@2: if val: lbessard@2: if attr_type.endswith("[]"): lbessard@2: getattr(self, name).append(val) lbessard@2: else: lbessard@2: setattr(self, name, val) lbessard@2: return loadXMLTreeMethod lbessard@2: lbessard@2: """ lbessard@2: Method that generates the method for generating an xml text by following the lbessard@2: attributes list defined lbessard@2: """ lbessard@2: def generateGenerateXMLText(cls, bases, dict): lbessard@2: def generateXMLTextMethod(self, name, indent, extras = {}, derived = False): lbessard@2: ind1, ind2 = getIndent(indent, name) lbessard@2: if not derived: lbessard@2: text = ind1 + "<%s"%name lbessard@2: else: lbessard@2: text = "" lbessard@2: if len(bases) > 0: lbessard@2: base_extras = {} lbessard@2: if "order" in dict.keys(): lbessard@2: order = dict["order"] lbessard@2: else: lbessard@2: order = [] lbessard@2: if "choice_content" in dict.keys() and "choice_content" not in order: lbessard@2: order.append("choice_content") lbessard@2: if "multichoice_content" in dict.keys() and "multichoice_content" not in order: lbessard@2: order.append("multichoice_content") lbessard@2: size = 0 lbessard@2: first = True lbessard@2: for attr, value in extras.items(): lbessard@2: if not first and not self.singleLineAttributes: lbessard@2: text += "\n%s"%(ind2) lbessard@2: text += " %s=\"%s\""%(attr, ComputeValue(value)) lbessard@2: first = False lbessard@2: for attr, values in dict.items(): lbessard@2: if attr in ["order","choice_content","multichoice_content"]: lbessard@2: pass lbessard@2: elif attr in ["enum","limit"]: lbessard@2: if not derived: lbessard@2: text += ">%s\n"%(ComputeValue(self.value),name) lbessard@2: else: lbessard@2: text += ComputeValue(self.value) lbessard@2: return text lbessard@2: elif values[1] == "attribute": lbessard@2: value = getattr(self, attr, None) lbessard@2: if values[2] != "optional" or value != None: lbessard@2: if not first and not self.singleLineAttributes: lbessard@2: text += "\n%s"%(ind2) lbessard@2: if values[0].startswith("cls"): lbessard@2: if len(bases) > 0: lbessard@2: base_extras[attr] = value.getValue() lbessard@2: else: lbessard@2: text += " %s=\"%s\""%(attr, ComputeValue(value.getValue())) lbessard@2: else: lbessard@2: if len(bases) > 0: lbessard@2: base_extras[attr] = value lbessard@2: else: lbessard@2: text += " %s=\"%s\""%(attr, ComputeValue(value)) lbessard@2: first = False lbessard@2: if len(bases) > 0: lbessard@2: first, new_text = bases[0].generateXMLText(self, name, indent, base_extras, True) lbessard@2: text += new_text lbessard@2: else: lbessard@2: first = True lbessard@2: ind3, ind4 = getIndent(indent + 1, name) lbessard@2: for attr in order: lbessard@2: value = getattr(self, attr, None) lbessard@2: if attr == "choice_content": lbessard@2: if self.content: lbessard@2: if first: lbessard@2: text += ">\n" lbessard@2: first = False lbessard@2: value_type = dict[attr][self.content["name"]] lbessard@2: if value_type.startswith("bse:"): lbessard@2: if value_type.endswith("[]"): lbessard@2: for content in self.content["value"]: lbessard@2: text += ind1 + "<%s>%s\n"%(self.content["name"], ComputeValue(content), self.content["name"]) lbessard@2: else: lbessard@2: text += ind1 + "<%s>%s\n"%(self.content["name"], ComputeValue(self.content["value"]), self.content["name"]) lbessard@2: elif value_type.endswith("[]"): lbessard@2: for content in self.content["value"]: lbessard@2: text += content.generateXMLText(self.content["name"], indent + 1) lbessard@2: else: lbessard@2: text += self.content["value"].generateXMLText(self.content["name"], indent + 1) lbessard@2: elif attr == "multichoice_content": lbessard@2: if len(self.content) > 0: lbessard@2: for element in self.content: lbessard@2: if first: lbessard@2: text += ">\n" lbessard@2: first = False lbessard@2: value_type = dict[attr][element["name"]] lbessard@2: if value_type.startswith("bse:"): lbessard@2: text += ind1 + "<%s>%s\n"%(element["name"], ComputeValue(element["value"]), element["name"]) lbessard@2: else: lbessard@2: text += element["value"].generateXMLText(element["name"], indent + 1) lbessard@2: elif dict[attr][2] != "optional" or value != None: lbessard@2: if dict[attr][0].endswith("[]"): lbessard@2: if first and len(value) > 0: lbessard@2: text += ">\n" lbessard@2: first = False lbessard@2: for element in value: lbessard@2: if dict[attr][0].startswith("bse:"): lbessard@2: text += ind3 + "<%s>%s\n"%(attr, ComputeValue(element), attr) lbessard@2: else: lbessard@2: text += element.generateXMLText(attr, indent + 1) lbessard@2: else: lbessard@2: if first: lbessard@2: text += ">\n" lbessard@2: first = False lbessard@2: if dict[attr][0].startswith("bse:"): lbessard@2: text += ind3 + "<%s>%s\n"%(attr, ComputeValue(value), attr) lbessard@2: else: lbessard@2: text += getattr(self, attr).generateXMLText(attr, indent + 1) lbessard@2: if not derived: lbessard@2: if first: lbessard@2: text += "/>\n" lbessard@2: else: lbessard@2: text += ind1 + "\n"%(name) lbessard@2: return text lbessard@2: else: lbessard@2: return first, text lbessard@2: return generateXMLTextMethod lbessard@2: lbessard@2: """ lbessard@2: Methods that generates the different methods for setting and getting the attributes lbessard@2: """ lbessard@2: lbessard@2: def generateInitMethod(cls, bases, dict, user_classes): lbessard@2: def initMethod(self): lbessard@2: for base in bases: lbessard@2: base.__init__(self) lbessard@2: for attr, initial in dict.items(): lbessard@2: setattr(self, attr, eval(initial, globals().update(user_classes))) lbessard@2: return initMethod lbessard@2: lbessard@2: def generateSetMethod(cls, attr, choice_type): lbessard@2: def setMethod(self, value): lbessard@2: setattr(self, attr, value) lbessard@2: return setMethod lbessard@2: lbessard@2: def generateSetChoiceMethod(cls, attr_type): lbessard@2: def setChoiceMethod(self, name, value): lbessard@2: self.content = {"name":name,"value":value} lbessard@2: return setChoiceMethod lbessard@2: lbessard@2: def generateSetEnumMethod(cls, enum, attr_type): lbessard@2: def setEnumMethod(self, value): lbessard@2: if value in enum: lbessard@2: self.value = value lbessard@2: else: lbessard@2: raise ValueError, "%s is not a valid value. Must be in %s"%(value, str(enum)) lbessard@2: return setEnumMethod lbessard@2: lbessard@2: def generateSetLimitMethod(cls, limit, attr_type): lbessard@2: def setMethod(self, value): lbessard@2: if "min" in limit and value < limit["min"]: lbessard@2: raise ValueError, "%s is not a valid value. Must be greater than %d"%(value, limit["min"]) lbessard@2: elif "max" in limit and value > limit["max"]: lbessard@2: raise ValueError, "%s is not a valid value. Must be smaller than %d"%(value, limit["max"]) lbessard@2: else: lbessard@2: self.value = value lbessard@2: return setMethod lbessard@2: lbessard@2: def generateGetMethod(cls, attr): lbessard@2: def getMethod(self): lbessard@2: return getattr(self, attr, None) lbessard@2: return getMethod lbessard@2: lbessard@2: def generateAddMethod(cls, attr, initial, user_classes): lbessard@2: def addMethod(self): lbessard@2: setattr(self, attr, eval(initial, globals().update(user_classes))) lbessard@2: return addMethod lbessard@2: lbessard@2: def generateDeleteMethod(cls, attr): lbessard@2: def deleteMethod(self): lbessard@2: setattr(self, attr, None) lbessard@2: return deleteMethod lbessard@2: lbessard@2: def generateAppendMethod(cls, attr, attr_type): lbessard@2: def appendMethod(self, value): lbessard@2: getattr(self, attr).append(value) lbessard@2: return appendMethod lbessard@2: lbessard@2: def generateInsertMethod(cls, attr, attr_type): lbessard@2: def insertMethod(self, index, value): lbessard@2: getattr(self, attr).insert(index, value) lbessard@2: return insertMethod lbessard@2: lbessard@2: def generateAppendChoiceMethod(cls, choice_types): lbessard@2: def appendMethod(self, name, value): lbessard@2: self.content.append({"name":name,"value":value}) lbessard@2: return appendMethod lbessard@2: lbessard@2: def generateInsertChoiceMethod(cls, choice_types): lbessard@2: def insertMethod(self, index, name, value): lbessard@2: self.content.insert(index, {"name":name,"value":value}) lbessard@2: return insertMethod lbessard@2: lbessard@2: def generateRemoveMethod(cls, attr): lbessard@2: def removeMethod(self, index): lbessard@2: getattr(self, attr).pop(index) lbessard@2: return removeMethod lbessard@2: lbessard@2: def generateCountMethod(cls, attr): lbessard@2: def countMethod(self): lbessard@2: return len(getattr(self, attr)) lbessard@2: return countMethod lbessard@2: lbessard@2: """ lbessard@2: Methods that generate the classes lbessard@2: """ lbessard@2: def CreateClasses(user_classes, user_types): lbessard@2: for classname in XMLClasses.keys(): lbessard@2: CreateClass(classname, user_classes, user_types) lbessard@2: lbessard@2: def CreateClass(classname, user_classes, user_types): lbessard@2: # Checks that classe haven't been generated yet lbessard@2: if classname not in user_classes and classname not in user_types and classname in XMLClasses: lbessard@2: inheritance, attributes = XMLClasses[classname] lbessard@2: #print classe, inheritance, attributes lbessard@2: dict = {} lbessard@2: bases = [] lbessard@2: lbessard@2: # If inheritance classes haven't been generated lbessard@2: for base in inheritance: lbessard@2: if base not in user_classes: lbessard@2: CreateClass(base, user_classes, user_types) lbessard@2: bases.append(user_classes[base]) lbessard@2: lbessard@2: # Checks that all attribute types are available lbessard@2: for attribute, type_attribute in attributes.items(): lbessard@2: if attribute == "group": lbessard@2: user_types[classname] = type_attribute lbessard@2: elif attribute == "ref": lbessard@2: user_types[classname] = {} lbessard@2: for attr in type_attribute: lbessard@2: if attr[4:] not in user_types: lbessard@2: CreateClass(attr[4:], user_classes, user_types) lbessard@2: user_types[classname].update(user_types[attr[4:]]) lbessard@2: elif attribute in ["choice_content","multichoice_content"]: lbessard@2: element_types = {} lbessard@2: for attr, value in type_attribute.items(): lbessard@2: if attr == "ref": lbessard@2: for ref in type_attribute["ref"]: lbessard@2: if ref[4:] not in user_types: lbessard@2: CreateClass(ref[4:], user_classes, user_types) lbessard@2: element_types.update(user_types[ref[4:]]) lbessard@2: else: lbessard@2: element_types[attr] = value lbessard@2: dict[attribute] = element_types lbessard@2: else: lbessard@2: dict[attribute] = type_attribute lbessard@2: if attribute == "enum": lbessard@2: user_types["%s_enum"%classname] = type_attribute lbessard@2: elif attribute not in ["limit", "order"]: lbessard@2: if type_attribute[0].startswith("ppx:"): lbessard@2: type_compute = type_attribute[0][4:].replace("[]","") lbessard@2: if type_compute not in user_classes: lbessard@2: CreateClass(type_compute, user_classes, user_types) lbessard@2: if "group" not in attributes.keys() and "ref" not in attributes.keys(): lbessard@2: cls = MetaClass.__new__(MetaClass, classname, tuple(bases), dict) lbessard@2: MetaClass.__init__(cls, classname, tuple(bases), dict, user_classes) lbessard@2: user_classes[classname] = cls lbessard@2: lbessard@2: """ lbessard@2: Methods that print the classes generated lbessard@2: """ lbessard@2: def PrintClasses(): lbessard@2: for classname, xmlclass in XMLClasses.items(): lbessard@2: print "%s : %s\n"%(classname, str(xmlclass)) lbessard@2: lbessard@2: def PrintClassNames(): lbessard@2: classnames = XMLClasses.keys() lbessard@2: classnames.sort() lbessard@2: for classname in classnames: lbessard@2: print classname