# HG changeset patch # User lbessard # Date 1188565745 -7200 # Node ID 180e4a0160b253487b1e78275b2560a06db977d0 # Parent 119b62c73085b43ce7d70e6926b1994b158e18a6 Adding support for default values diff -r 119b62c73085 -r 180e4a0160b2 xmlclass/xmlclass.py --- a/xmlclass/xmlclass.py Fri Aug 31 15:08:11 2007 +0200 +++ b/xmlclass/xmlclass.py Fri Aug 31 15:09:05 2007 +0200 @@ -88,8 +88,10 @@ return False else: raise ValueError, "\"%s\" is not a valid boolean!"%value - elif type_compute in ["decimal","unsignedLong","long","integer"]: + elif type_compute in ["unsignedLong","long","integer"]: return int(value) + elif type_compute == "decimal": + return float(value) elif type_compute in ["string","anyURI","NMTOKEN","language"]: return value elif type_compute == "time": @@ -123,6 +125,11 @@ print "Can't affect: %s"%type_compute return None +def GetInitialValueFunction(value): + def GetInitialValue(): + return value + return GetInitialValue + """ Class that generate class from an XML Tree """ @@ -158,6 +165,7 @@ # This tags defines an attribute of the class if name in ["element", "attribute"]: nodename = GetAttributeValue(node._attrs["name"]) + default = None if "type" in node._attrs: nodetype = GetAttributeValue(node._attrs["type"]) if nodetype.startswith("xsd"): @@ -179,7 +187,9 @@ use = GetAttributeValue(node._attrs["use"]) else: use = "optional" - if name == "element": + if "default" in node._attrs: + default = GetAttributeValue(node._attrs["default"]) + elif name == "element": # If a tag can be written more than one time we define a list attribute if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": nodetype = "%s[]"%nodetype @@ -187,7 +197,7 @@ use = "optional" else: use = "required" - attributes[nodename] = (nodetype, name, use) + attributes[nodename] = (nodetype, name, use, default) if sequence: order.append(nodename) @@ -214,7 +224,7 @@ choices = attrs else: choices = {} - for attr, (attr_type, xml_type, write_type) in attrs.items(): + for attr, (attr_type, xml_type, write_type, default) in attrs.items(): choices[attr] = attr_type if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": attributes["multichoice_content"] = choices @@ -230,11 +240,11 @@ elif name in "sequence": super, attrs, order = self.GenerateXSDClasses(node, parent, True) if "maxOccurs" in node._attrs and GetAttributeValue(node._attrs["maxOccurs"]) == "unbounded": - for attr, (attr_type, xml_type, write_type) in attrs.items(): - attrs[attr] = ("%s[]"%attr_type, xml_type, write_type) + for attr, (attr_type, xml_type, write_type, default) in attrs.items(): + attrs[attr] = ("%s[]"%attr_type, xml_type, write_type, default) if "minOccurs" in node._attrs and GetAttributeValue(node._attrs["minOccurs"]) == "0": - for attr, (attr_type, xml_type, write_type) in attrs.items(): - attrs[attr] = (attr_type, xml_type, "optional") + for attr, (attr_type, xml_type, write_type, default) in attrs.items(): + attrs[attr] = (attr_type, xml_type, "optional", default) inheritance.extend(super) attributes.update(attrs) attributes["order"] = order @@ -315,28 +325,107 @@ """ Funtion that returns the Python type and default value for a given type """ - def GetTypeInitialValue(self, attr_type): + def GetTypeInitialValue(self, attr_type, default = None): type_compute = attr_type[4:].replace("[]", "") if attr_type.startswith("bse:"): if type_compute == "boolean": - return BooleanType, "False" - elif type_compute in ["decimal","unsignedLong","long","integer"]: - return IntType, "0" + if default: + def GetBooleanInitialValue(): + return default == "true" + return BooleanType, GetBooleanInitialValue + else: + return BooleanType, lambda:False + elif type_compute in ["unsignedLong","long","integer"]: + if default: + def GetIntegerInitialValue(): + return int(default) + return IntType, GetIntegerInitialValue + else: + return IntType, lambda:0 + elif type_compute == "decimal": + if default: + def GetFloatInitialValue(): + return float(default) + return FloatType, GetFloatInitialValue + else: + return FloatType, lambda:0. elif type_compute in ["string","anyURI","NMTOKEN"]: - return StringType, "\"\"" + if default: + def GetStringInitialValue(): + return default + return StringType, GetStringInitialValue + else: + return StringType, lambda:"" elif type_compute == "time": - return TimeType, "time(0,0,0,0)" + if default: + def GetTimeInitialValue(): + result = time_model.match(value) + if result: + values = result.groups() + time_values = [int(v) for v in values[:2]] + seconds = float(values[2]) + time_values.extend([int(seconds), int((seconds % 1) * 1000000)]) + return time(*time_values) + return time(0,0,0,0) + return TimeType, GetTimeInitialValue + else: + return TimeType, lambda:time(0,0,0,0) elif type_compute == "date": - return DateType, "date(1,1,1)" + if default: + def GetDateInitialValue(): + result = date_model.match(value) + if result: + date_values = [int(v) for v in result.groups()] + return date(*date_values) + return date(1,1,1) + return DateType, GetDateInitialValue + else: + return DateType, lambda:date(1,1,1) elif type_compute == "dateTime": - return DateTimeType, "datetime(1,1,1,0,0,0,0)" + if default: + def GetDateTimeInitialValue(): + result = datetime_model.match(value) + if result: + values = result.groups() + datetime_values = [int(v) for v in values[:5]] + seconds = float(values[5]) + datetime_values.extend([int(seconds), int((seconds % 1) * 1000000)]) + return datetime(*datetime_values) + return datetime(1,1,1,0,0,0,0) + return DateTimeType, GetDateTimeInitialValue + else: + return DateTimeType, lambda:datetime(1,1,1,0,0,0,0) elif type_compute == "language": - return StringType, "\"en-US\"" + if default: + def GetStringInitialValue(): + return default + return StringType, GetStringInitialValue + else: + return StringType, lambda:"en-US" else: print "Can't affect: %s"%type_compute elif attr_type.startswith("cls:"): if self.XMLClassDefinitions.get(type_compute, None) != None: - return self.XMLClassDefinitions[type_compute],"%s()"%type_compute + def GetClassInitialValue(): + if self.XMLClassDefinitions.get(type_compute, None) != None: + obj = self.ComputedClasses[type_compute]() + if default: + obj.setValue(default) + return obj + return None + return self.XMLClassDefinitions[type_compute], GetClassInitialValue + return None, lambda:None + + """ + Funtion that returns the Python type and default value for a given type + """ + def GetInitialValues(self, value_types): + initial_values = {} + for name, value_type in value_types.items(): + result = self.GetTypeInitialValue(value_type) + if result: + initial_values[name] = result[1] + return initial_values """ Methods that generate the classes @@ -396,20 +485,20 @@ # Class is a enumerated type elif attr == "enum": value_type, initial = self.GetTypeInitialValue(members["basetype"]) - initialValues["value"] = "\"%s\""%values[0] + initialValues["value"] = GetInitialValueFunction(values[0]) classmembers["value"] = values[0] classmembers["setValue"] = generateSetEnumMethod(values, value_type) classmembers["getValue"] = generateGetMethod("value") + classmembers["getValidValues"] = generateGetChoicesMethod(values) # Class is a limited type elif attr == "limit": value_type, initial = self.GetTypeInitialValue(members["basetype"]) - initial = 0 if "min" in values: initial = max(initial, values["min"]) if "max" in values: initial = min(initial, values["max"]) - initialValues["value"] = "%d"%initial + initialValues["value"] = GetInitialValueFunction(initial) classmembers["value"] = initial classmembers["setValue"] = generateSetLimitMethod(values, value_type) classmembers["getValue"] = generateGetMethod("value") @@ -417,29 +506,33 @@ # Class has an attribute that can have different value types elif attr == "choice_content": classmembers["content"] = None - initialValues["content"] = "None" + initialValues["content"] = lambda:None classmembers["deleteContent"] = generateDeleteMethod("content") + classmembers["addContent"] = generateAddChoiceMethod(values, self.GetInitialValues(values)) classmembers["setContent"] = generateSetChoiceMethod(values) classmembers["getContent"] = generateGetMethod("content") + classmembers["getChoices"] = generateGetChoicesMethod(values) elif attr == "multichoice_content": classmembers["content"] = [] - initialValues["content"] = "[]" + initialValues["content"] = lambda:[] classmembers["appendContent"] = generateAppendChoiceMethod(values) + classmembers["appendContentByType"] = generateAppendChoiceByTypeMethod(values, self.GetInitialValues(values)) classmembers["insertContent"] = generateInsertChoiceMethod(values) classmembers["removeContent"] = generateRemoveMethod("content") classmembers["countContent"] = generateCountMethod("content") classmembers["setContent"] = generateSetMethod("content", ListType) classmembers["getContent"] = generateGetMethod("content") + classmembers["getChoices"] = generateGetChoicesMethod(values) # It's an attribute of the class else: attrname = attr[0].upper()+attr[1:] - attr_type, xml_type, write_type = values - value_type, initial = self.GetTypeInitialValue(attr_type) + attr_type, xml_type, write_type, default = values + value_type, initial = self.GetTypeInitialValue(attr_type, default) # Value of the attribute is a list if attr_type.endswith("[]"): classmembers[attr] = [] - initialValues[attr] = "[]" + initialValues[attr] = lambda:[] classmembers["append"+attrname] = generateAppendMethod(attr, value_type) classmembers["insert"+attrname] = generateInsertMethod(attr, value_type) classmembers["remove"+attrname] = generateRemoveMethod(attr) @@ -448,18 +541,18 @@ else: if write_type == "optional": classmembers[attr] = None - initialValues[attr] = "None" - classmembers["add"+attrname] = generateAddMethod(attr, initial, self.ComputedClasses) + initialValues[attr] = lambda:None + classmembers["add"+attrname] = generateAddMethod(attr, initial) classmembers["delete"+attrname] = generateDeleteMethod(attr) else: - classmembers[attr] = initial + classmembers[attr] = initial() initialValues[attr] = initial classmembers["set"+attrname] = generateSetMethod(attr, value_type) classmembers["get"+attrname] = generateGetMethod(attr) - classmembers["__init__"] = generateInitMethod(bases, initialValues, self.ComputedClasses) + classmembers["__init__"] = generateInitMethod(bases, initialValues) classmembers["loadXMLTree"] = generateLoadXMLTree(bases, members, self.ComputedClasses) classmembers["generateXMLText"] = generateGenerateXMLText(bases, members) - classmembers["getElementAttributes"] = generategetElementAttributes(bases, members) + classmembers["getElementAttributes"] = generateGetElementAttributes(bases, members, self.ComputedClasses) classmembers["singleLineAttributes"] = True self.ComputedClasses[classname] = classobj(classname, bases, classmembers) @@ -528,7 +621,7 @@ # Load the node attributes if they are defined in the list for attrname, attr in tree._attrs.items(): if attrname in members.keys(): - attr_type, xml_type, write_type = members[attrname] + attr_type, xml_type, write_type, default = members[attrname] attr_value = GetAttributeValue(attr) if write_type != "optional" or attr_value != "": # Extracts the value @@ -587,7 +680,7 @@ # The node child is defined in the list elif name in members.keys(): - attr_type, xml_type, write_type = members[name] + attr_type, xml_type, write_type, default = members[name] # Extracts the value if attr_type.startswith("bse:"): attr_value = GetAttributeValue(node) @@ -623,10 +716,10 @@ order = members["order"] else: order = [] - if "choice_content" in members.keys() and "choice_content" not in order: - order.append("choice_content") - if "multichoice_content" in members.keys() and "multichoice_content" not in order: - order.append("multichoice_content") + for attr, values in members.items(): + if attr != "order" and (attr in ("choice_content", "multichoice_content") or values[1] != "attribute"): + if attr not in order: + order.append(attr) size = 0 first = True for attr, value in extras.items(): @@ -645,21 +738,16 @@ return text elif values[1] == "attribute": value = getattr(self, attr, None) - if value == "": - value = None - if values[2] != "optional" or value != None: - if not first and not self.singleLineAttributes: - text += "\n%s"%(ind2) - if values[0].startswith("cls"): - if len(bases) > 0: - base_extras[attr] = value.getValue() - else: - text += " %s=\"%s\""%(attr, ComputeValue(value.getValue())) + if values[0].startswith("cls"): + value = value.getValue() + computed_value = ComputeValue(value) + if values[2] != "optional" or value != computed_value: + if len(bases) > 0: + base_extras[attr] = value else: - if len(bases) > 0: - base_extras[attr] = value - else: - text += " %s=\"%s\""%(attr, ComputeValue(value)) + if not first and not self.singleLineAttributes: + text += "\n%s"%(ind2) + text += " %s=\"%s\""%(attr, computed_value) first = False if len(bases) > 0: first, new_text = bases[0].generateXMLText(self, name, indent, base_extras, True) @@ -726,31 +814,37 @@ return generateXMLTextMethod -def generategetElementAttributes(bases, members): +def generateGetElementAttributes(bases, members, classes): def getElementAttributes(self): attr_list = [] for attr, values in members.items(): if attr in ["order","choice_content","multichoice_content"]: pass elif values[1] == "attribute": - if values[2] == "required": - require = True - else: - require = False - attr_hash ={"name": attr,"type": values[0] ,"value": getattr(self, attr, "") ,"require": require} - attr_list.append(attr_hash) + attr_params = {"name": attr, "require": values[2] == "required"} + if values[0].startswith("cls:"): + attr_value = getattr(self, attr, None) + if attr_value: + attr_params["value"] = attr_value.getValue() + else: + attr_params["value"] = "" + attr_params["type"] = classes[values[0][4:]]().getValidValues() + else: + attr_params["value"] = getattr(self, attr, "") + attr_params["type"] = values[0][4:] + attr_list.append(attr_params) return attr_list return getElementAttributes """ Methods that generates the different methods for setting and getting the attributes """ -def generateInitMethod(bases, members, classes): +def generateInitMethod(bases, members): def initMethod(self): for base in bases: base.__init__(self) for attr, initial in members.items(): - setattr(self, attr, eval(initial, globals().update(classes))) + setattr(self, attr, initial()) return initMethod def generateSetMethod(attr, attr_type): @@ -758,11 +852,22 @@ setattr(self, attr, value) return setMethod +def generateAddChoiceMethod(choice_type, initial_values): + def addChoiceMethod(self, name): + if name in choice_type: + self.content = {"name" : name, "value" : initial_values[name]()} + return addChoiceMethod + def generateSetChoiceMethod(choice_type): def setChoiceMethod(self, name, value): - self.content = {"name":name,"value":value} + self.content = {"name" : name, "value" : value} return setChoiceMethod +def generateGetChoicesMethod(choice_type): + def getChoicesMethod(self): + return choice_type + return getChoicesMethod + def generateSetEnumMethod(enum, attr_type): def setEnumMethod(self, value): if value in enum: @@ -786,9 +891,9 @@ return getattr(self, attr, None) return getMethod -def generateAddMethod(attr, initial, classes): +def generateAddMethod(attr, initial): def addMethod(self): - setattr(self, attr, eval(initial, globals().update(classes))) + setattr(self, attr, initial()) return addMethod def generateDeleteMethod(attr): @@ -806,6 +911,12 @@ getattr(self, attr).insert(index, value) return insertMethod +def generateAppendChoiceByTypeMethod(choice_type, initial_values): + def addChoiceMethod(self, name): + if name in choice_type: + self.content.append({"name" : name, "value" : initial_values[name]()}) + return addChoiceMethod + def generateAppendChoiceMethod(choice_types): def appendMethod(self, name, value): self.content.append({"name":name,"value":value}) @@ -836,6 +947,7 @@ sys._getframe(1).f_locals[ClassName] = Class for TypeName, Type in pluginTypes.items(): sys._getframe(1).f_locals[TypeName] = Type + globals().update(ComputedClasses) return ComputedClasses, ComputedTypes """ @@ -854,4 +966,3 @@ factory = ClassFactory(minidom.parseString(xsdstring)) return GenerateClasses(factory, declare) -