Initial oftest skeleton with wrapper generators and pylibopenflow
diff --git a/tools/pylibopenflow/pylib/cpythonize.py b/tools/pylibopenflow/pylib/cpythonize.py
new file mode 100644
index 0000000..6a66d7c
--- /dev/null
+++ b/tools/pylibopenflow/pylib/cpythonize.py
@@ -0,0 +1,533 @@
+"""This module generate Python code for C structs.
+
+Date January 2010
+Created by ykk
+"""
+import cheader
+import c2py
+import datetime
+import struct
+import re
+from config import *
+
+def _space_to(n, str):
+ """
+ Generate a string of spaces to achieve width n given string str
+ If length of str >= n, return one space
+ """
+ spaces = n - len(str)
+ if spaces > 0:
+ return " " * spaces
+ return " "
+
+class rules:
+ """Class that specify rules for pythonization
+
+ Date January 2010
+ Created by ykk
+ """
+ def __init__(self):
+ """Initialize rules
+ """
+ ##Default values for members
+ self.default_values = {}
+ #Default values for struct
+ self.struct_default = {}
+ ##What is a tab
+ self.tab = " "
+ ##Macros to exclude
+ self.excluded_macros = []
+ ##Enforce mapping
+ self.enforced_maps = {}
+
+ def get_enforced_map(self, structname):
+ """Get code to enforce mapping
+ """
+ code = []
+ try:
+ mapping = self.enforced_maps[structname]
+ except KeyError:
+ return None
+ for (x,xlist) in mapping:
+ code.append("if (not (self."+x+" in "+xlist+")):")
+ code.append(self.tab+"return (False, \""+x+" must have values from "+xlist+"\")")
+ return code
+
+
+ def get_struct_default(self, structname, fieldname):
+ """Get code to set defaults for member struct
+ """
+ try:
+ return "."+fieldname+self.struct_default[(structname, fieldname)]
+ except KeyError:
+ return None
+
+ def get_default_value(self, structname, fieldname):
+ """Get default value for struct's field
+ """
+ try:
+ return self.default_values[(structname, fieldname)]
+ except KeyError:
+ return 0
+
+ def include_macro(self, name):
+ """Check if macro should be included
+ """
+ return not (name in self.excluded_macros)
+
+class pythonizer:
+ """Class that pythonize C structures
+
+ Date January 2010
+ Created by ykk
+ """
+ def __init__(self, cheaderfile, pyrules = None, tab=" "):
+ """Initialize
+ """
+ ##Rules
+ if (pyrules == None):
+ self.rules = rules()
+ else:
+ self.rules = pyrules
+ ##What is a tab (same as rules)
+ self.tab = str(tab)
+ self.rules.tab = self.tab
+ ##Reference to C header file
+ self.cheader = cheaderfile
+ ##Reference to cstruct2py
+ self.__c2py = c2py.cstruct2py()
+ ##Code for assertion
+ self.__assertcode = []
+
+ def pycode(self,preamble=None):
+ """Return pythonized code
+ """
+ code = []
+ code.append("import struct")
+ code.append("")
+ if (preamble != None):
+ fileRef = open(preamble,"r")
+ for l in fileRef:
+ code.append(l[:-1])
+ fileRef.close()
+ code.append("# Structure definitions")
+ for name,struct in self.cheader.structs.items():
+ code.extend(self.pycode_struct(struct))
+ code.append("")
+ code.append("# Enumerated type definitions")
+ for name,enum in self.cheader.enums.items():
+ code.extend(self.pycode_enum(name,enum))
+ if GEN_ENUM_DICTIONARY:
+ code.extend(self.pycode_enum_map(name,enum))
+ code.append("")
+ code.append("# Values from macro definitions")
+ for name,macro in self.cheader.macros.items():
+ code.extend(self.pycode_macro(name))
+ code.append("")
+ code.append("# Basic structure size definitions.")
+ if IGNORE_OFP_HEADER:
+ code.append("# Does not include ofp_header members.")
+ if IGNORE_ZERO_ARRAYS:
+ code.append("# Does not include variable length arrays.")
+ struct_keys = self.cheader.structs.keys()
+ struct_keys.sort()
+ for name in struct_keys:
+ struct = self.cheader.structs[name]
+ code.append(self.pycode_struct_size(name, struct))
+
+ return code
+
+ def pycode_enum(self, name, enum):
+ """Return Python array for enum
+ """
+ code=[]
+ code.append(name+" = "+str(enum))
+ ev = []
+ for e in enum:
+ v = self.cheader.get_value(e)
+ ev.append(v)
+ code.append(e+"%s= "%_space_to(36,e)+str(v))
+ if GEN_ENUM_VALUES_LIST:
+ code.append(name+"_values = "+str(ev))
+ return code
+
+ def pycode_enum_map(self, name, enum):
+ """Return Python dictionary for enum
+ """
+ code = []
+ code.append(name+"_map = {")
+ first = 1
+ for e in enum:
+ v = self.cheader.get_value(e)
+ if first:
+ prev_e = e
+ prev_v = v
+ first = 0
+ else:
+ code.append(self.tab + "'%s'%s: %s," %
+ (prev_e, _space_to(30, prev_e), prev_v))
+ prev_e = e
+ prev_v = v
+ code.append(self.tab + "'%s'%s: %s" %
+ (prev_e, _space_to(30, prev_e), prev_v))
+ code.append("}")
+ return code
+
+ def pycode_macro(self,name):
+ """Return Python dict for macro
+ """
+ code = []
+ if (self.rules.include_macro(name)):
+ code.append(name+" = "+str(self.cheader.get_value(name)))
+ return code
+
+ def pycode_struct_size(self, name, struct):
+ """Return one liner giving the structure size in bytes
+ """
+ pattern = '!' + self.__c2py.get_pattern(struct)
+ bytes = self.__c2py.get_size(pattern)
+ code = name.upper() + "_BYTES = " + str(bytes)
+ return code
+
+ def pycode_struct(self, struct_in):
+ """Return Python class code given C struct.
+
+ Returns None if struct_in is not cheader.cstruct.
+ Else return list of strings that codes Python class.
+ """
+ if (not isinstance(struct_in, cheader.cstruct)):
+ return None
+
+ code=[]
+ self.__assertcode = []
+ code.extend(self.codeheader(struct_in))
+ code.extend(self.codeinit(struct_in))
+ code.append("")
+ code.extend(self.codeassert(struct_in))
+ code.append("")
+ code.extend(self.codepack(struct_in))
+ code.append("")
+ code.extend(self.codeunpack(struct_in))
+ code.append("")
+ code.extend(self.codelen(struct_in))
+ code.append("")
+ if GEN_OBJ_EQUALITY:
+ code.extend(self.codeeq(struct_in))
+ code.append("")
+ if GEN_OBJ_SHOW:
+ code.extend(self.codeshow(struct_in))
+ code.append("")
+ return code
+
+ def codeheader(self, struct_in):
+ """Return Python code for header
+ """
+ code=[]
+ code.append("class "+struct_in.typename+":")
+ code.append(self.tab+"\"\"\"Automatically generated Python class for "+struct_in.typename)
+ code.append("")
+ code.append(self.tab+"Date "+str(datetime.date.today()))
+ code.append(self.tab+"Created by "+self.__module__+"."+self.__class__.__name__)
+ if IGNORE_OFP_HEADER:
+ code.append(self.tab+"Core structure: Messages do not include ofp_header")
+ if IGNORE_ZERO_ARRAYS:
+ code.append(self.tab+"Does not include var-length arrays")
+ code.append(self.tab+"\"\"\"")
+ return code
+
+ def codeinit(self, struct_in):
+ """Return Python code for init function
+ """
+ code = []
+ code.append(self.tab+"def __init__(self):")
+ code.append(self.tab*2+"\"\"\"Initialize")
+ code.append(self.tab*2+"Declare members and default values")
+ code.append(self.tab*2+"\"\"\"")
+ code.extend(self.codemembers(struct_in,self.tab*2+"self"))
+ return code
+
+ def codemembers(self, struct_in, prepend=""):
+ """Return members of class
+ """
+ code = []
+ for member in struct_in.members:
+ if (isinstance(member, cheader.cstruct)):
+ code.append(prepend+"."+member.name+" = "+member.typename+"()")
+ struct_default = self.rules.get_struct_default(struct_in.typename, member.name)
+ if (struct_default != None):
+ code.append(prepend+struct_default)
+ self.__structassert(member, (prepend+"."+member.name).strip())
+ elif (isinstance(member, cheader.carray)):
+ if (member.typename == "char"):
+ initvalue = "\"\""
+ self.__stringassert(member, (prepend+"."+member.name).strip())
+ else:
+ if (isinstance(member.object, cheader.cprimitive)):
+ initvalue="0"
+ else:
+ initvalue="None"
+ initvalue=(initvalue+",")*member.size
+ initvalue="["+initvalue[:-1]+"]"
+ self.__arrayassert(member, (prepend+"."+member.name).strip())
+ code.append(prepend+"."+member.name+"= "+initvalue)
+ else:
+ code.append(prepend+"."+member.name+" = "+
+ str(self.rules.get_default_value(struct_in.typename, member.name)))
+ return code
+
+ def __structassert(self, cstruct, cstructname):
+ """Return code to check for C array
+ """
+ self.__assertcode.append(self.tab*2+"if(not isinstance("+cstructname+", "+cstruct.typename+")):")
+ self.__assertcode.append(self.tab*3+"return (False, \""+cstructname+" is not class "+cstruct.typename+" as expected.\")")
+
+ def __addassert(self, prefix):
+ code = []
+ code.append(prefix+"if(not self.__assert()[0]):")
+ code.append(prefix+self.tab+"return None")
+ return code
+
+ def __stringassert(self, carray, carrayname):
+ """Return code to check for C array
+ """
+ self.__assertcode.append(self.tab*2+"if(not isinstance("+carrayname+", str)):")
+ self.__assertcode.append(self.tab*3+"return (False, \""+carrayname+" is not string as expected.\")")
+ self.__assertcode.append(self.tab*2+"if(len("+carrayname+") > "+str(carray.size)+"):")
+ self.__assertcode.append(self.tab*3+"return (False, \""+carrayname+" is not of size "+str(carray.size)+" as expected.\")")
+
+ def __arrayassert(self, carray, carrayname):
+ """Return code to check for C array
+ """
+ if (carray.size == 0):
+ return
+ self.__assertcode.append(self.tab*2+"if(not isinstance("+carrayname+", list)):")
+ self.__assertcode.append(self.tab*3+"return (False, \""+carrayname+" is not list as expected.\")")
+ self.__assertcode.append(self.tab*2+"if(len("+carrayname+") != "+str(carray.size)+"):")
+ self.__assertcode.append(self.tab*3+"return (False, \""+carrayname+" is not of size "+str(carray.size)+" as expected.\")")
+
+ def codeassert(self, struct_in):
+ """Return code for sanity checking
+ """
+ code = []
+ code.append(self.tab+"def __assert(self):")
+ code.append(self.tab*2+"\"\"\"Sanity check")
+ code.append(self.tab*2+"\"\"\"")
+ enforce = self.rules.get_enforced_map(struct_in.typename)
+ if (enforce != None):
+ for line in enforce:
+ code.append(self.tab*2+line)
+ code.extend(self.__assertcode)
+ code.append(self.tab*2+"return (True, None)")
+ return code
+
+ def codepack(self, struct_in, prefix="!"):
+ """Return code that pack struct
+ """
+ code = []
+ code.append(self.tab+"def pack(self, assertstruct=True):")
+ code.append(self.tab*2+"\"\"\"Pack message")
+ code.append(self.tab*2+"Packs empty array used as placeholder")
+ code.append(self.tab*2+"\"\"\"")
+ code.append(self.tab*2+"if(assertstruct):")
+ code.extend(self.__addassert(self.tab*3))
+ code.append(self.tab*2+"packed = \"\"")
+ primPattern = ""
+ primMemberNames = []
+ for member in struct_in.members:
+ if (isinstance(member, cheader.cprimitive)):
+ #Primitives
+ primPattern += self.__c2py.structmap[member.typename]
+ primMemberNames.append("self."+member.name)
+ else:
+ (primPattern, primMemberNames) = \
+ self.__codepackprimitive(code, primPattern,
+ primMemberNames, prefix)
+ if (isinstance(member, cheader.cstruct)):
+ #Struct
+ code.append(self.tab*2+"packed += self."+member.name+".pack()")
+ elif (isinstance(member, cheader.carray) and member.typename == "char"):
+ #String
+ code.append(self.tab*2+"packed += self."+member.name+".ljust("+\
+ str(member.size)+",'\\0')")
+ elif (isinstance(member, cheader.carray) and \
+ isinstance(member.object, cheader.cprimitive)):
+ #Array of Primitives
+ expandedarr = ""
+ if (member.size != 0):
+ for x in range(0, member.size):
+ expandedarr += ", self."+member.name+"["+\
+ str(x).strip()+"]"
+ code.append(self.tab*2+"packed += struct.pack(\""+prefix+\
+ self.__c2py.structmap[member.object.typename]*member.size+\
+ "\""+expandedarr+")")
+ else:
+ code.append(self.tab*2+"for i in self."+member.name+":")
+ code.append(self.tab*3+"packed += struct.pack(\""+\
+ prefix+self.__c2py.get_pattern(member.object)+\
+ "\",i)")
+ elif (isinstance(member, cheader.carray) and \
+ isinstance(member.object, cheader.cstruct)):
+ #Array of struct
+ if (member.size != 0):
+ for x in range(0, member.size):
+ code.append(self.tab*2+"packed += self."+member.name+"["+\
+ str(x).strip()+"].pack()")
+ else:
+ code.append(self.tab*2+"for i in self."+member.name+":")
+ code.append(self.tab*3+"packed += i.pack(assertstruct)")
+ #Clear remaining fields
+ (primPattern, primMemberNames) = \
+ self.__codepackprimitive(code, primPattern,
+ primMemberNames, prefix)
+ code.append(self.tab*2+"return packed")
+ return code
+
+ def __codepackprimitive(self, code, primPattern, primMemberNames, prefix):
+ """Return code for packing primitives
+ """
+ if (primPattern != ""):
+ #Clear prior primitives
+ code.append(self.tab*2+"packed += struct.pack(\""+\
+ prefix+primPattern+"\", "+\
+ str(primMemberNames).replace("'","")[1:-1]+")")
+ return ("",[])
+
+ def codelen(self, struct_in):
+ """Return code to return length
+ """
+ pattern = "!" + self.__c2py.get_pattern(struct_in)
+ code = []
+ code.append(self.tab+"def __len__(self):")
+ code.append(self.tab*2+"\"\"\"Return length of message")
+ code.append(self.tab*2+"\"\"\"")
+ code.append(self.tab*2+"l = "+str(self.__c2py.get_size(pattern)))
+ for member in struct_in.members:
+ if (isinstance(member, cheader.carray) and member.size == 0):
+ if (isinstance(member.object, cheader.cstruct)):
+ code.append(self.tab*2+"for i in self."+member.name+":")
+ code.append(self.tab*3+"l += i.length()")
+ else:
+ pattern="!"+self.__c2py.get_pattern(member.object)
+ size=self.__c2py.get_size(pattern)
+ code.append(self.tab*2+"l += len(self."+member.name+")*"+str(size))
+ code.append(self.tab*2+"return l")
+ return code
+
+ def codeeq(self, struct_in):
+ """Return code to return equality comparisons
+ """
+ code = []
+ code.append(self.tab+"def __eq__(self, other):")
+ code.append(self.tab*2+"\"\"\"Return True if self and other have same values")
+ code.append(self.tab*2+"\"\"\"")
+ code.append(self.tab*2+"if type(self) != type(other): return False")
+ for member in struct_in.members:
+ code.append(self.tab*2 + "if self." + member.name + " != other." +
+ member.name + ": return False")
+ code.append(self.tab*2+"return True")
+ code.append("")
+ code.append(self.tab+"def __ne__(self, other): return not self.__eq__(other)")
+ return code
+
+ def codeshow(self, struct_in):
+ """Return code to print basic members of structure
+ """
+ code = []
+ code.append(self.tab+"def show(self, prefix=''):")
+ code.append(self.tab*2+"\"\"\"" + "Print basic members of structure")
+ code.append(self.tab*2+"\"\"\"")
+ for member in struct_in.members:
+ if re.search('pad', member.name):
+ continue
+ elif (isinstance(member, cheader.cstruct)):
+ code.append(self.tab*2 + "print prefix + '" +
+ member.name + ": ' ")
+ code.append(self.tab*2 + "self." + member.name +
+ ".show(prefix + ' ')")
+ elif (isinstance(member, cheader.carray) and
+ not isinstance(member.object, cheader.cprimitive)):
+ code.append(self.tab*2 + "print prefix + '" + member.name +
+ ": ' ")
+ code.append(self.tab*2 + "for obj in self." + member.name + ":")
+ code.append(self.tab*3 + "obj.show(prefix + ' ')")
+ else:
+ code.append(self.tab*2 + "print prefix + '" + member.name +
+ ": ' + str(self." + member.name + ")")
+ return code
+
+ def codeunpack(self, struct_in, prefix="!"):
+ """Return code that unpack struct
+ """
+ pattern = self.__c2py.get_pattern(struct_in)
+ structlen = self.__c2py.get_size(prefix + pattern)
+ code = []
+ code.append(self.tab+"def unpack(self, binaryString):")
+ code.append(self.tab*2+"\"\"\"Unpack message")
+ code.append(self.tab*2+"Do not unpack empty array used as placeholder")
+ code.append(self.tab*2+"since they can contain heterogeneous type")
+ code.append(self.tab*2+"\"\"\"")
+ code.append(self.tab*2+"if (len(binaryString) < "+str(structlen)+"):")
+ code.append(self.tab*3+"return binaryString")
+ offset = 0
+ primPattern = ""
+ primMemberNames = []
+ for member in struct_in.members:
+ if (isinstance(member, cheader.cprimitive)):
+ #Primitives
+ primPattern += self.__c2py.structmap[member.typename]
+ primMemberNames.append("self."+member.name)
+ else:
+ (primPattern, primMemberNames, offset) = \
+ self.__codeunpackprimitive(code, offset, primPattern,
+ primMemberNames, prefix)
+ if (isinstance(member, cheader.cstruct)):
+ #Struct
+ code.append(self.tab*2+"self."+member.name+\
+ ".unpack(binaryString["+str(offset)+":])")
+ pattern = self.__c2py.get_pattern(member)
+ offset += self.__c2py.get_size(prefix+pattern)
+ elif (isinstance(member, cheader.carray) and member.typename == "char"):
+ #String
+ code.append(self.tab*2+"self."+member.name+\
+ " = binaryString["+str(offset)+":"+\
+ str(offset+member.size)+"].replace(\"\\0\",\"\")")
+ offset += member.size
+ elif (isinstance(member, cheader.carray) and \
+ isinstance(member.object, cheader.cprimitive)):
+ #Array of Primitives
+ expandedarr = ""
+ if (member.size != 0):
+ arrpattern = self.__c2py.structmap[member.object.typename]*member.size
+ for x in range(0, member.size):
+ expandedarr += "self."+member.name+"["+\
+ str(x).strip()+"], "
+ code.append(self.tab*2+"("+expandedarr[:-2]+") = struct.unpack_from(\""+\
+ prefix+arrpattern+\
+ "\", binaryString, "+str(offset)+")")
+ offset += struct.calcsize(prefix + arrpattern)
+ elif (isinstance(member, cheader.carray) and \
+ isinstance(member.object, cheader.cstruct)):
+ #Array of struct
+ astructlen = self.__c2py.get_size("!"+self.__c2py.get_pattern(member.object))
+ for x in range(0, member.size):
+ code.append(self.tab*2+"self."+member.name+"["+str(x)+"]"+\
+ ".unpack(binaryString["+str(offset)+":])")
+ offset += astructlen
+ #Clear remaining fields
+ (primPattern, primMemberNames, offset) = \
+ self.__codeunpackprimitive(code, offset, primPattern,
+ primMemberNames, prefix)
+ code.append(self.tab*2+"return binaryString["+str(structlen)+":]");
+ return code
+
+ def __codeunpackprimitive(self, code, offset, primPattern,
+ primMemberNames, prefix):
+ """Return code for unpacking primitives
+ """
+ if (primPattern != ""):
+ #Clear prior primitives
+ code.append(self.tab*2+"("+str(primMemberNames).replace("'","")[1:-1]+\
+ ") = struct.unpack_from(\""+\
+ prefix+primPattern+"\", binaryString, "+str(offset)+")")
+ return ("",[], offset+struct.calcsize(prefix+primPattern))
+