* birtakim duzeltmeler (saka canim)

* autoxml'de muhtelif duzeltmeler
* toplam code size'ini azaltip, list type'ini encode disinda
  implement et. sira class type'inda
* run.py'de pisi.api'i init et, ne bileyim iste.
* code'u yazan biziz calistiran da biz olacagiz
This commit is contained in:
Eray Özkural
2005-09-21 22:46:55 +00:00
parent fd4138ff5e
commit 3f2febb2a3
3 changed files with 144 additions and 108 deletions
+136 -106
View File
@@ -143,7 +143,7 @@ class autoxml(type):
class Company: class Company:
__metaclass__ = autoxml __metaclass__ = autoxml
t_Employees = [ Employee, xmlfile.mandatory] t_Employees = [ [Employee], xmlfile.mandatory]
Logically, inside the Company tag, we will have several Employee Logically, inside the Company tag, we will have several Employee
tags, which are inserted to the Employees instance variable of tags, which are inserted to the Employees instance variable of
@@ -154,7 +154,7 @@ class autoxml(type):
It is also possible to change the XML path we expect the tag in, It is also possible to change the XML path we expect the tag in,
just like with any other tag. just like with any other tag.
t_Employees = [ Employee, xmlfile.mandatory, 'Employees/Employee'] t_Employees = [ [Employee], xmlfile.mandatory, 'Employees/Employee']
You see, it works like magic, when it works of course. All of it You see, it works like magic, when it works of course. All of it
@@ -175,12 +175,11 @@ class autoxml(type):
#TODO: initialize class attribute __xml_tags #TODO: initialize class attribute __xml_tags
#setattr(cls, 'xml_variables', []) #setattr(cls, 'xml_variables', [])
if not dict.has_key('tag'): # default class tag is class name
setattr(cls, 'tag', name) if not dict.has_key('tag'):
cls.tag = name
root_tag = cls.tag # generate helper routines, for each XML component
# generate helper routines
inits = [] inits = []
decoders = [] decoders = []
encoders = [] encoders = []
@@ -188,177 +187,208 @@ class autoxml(type):
for var in dict: for var in dict:
if var.startswith('t_') or var.startswith('a_'): if var.startswith('t_') or var.startswith('a_'):
name = var[2:] name = var[2:]
#print 'name', name print 'generating member', name
if var.startswith('t_'): if var.startswith('a_'):
x = autoxml.gen_tag(cls, name) x = autoxml.gen_attr_member(cls, name)
elif var.startswith('a_'): elif var.startswith('t_'):
x = autoxml.gen_attr(cls, name) x = autoxml.gen_tag_member(cls, name)
ctx.ui.debug(x)
(init, decoder, encoder, formatter) = x (init, decoder, encoder, formatter) = x
inits.append(init) inits.append(init)
decoders.append(decoder) decoders.append(decoder)
encoders.append(encoder) encoders.append(encoder)
formatters.append(formatter) formatters.append(formatter)
varname = cls.mixed_case(name) # generate top-level helper functions
cls.initializers = inits
setattr(cls, 'initializers', inits)
def initialize(self): def initialize(self):
for init in self.__class__.initializers: for init in self.__class__.initializers:
init(self) init(self)
setattr(cls, '__init__', initialize) cls.__init__ = initialize
setattr(cls, 'decoders', decoders) cls.decoders = decoders
def decode(self, node): def decode(self, node):
for decoder in self.__class__.decoders: for decoder in self.__class__.decoders:
setattr(self, varname, decoder(self, node)) decoder(self, node)
setattr(cls, 'decode', decode) cls.decode = decode
setattr(cls, 'encoders', encoders) cls.encoders = encoders
def encode(self, xml): def encode(self, xml):
for encoder in self.__class__.encoders: for encoder in self.__class__.encoders:
encoder(self, xml, getattr(self, varname)) encoder(self, xml)
setattr(cls, 'encode', encode) cls.encode = encode
setattr(cls, 'formatters', formatters) cls.formatters = formatters
def format(self): def format(self):
string = '' string = ''
for formatter in self.__class__.formatters: for formatter in self.__class__.formatters:
string = string + formatter(self) string += formatter(self)
return string return string
setattr(cls, 'format', format) cls.format = format
if not dict.has_key('__str__'): if not dict.has_key('__str__'):
def string(self): cls.__str__ = format
return self.format()
setattr(cls, '__str__', string)
def gen_tag(cls, tag): def gen_attr_member(cls, attr):
# generate readers and writers for the tag """generate readers and writers for an attribute member"""
val = getattr(cls, 't_' + tag) print 'attr:', attr
tag_type = val[0] spec = getattr(cls, 'a_' + attr)
return autoxml.gen_tag_aux(cls, tag, tag_type, val) tag_type = spec[0]
def gen_tag_aux(cls, tag, tag_type, val):
if type(tag_type) == types.TypeType:
# basic types
return autoxml.gen_basic_tag(cls, tag, val)
elif type(tag_type) == types.ClassType:
return autoxml.gen_class_tag(cls, tag, val)
elif type(tag_type) == types.ListType:
return autoxml.gen_list_tag(cls, tag, val)
def gen_attr(cls, tag):
"generate readers and writers for an attribute"
#print 'attr:', tag
val = getattr(cls, 'a_' + tag)
tag_type = val[0]
assert type(tag_type) == type(type) assert type(tag_type) == type(type)
return autoxml.gen_basic_attr(cls, tag, val) def readtext(node, attr):
return getNodeAttribute(node, attr)
def writetext(xml, node, attr, value):
node.setAttribute(attr, value)
anonfuns = cls.gen_anon_basic(attr, spec, readtext, writetext)
return cls.gen_named_comp(attr, spec, anonfuns)
def gen_tag_member(cls, tag):
"""generate helper funs for tag member of class"""
spec = getattr(cls, 't_' + tag)
def readtext(node, tag):
return getNodeText(getNode(node, tag))
def writetext(xml, node, tag, value):
xml.addTextNodeUnder(node, tag, value)
anonfuns = cls.gen_tag(tag, spec, readtext, writetext)
return cls.gen_named_comp(tag, spec, anonfuns)
def gen_named_comp(cls, token, spec, anonfuns):
"""generate a named component tag/attr. a decoration of
anonymous functions that do not bind to variable names"""
name = cls.mixed_case(token)
token_type = spec[0]
req = spec[1]
(init_a, decode_a, encode_a, format_a) = anonfuns
def init(self):
setattr(self, name, init_a())
def decode(self, node):
setattr(self, name, decode_a(node))
def encode(self, xml):
if hasattr(self, name):
value = getattr(self, name)
else:
value = None
encode_a(xml, value)
def format(self):
if hasattr(self, name):
value = getattr(self,name)
return '%s: %s\n' % (token, format_a(value))
else:
if req == mandatory:
raise Error('Mandatory variable %s not available' % name)
return ''
return (init, decode, encode, format)
def gen_tag(cls, tag, spec, readtext, writetext):
"""generate readers and writers for the tag"""
tag_type = spec[0]
if type(tag_type) == types.TypeType:
return cls.gen_anon_basic(tag, spec, readtext, writetext)
elif type(tag_type) == types.ListType:
return cls.gen_list_tag(tag, spec, readtext, writetext)
elif type(tag_type) == types.ClassType:
return cls.gen_class_tag(tag, spec, readtext, writetext)
def mixed_case(cls, identifier): def mixed_case(cls, identifier):
"""helper function to turn token name into mixed case"""
identifier_p = identifier[0].lower() + identifier[1:] identifier_p = identifier[0].lower() + identifier[1:]
return identifier_p return identifier_p
def gen_basic(cls, token, val, readtext, writetext): def gen_anon_basic(cls, token, spec, readtext, writetext):
"""Generate a basic tag or attribute. This has got """Generate a tag or attribute with one of the basic
to be pretty generic so we can invoke it from the complex types like integer. This has got to be pretty generic
types such as Class and List""" so we can invoke it from the complex types such as Class
and List. The readtext and writetext arguments achieve
the text input I/O for this datatype."""
name = cls.mixed_case(token) name = cls.mixed_case(token)
token_type = val[0] token_type = spec[0]
req = val[1] req = spec[1]
def initialize(self): def initialize():
#print 'init:', name """default value for all basic types is None"""
setattr(self, name, None) return None
def decode(self, node): def decode(node):
"""decode from DOM node, the value, watching the spec"""
text = readtext(node, token) text = readtext(node, token)
print 'read text ', text
if text: if text:
try: try:
value = autoxml.basic_cons_map[token_type](text) value = autoxml.basic_cons_map[token_type](text)
except Error: except Error:
raise Error('Type mismatch') raise Error('Type mismatch: read text cannot be decoded')
setattr(self, name, value) return value
else: else:
if req == mandatory: if req == mandatory:
raise Error('Mandatory argument not available') raise Error('Mandatory argument not available')
else: else:
return None return None
def encode(self, xml, value): def encode(xml, value):
"""encode given value into xml file"""
node = xml.newNode(cls.tag) node = xml.newNode(cls.tag)
if hasattr(self, name): if value:
writetext(xml, node, token, str(value)) writetext(xml, node, token, str(value))
else: else:
if req == mandatory: if req == mandatory:
raise Error('Mandatory argument not available') raise Error('Mandatory argument not available')
def format(self): def format(value):
if hasattr(self, name): return str(value)
return '%s: %s\n' % (token, str(getattr(self, name)))
else:
if req == mandatory:
raise Error('Mandatory variable %s not available' % name)
return ""
return initialize, decode, encode, format return initialize, decode, encode, format
def gen_basic_attr(cls, attr, spec): def gen_class_tag(cls, tag, spec, readtext, writetext):
"""generate an attribute with a basic datatype"""
def readtext(node, attr):
return getNodeAttribute(node, attr)
def writetext(xml, node, attr, value):
node.setAttribute(attr, value)
return autoxml.gen_basic(cls, attr, spec, readtext, writetext)
def gen_basic_tag(cls, tag, spec):
"""generate a tag with a basic datatype"""
def readtext(node, tag):
return getNodeText(getNode(node, tag))
def writetext(xml, node, tag, value):
xml.addTextNodeUnder(node, tag, value)
return autoxml.gen_basic(cls, tag, spec, readtext, writetext)
def gen_class_tag(cls, tag, val):
pass pass
def gen_list_tag(cls, tag, val): def gen_list_tag(cls, tag, spec, readtext, writetext):
""" generate a list member of a class. we do not support
list members that are embedded in lists. """
name = cls.mixed_case(tag) name = cls.mixed_case(tag)
tag_type = val[0] tag_type = spec[0]
req = val[1] req = spec[1]
if len(val)>=3: if len(spec)>=3:
path = val[2] # an alternative path specified path = spec[2] # an alternative path specified
else: else:
path = tag # otherwise it's the same name as path = tag # otherwise it's the same name as
# the tag # the tag
if len(tag_type) != 1: if len(tag_type) != 1:
raise Error('List type must contain only one element') raise Error('List type must contain only one element')
x = autoxml.gen_tag_aux(cls, tag, tag_type[0], val) def readtext(node, tag):
return getNodeText(node)
def writetext(xml, node, tag, value):
xml.addTextNode(node, value)
x = cls.gen_tag(tag, [tag_type[0], mandatory], readtext, writetext)
(init_item, decode_item, encode_item, format_item) = x (init_item, decode_item, encode_item, format_item) = x
def init(self): def init():
setattr(self, name, []) return []
def decode(self, node): def decode(node):
l = [] l = []
self.nodes = getAllNodes(node, path) nodes = getAllNodes(node, path)
print 'F U', self.nodes print 'F U', nodes
if len(self.nodes) is 0 and req is mandatory: if len(nodes) is 0 and req is mandatory:
raise Error('Mandatory list empty') raise Error('Mandatory list empty')
for node in self.nodes: for node in nodes:
l.append(decode_item(self, node)) l.append(decode_item(node))
return l return l
def encode(self, xml, value): def encode(xml, l):
pass pass
def format(self): def format(l):
#print 'format:', name #print 'format:', name
s = '' s = ''
l = getattr(self, name)
for ix in range(len(l)): for ix in range(len(l)):
s += str(ix) + format_item(l[ix]) s += str(ix+1) + ': ' + format_item(l[ix])
if ix != len(l)-1:
s += ', '
return s return s
return (init, decode, encode, format) return (init, decode, encode, format)
+4
View File
@@ -17,6 +17,9 @@ import os
sys.path.append('.') sys.path.append('.')
sys.path.append('..') sys.path.append('..')
import pisi
import pisi.api
runTestSuite = lambda(x): unittest.TextTestRunner(verbosity=2).run(x) runTestSuite = lambda(x): unittest.TextTestRunner(verbosity=2).run(x)
def run_all(): def run_all():
@@ -59,6 +62,7 @@ def run_all():
runTestSuite(alltests) runTestSuite(alltests)
if __name__ == "__main__": if __name__ == "__main__":
pisi.api.init(False)
args = sys.argv args = sys.argv
if len(args) > 1: # run modules given from the command line if len(args) > 1: # run modules given from the command line
tests = sys.argv[1:] tests = sys.argv[1:]
+4 -2
View File
@@ -32,7 +32,7 @@ class XmlFileTestCase(unittest.TestCase):
t_Number = [types.IntType, xmlfile.optional] t_Number = [types.IntType, xmlfile.optional]
t_Email = [types.StringType, xmlfile.optional] t_Email = [types.StringType, xmlfile.optional]
a_href = [types.StringType, xmlfile.mandatory] a_href = [types.StringType, xmlfile.mandatory]
#t_Projects = [ [types.StringType], xmlfile.mandatory] t_Projects = [ [types.StringType], xmlfile.mandatory, 'Projects/Project']
a = A() a = A()
self.assertEqual(a.href, None) self.assertEqual(a.href, None)
dom = mdom.parse('tests/a.xml') dom = mdom.parse('tests/a.xml')
@@ -43,13 +43,15 @@ class XmlFileTestCase(unittest.TestCase):
self.assertEqual(a.number, 868) self.assertEqual(a.number, 868)
self.assertEqual(a.name, 'Eray Ozkural') self.assertEqual(a.name, 'Eray Ozkural')
string = a.format() string = a.format()
#print '*', string print '*', string
#self.assert_(string.startswith('Name')) #self.assert_(string.startswith('Name'))
outfn = '/tmp/a2.xml' outfn = '/tmp/a2.xml'
xml = xmlfile.XmlFile('A') xml = xmlfile.XmlFile('A')
a2 = A() a2 = A()
a2.name = "Baris Metin" a2.name = "Baris Metin"
a2.email = "baris@uludag.org.tr" a2.email = "baris@uludag.org.tr"
a2.href = 'http://cekirdek.uludag.org.tr/~baris'
a2.projects = [ 'pisi', 'tasma', 'plasma' ]
elt = a2.encode(xml) elt = a2.encode(xml)
string = a2.format() string = a2.format()