Package Ganga :: Package Core :: Package JobRepositoryXML :: Module VStreamer
[hide private]
[frames] | no frames]

Source Code for Module Ganga.Core.JobRepositoryXML.VStreamer

  1  ################################################################################ 
  2  # Ganga Project. http://cern.ch/ganga 
  3  # 
  4  # $Id: VStreamer.py,v 1.5 2009-06-09 13:03:16 moscicki Exp $ 
  5  ################################################################################ 
  6   
  7  # dump object (job) to file f (or stdout) 
8 -def to_file(j,f=None):
9 vstreamer = VStreamer(out=f,selection='subjobs')#FIXME: hardcoded subjobs handling 10 vstreamer.begin_root() 11 j.accept(vstreamer) 12 vstreamer.end_root()
13 14 # load object (job) from file f
15 -def from_file(f):
16 ###logger.debug('----------------------------') 17 ###logger.debug('Parsing file: %s',f.name) 18 obj,errors = Loader().parse(f.read()) 19 return obj,errors
20 21 ################################################################################ 22 # utilities 23 24 import xml.sax.saxutils 25 #import escape, unescape 26
27 -def escape(s):
28 return xml.sax.saxutils.escape(s) #s.replace('"', '\\"').replace("'", "\\'"))
29
30 -def unescape(s):
31 return xml.sax.saxutils.unescape(s)
32 33 34 from Ganga.GPIDev.Lib.GangaList.GangaList import makeGangaListByRef as makeGangaListByRef 35 36 # config_scope is namespace used for evaluating simple objects (e.g. File) 37 from Ganga.Utility.Config import config_scope 38 39 #def makeGangaList(l): 40 # return l[:] 41 42 ################################################################################ 43 # A visitor to print the object tree into XML. 44 #
45 -class VStreamer(object):
46 # Arguments: 47 # out: file-like output stream where to print, default sys.stdout 48 # selection: string specifying the name of properties which should not be printed 49 # e.g. 'subjobs' - will not print subjobs
50 - def __init__(self,out=None,selection=''):
51 self.level = 0 52 self.nocomma = 1 53 self.selection = selection 54 if out: 55 self.out = out 56 else: 57 import sys 58 self.out = sys.stdout
59
60 - def begin_root(self):
61 print >> self.out,'<root>'
62
63 - def end_root(self):
64 print >> self.out,'</root>'
65
66 - def indent(self):
67 return ' '*(self.level-1)*3
68
69 - def nodeBegin(self,node):
70 self.level += 1 71 s = node._schema 72 print >> self.out,self.indent(),'<class name="%s" version="%d.%d" category="%s">'%(s.name,s.version.major,s.version.minor,s.category) 73 self.nocomma = 1 74 self.empty_body = 1
75
76 - def nodeEnd(self,node):
77 print >> self.out,self.indent(),'</class>' 78 self.level -= 1 79 return
80
81 - def showAttribute( self, node, name ):
82 return not node._schema.getItem(name)['transient'] and name!=self.selection
83
84 - def simpleAttribute(self,node,name, value,sequence):
85 if self.showAttribute( node, name ): 86 self.level+=1 87 print >> self.out, self.indent(), 88 print >> self.out, '<attribute name="%s">'%name, 89 90 def print_value(v): 91 #print 'value',quote(v) 92 print >> self.out,'<value>%s</value>'%self.quote(v),
93 94 if sequence: 95 self.level+=1 96 print >> self.out 97 print >> self.out, self.indent(),'<sequence>' 98 for v in value: 99 self.level+=1 100 print >> self.out, self.indent(), 101 print_value(v) 102 print >> self.out 103 self.level-=1 104 print >> self.out, self.indent(), '</sequence>' 105 self.level-=1 106 print >> self.out, self.indent(), '</attribute>' 107 else: 108 self.level+=1 109 print_value(value) 110 self.level-=1 111 print >> self.out,'</attribute>' 112 self.level-=1
113
114 - def acceptOptional(self,s):
115 self.level+=1 116 if s is None: 117 print >> self.out,self.indent(), '<value>None</value>' 118 else: 119 s.accept(self) 120 self.level-=1
121
122 - def componentAttribute(self,node,name,subnode,sequence):
123 if self.showAttribute( node, name ): 124 self.empty_body = 0 125 self.level+=1 126 print >> self.out, self.indent(), '<attribute name="%s">'%name 127 if sequence: 128 self.level+=1 129 print >> self.out, self.indent(), '<sequence>' 130 for s in subnode: 131 self.acceptOptional(s) 132 print >> self.out,self.indent(), '</sequence>' 133 self.level-=1 134 else: 135 self.acceptOptional(subnode) 136 print >> self.out,self.indent(), '</attribute>' 137 self.level-=1
138
139 - def quote(self,x):
140 return escape(repr(x))
141 142 143 ################################################################################ 144 # XML Parser. 145 146 from Ganga.GPIDev.Base.Objects import GangaObject 147 from Ganga.Utility.Plugin import PluginManagerError, allPlugins 148 from Ganga.GPIDev.Schema import Schema, Version 149 150 from Ganga.Utility.logging import getLogger 151 logger = getLogger() 152 153 # Empty Ganga Object
154 -class EmptyGangaObject(GangaObject):
155 """Empty Ganga Object. Is used to construct incomplete jobs""" 156 _schema = Schema(Version(0,0), {}) 157 _name = "Unknown" 158 _category = "unknownObjects" 159 _hidden = 1
160 161
162 -class SchemaVersionError(Exception):
163 pass
164
165 -class Loader:
166 """ Job object tree loader. 167 """ 168
169 - def __init__(self):
170 self.stack = None # we construct object tree using this stack 171 self.ignore_count = 0 # ignore nested XML elements in case of data errors at a higher level 172 self.errors = [] # list of exception objects in case of data errors 173 self.value_construct = None #buffer for <value> elements (evaled as python expressions) 174 self.sequence_start = [] # buffer for building sequences (FIXME: what about nested sequences?)
175
176 - def parse(self,s):
177 """ Parse and load object from string s using internal XML parser (expat). 178 """ 179 import xml.parsers.expat 180 181 # 3 handler functions 182 def start_element(name, attrs): 183 ###logger.debug('Start element: name=%s attrs=%s', name, attrs) #FIXME: for 2.4 use CurrentColumnNumber and CurrentLineNumber 184 # if higher level element had error, ignore the corresponding part of the XML tree as we go down 185 if self.ignore_count: 186 self.ignore_count += 1 187 return 188 189 # initialize object stack 190 if name == 'root': 191 assert self.stack is None,"duplicated <root> element" 192 self.stack = [] 193 return 194 195 assert not self.stack is None,"missing <root> element" 196 197 # load a class, make empty object and push it as the current object on the stack 198 if name == 'class': 199 try: 200 cls = allPlugins.find(attrs['category'],attrs['name']) 201 except PluginManagerError,e: 202 self.errors.append(e) 203 #self.errors.append('Unknown class: %(name)s'%attrs) 204 obj = EmptyGangaObject() 205 self.ignore_count = 1 # ignore all elemenents until the corresponding ending element (</class>) is reached 206 else: 207 version = Version(*[int(v) for v in attrs['version'].split('.')]) 208 if not cls._schema.version.isCompatible(version): 209 attrs['currversion'] = '%s.%s'%(cls._schema.version.major,cls._schema.version.minor) 210 self.errors.append(SchemaVersionError('Incompatible schema of %(name)s, repository is %(version)s currently in use is %(currversion)s'%attrs)) 211 obj = EmptyGangaObject() 212 self.ignore_count = 1 # ignore all elemenents until the corresponding ending element (</class>) is reached 213 else: 214 # make a new ganga object 215 obj = super(cls, cls).__new__(cls) 216 obj._data = {} 217 self.stack.append(obj) 218 219 # push the attribute name on the stack 220 if name == 'attribute': 221 self.stack.append(attrs['name']) 222 223 # start value_contruct mode and initialize the value buffer 224 if name == 'value': 225 self.value_construct = '' 226 227 # save a marker where the sequence begins on the stack 228 if name == 'sequence': 229 self.sequence_start.append(len(self.stack))
230 231 def end_element(name): 232 ###logger.debug('End element: name=%s', name) 233 234 # if higher level element had error, ignore the corresponding part of the XML tree as we go up 235 if self.ignore_count: 236 self.ignore_count -= 1 237 return 238 239 # when </attribute> is seen the current object, attribute name and value should be on top of the stack 240 if name == 'attribute': 241 value = self.stack.pop() 242 aname = self.stack.pop() 243 obj = self.stack[-1] 244 # update the object's attribute 245 obj._data[aname] = value 246 247 # when </value> is seen the value_construct buffer (CDATA) should be a python expression (e.g. quoted string) 248 if name == 'value': 249 # unescape the special characters 250 s = unescape(self.value_construct) 251 ###logger.debug('string value: %s',s) 252 val = eval(s,config_scope) 253 ###logger.debug('evaled value: %s type=%s',repr(val),type(val)) 254 self.stack.append(val) 255 self.value_construct = None 256 257 # when </sequence> is seen we remove last items from stack (as indicated by sequence_start) 258 # we make a GangaList from these items and put it on stack 259 if name == 'sequence': 260 pos = self.sequence_start.pop() 261 alist = makeGangaListByRef(self.stack[pos:]) 262 del self.stack[pos:] 263 self.stack.append(alist) 264 265 # when </class> is seen we finish initializing the new object 266 # by setting remaining attributes to their default values 267 # the object stays on the stack (will be removed by </attribute> or is a root object) 268 if name == 'class': 269 obj = self.stack[-1] 270 for attr, item in obj._schema.allItems(): 271 if not attr in obj._data: 272 obj._data[attr] = obj._schema.getDefaultValue(attr) 273 obj.__setstate__(obj.__dict__) # this sets the parent
274 275 def char_data(data): 276 # char_data may be called many times in one CDATA section so we need to build up 277 # the full buffer for <value>CDATA</value> section incrementally 278 if self.value_construct is not None: 279 ###logger.debug('char_data: append=%s',data) 280 #FIXME: decode data 281 self.value_construct += data 282 283 #start parsing using callbacks 284 p = xml.parsers.expat.ParserCreate() 285 286 p.StartElementHandler = start_element 287 p.EndElementHandler = end_element 288 p.CharacterDataHandler = char_data 289 290 p.Parse(s) 291 292 assert len(self.stack)==1, 'multiple objects inside <root> element' 293 294 obj = self.stack[-1] 295 if obj._name == 'Unknown': 296 raise Exception('Unable to create root object',self.errors) 297 298 return obj,self.errors 299 300 301 ################################################################################ 302 # JUNK 303 304 #-o[Logging]Ganga.GPIDev.Lib.JobRegistry=DEBUG -o[Logging]Ganga.Core.JobRepository=DEBUG -o[Configuration]StartupGPI="from Ganga.GPIDev.Base.VStreamer import p,g; j=Job(inputsandbox=['x','y'],outputsandbox=['a','b']); p(j); jj=g(j);" 305 306
307 -def p(j,f=None):
308 vstreamer = VStreamer(out=f) 309 vstreamer.begin_root() 310 j._impl.accept(vstreamer) 311 vstreamer.end_root()
312
313 -def g(j):
314 import StringIO 315 s = StringIO.StringIO() 316 p(j,s) 317 return Parser().parse(s.getvalue())
318 319 ################################################################################ 320