pywbem-0.8.0~dev/0000755000175000017500000000000012413747232013616 5ustar bzedbzed00000000000000pywbem-0.8.0~dev/pywbem/0000755000175000017500000000000012413747232015121 5ustar bzedbzed00000000000000pywbem-0.8.0~dev/pywbem/yacc.py0000644000175000017500000036311512413747174016430 0ustar bzedbzed00000000000000# ----------------------------------------------------------------------------- # ply: yacc.py # # Author(s): David M. Beazley (dave@dabeaz.com) # # Copyright (C) 2001-2009, David M. Beazley # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # See the file COPYING for a complete copy of the LGPL. # # # This implements an LR parser that is constructed from grammar rules defined # as Python functions. The grammer is specified by supplying the BNF inside # Python documentation strings. The inspiration for this technique was borrowed # from John Aycock's Spark parsing system. PLY might be viewed as cross between # Spark and the GNU bison utility. # # The current implementation is only somewhat object-oriented. The # LR parser itself is defined in terms of an object (which allows multiple # parsers to co-exist). However, most of the variables used during table # construction are defined in terms of global variables. Users shouldn't # notice unless they are trying to define multiple parsers at the same # time using threads (in which case they should have their head examined). # # This implementation supports both SLR and LALR(1) parsing. LALR(1) # support was originally implemented by Elias Ioup (ezioup@alumni.uchicago.edu), # using the algorithm found in Aho, Sethi, and Ullman "Compilers: Principles, # Techniques, and Tools" (The Dragon Book). LALR(1) has since been replaced # by the more efficient DeRemer and Pennello algorithm. # # :::::::: WARNING ::::::: # # Construction of LR parsing tables is fairly complicated and expensive. # To make this module run fast, a *LOT* of work has been put into # optimization---often at the expensive of readability and what might # consider to be good Python "coding style." Modify the code at your # own risk! # ---------------------------------------------------------------------------- __version__ = "3.0" __tabversion__ = "3.0" # Table version #----------------------------------------------------------------------------- # === User configurable parameters === # # Change these to modify the default behavior of yacc (if you wish) #----------------------------------------------------------------------------- yaccdebug = 1 # Debugging mode. If set, yacc generates a # a 'parser.out' file in the current directory debug_file = 'parser.out' # Default name of the debugging file tab_module = 'parsetab' # Default name of the table module default_lr = 'LALR' # Default LR table generation method error_count = 3 # Number of symbols that must be shifted to leave recovery mode yaccdevel = 0 # Set to True if developing yacc. This turns off optimized # implementations of certain functions. resultlimit = 40 # Size limit of results when running in debug mode. import re, types, sys, os.path # Compatibility function for python 2.6/3.0 if sys.version_info[0] < 3: def func_code(f): return f.func_code else: def func_code(f): return f.__code__ # Compatibility try: MAXINT = sys.maxint except AttributeError: MAXINT = sys.maxsize # Python 2.x/3.0 compatibility. def load_ply_lex(): if sys.version_info[0] < 3: import lex else: import ply.lex as lex return lex # This object is a stand-in for a logging object created by the # logging module. PLY will use this by default to create things # such as the parser.out file. If a user wants more detailed # information, they can create their own logging object and pass # it into PLY. class PlyLogger(object): def __init__(self,f): self.f = f def debug(self,msg,*args,**kwargs): self.f.write((msg % args) + "\n") info = debug def warning(self,msg,*args,**kwargs): self.f.write("WARNING: "+ (msg % args) + "\n") def error(self,msg,*args,**kwargs): self.f.write("ERROR: " + (msg % args) + "\n") critical = debug # Null logger is used when no output is generated. Does nothing. class NullLogger(object): def __getattribute__(self,name): return self def __call__(self,*args,**kwargs): return self # Exception raised for yacc-related errors class YaccError(Exception): pass # Format the result message that the parser produces when running in debug mode. def format_result(r): repr_str = repr(r) if '\n' in repr_str: repr_str = repr(repr_str) if len(repr_str) > resultlimit: repr_str = repr_str[:resultlimit]+" ..." result = "<%s @ 0x%x> (%s)" % (type(r).__name__,id(r),repr_str) return result # Format stack entries when the parser is running in debug mode def format_stack_entry(r): repr_str = repr(r) if '\n' in repr_str: repr_str = repr(repr_str) if len(repr_str) < 16: return repr_str else: return "<%s @ 0x%x>" % (type(r).__name__,id(r)) #----------------------------------------------------------------------------- # === LR Parsing Engine === # # The following classes are used for the LR parser itself. These are not # used during table construction and are independent of the actual LR # table generation algorithm #----------------------------------------------------------------------------- # This class is used to hold non-terminal grammar symbols during parsing. # It normally has the following attributes set: # .type = Grammar symbol type # .value = Symbol value # .lineno = Starting line number # .endlineno = Ending line number (optional, set automatically) # .lexpos = Starting lex position # .endlexpos = Ending lex position (optional, set automatically) class YaccSymbol: def __str__(self): return self.type def __repr__(self): return str(self) # This class is a wrapper around the objects actually passed to each # grammar rule. Index lookup and assignment actually assign the # .value attribute of the underlying YaccSymbol object. # The lineno() method returns the line number of a given # item (or 0 if not defined). The linespan() method returns # a tuple of (startline,endline) representing the range of lines # for a symbol. The lexspan() method returns a tuple (lexpos,endlexpos) # representing the range of positional information for a symbol. class YaccProduction: def __init__(self,s,stack=None): self.slice = s self.stack = stack self.lexer = None self.parser= None def __getitem__(self,n): if n >= 0: return self.slice[n].value else: return self.stack[n].value def __setitem__(self,n,v): self.slice[n].value = v def __getslice__(self,i,j): return [s.value for s in self.slice[i:j]] def __len__(self): return len(self.slice) def lineno(self,n): return getattr(self.slice[n],"lineno",0) def set_lineno(self,n,lineno): self.slice[n].lineno = n def linespan(self,n): startline = getattr(self.slice[n],"lineno",0) endline = getattr(self.slice[n],"endlineno",startline) return startline,endline def lexpos(self,n): return getattr(self.slice[n],"lexpos",0) def lexspan(self,n): startpos = getattr(self.slice[n],"lexpos",0) endpos = getattr(self.slice[n],"endlexpos",startpos) return startpos,endpos def error(self): raise SyntaxError # ----------------------------------------------------------------------------- # == LRParser == # # The LR Parsing engine. # ----------------------------------------------------------------------------- class LRParser: def __init__(self,lrtab,errorf): self.productions = lrtab.lr_productions self.action = lrtab.lr_action self.goto = lrtab.lr_goto self.errorfunc = errorf def errok(self): self.errorok = 1 def restart(self): del self.statestack[:] del self.symstack[:] sym = YaccSymbol() sym.type = '$end' self.symstack.append(sym) self.statestack.append(0) def parse(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): if debug or yaccdevel: if isinstance(debug,int): debug = PlyLogger(sys.stderr) return self.parsedebug(input,lexer,debug,tracking,tokenfunc) elif tracking: return self.parseopt(input,lexer,debug,tracking,tokenfunc) else: return self.parseopt_notrack(input,lexer,debug,tracking,tokenfunc) # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # parsedebug(). # # This is the debugging enabled version of parse(). All changes made to the # parsing engine should be made here. For the non-debugging version, # copy this code to a method parseopt() and delete all of the sections # enclosed in: # # #--! DEBUG # statements # #--! DEBUG # # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! def parsedebug(self,input=None,lexer=None,debug=None,tracking=0,tokenfunc=None): lookahead = None # Current lookahead symbol lookaheadstack = [ ] # Stack of lookahead symbols actions = self.action # Local reference to action table (to avoid lookup on self.) goto = self.goto # Local reference to goto table (to avoid lookup on self.) prod = self.productions # Local reference to production list (to avoid lookup on self.) pslice = YaccProduction(None) # Production object passed to grammar rules errorcount = 0 # Used during error recovery # --! DEBUG debug.info("PLY: PARSE DEBUG START") # --! DEBUG # If no lexer was given, we will try to use the lex module if not lexer: lex = load_ply_lex() lexer = lex.lexer # Set up the lexer and parser objects on pslice pslice.lexer = lexer pslice.parser = self # If input was supplied, pass to lexer if input is not None: lexer.input(input) if tokenfunc is None: # Tokenize function get_token = lexer.token else: get_token = tokenfunc # Set up the state and symbol stacks statestack = [ ] # Stack of parsing states self.statestack = statestack symstack = [ ] # Stack of grammar symbols self.symstack = symstack pslice.stack = symstack # Put in the production errtoken = None # Err token # The start state is assumed to be (0,$end) statestack.append(0) sym = YaccSymbol() sym.type = "$end" symstack.append(sym) state = 0 while 1: # Get the next symbol on the input. If a lookahead symbol # is already set, we just use that. Otherwise, we'll pull # the next token off of the lookaheadstack or from the lexer # --! DEBUG debug.debug('') debug.debug('State : %s', state) # --! DEBUG if not lookahead: if not lookaheadstack: lookahead = get_token() # Get the next token else: lookahead = lookaheadstack.pop() if not lookahead: lookahead = YaccSymbol() lookahead.type = "$end" # --! DEBUG debug.debug('Stack : %s', ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) # --! DEBUG # Check the action table ltype = lookahead.type t = actions[state].get(ltype) if t is not None: if t > 0: # shift a symbol on the stack statestack.append(t) state = t # --! DEBUG debug.debug("Action : Shift and goto state %s", t) # --! DEBUG symstack.append(lookahead) lookahead = None # Decrease error count on successful shift if errorcount: errorcount -=1 continue if t < 0: # reduce a symbol on the stack, emit a production p = prod[-t] pname = p.name plen = p.len # Get production function sym = YaccSymbol() sym.type = pname # Production name sym.value = None # --! DEBUG if plen: debug.info("Action : Reduce rule [%s] with %s and goto state %d", p.str, "["+",".join([format_stack_entry(_v.value) for _v in symstack[-plen:]])+"]",-t) else: debug.info("Action : Reduce rule [%s] with %s and goto state %d", p.str, [],-t) # --! DEBUG if plen: targ = symstack[-plen-1:] targ[0] = sym # --! TRACKING if tracking: t1 = targ[1] sym.lineno = t1.lineno sym.lexpos = t1.lexpos t1 = targ[-1] sym.endlineno = getattr(t1,"endlineno",t1.lineno) sym.endlexpos = getattr(t1,"endlexpos",t1.lexpos) # --! TRACKING # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # The code enclosed in this section is duplicated # below as a performance optimization. Make sure # changes get made in both locations. pslice.slice = targ try: # Call the grammar rule with our special slice object del symstack[-plen:] del statestack[-plen:] p.callable(pslice) # --! DEBUG debug.info("Result : %s", format_result(pslice[0])) # --! DEBUG symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state lookaheadstack.append(lookahead) symstack.pop() statestack.pop() state = statestack[-1] sym.type = 'error' lookahead = sym errorcount = error_count self.errorok = 0 continue # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! else: # --! TRACKING if tracking: sym.lineno = lexer.lineno sym.lexpos = lexer.lexpos # --! TRACKING targ = [ sym ] # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # The code enclosed in this section is duplicated # above as a performance optimization. Make sure # changes get made in both locations. pslice.slice = targ try: # Call the grammar rule with our special slice object p.callable(pslice) # --! DEBUG debug.info("Result : %s", format_result(pslice[0])) # --! DEBUG symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state lookaheadstack.append(lookahead) symstack.pop() statestack.pop() state = statestack[-1] sym.type = 'error' lookahead = sym errorcount = error_count self.errorok = 0 continue # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if t == 0: n = symstack[-1] result = getattr(n,"value",None) # --! DEBUG debug.info("Done : Returning %s", format_result(result)) debug.info("PLY: PARSE DEBUG END") # --! DEBUG return result if t == None: # --! DEBUG debug.error('Error : %s', ("%s . %s" % (" ".join([xx.type for xx in symstack][1:]), str(lookahead))).lstrip()) # --! DEBUG # We have some kind of parsing error here. To handle # this, we are going to push the current token onto # the tokenstack and replace it with an 'error' token. # If there are any synchronization rules, they may # catch it. # # In addition to pushing the error token, we call call # the user defined p_error() function if this is the # first syntax error. This function is only called if # errorcount == 0. if errorcount == 0 or self.errorok: errorcount = error_count self.errorok = 0 errtoken = lookahead if errtoken.type == "$end": errtoken = None # End of file! if self.errorfunc: global errok,token,restart errok = self.errok # Set some special functions available in error recovery token = get_token restart = self.restart if errtoken and not hasattr(errtoken,'lexer'): errtoken.lexer = lexer tok = self.errorfunc(errtoken) del errok, token, restart # Delete special functions if self.errorok: # User must have done some kind of panic # mode recovery on their own. The # returned token is the next lookahead lookahead = tok errtoken = None continue else: if errtoken: if hasattr(errtoken,"lineno"): lineno = lookahead.lineno else: lineno = 0 if lineno: sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) else: sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) else: sys.stderr.write("yacc: Parse error in input. EOF\n") return else: errorcount = error_count # case 1: the statestack only has 1 entry on it. If we're in this state, the # entire parse has been rolled back and we're completely hosed. The token is # discarded and we just keep going. if len(statestack) <= 1 and lookahead.type != "$end": lookahead = None errtoken = None state = 0 # Nuke the pushback stack del lookaheadstack[:] continue # case 2: the statestack has a couple of entries on it, but we're # at the end of the file. nuke the top entry and generate an error token # Start nuking entries on the stack if lookahead.type == "$end": # Whoa. We're really hosed here. Bail out return if lookahead.type != 'error': sym = symstack[-1] if sym.type == 'error': # Hmmm. Error is on top of stack, we'll just nuke input # symbol and continue lookahead = None continue t = YaccSymbol() t.type = 'error' if hasattr(lookahead,"lineno"): t.lineno = lookahead.lineno t.value = lookahead lookaheadstack.append(lookahead) lookahead = t else: symstack.pop() statestack.pop() state = statestack[-1] # Potential bug fix continue # Call an error function here raise RuntimeError("yacc: internal parser error!!!\n") # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # parseopt(). # # Optimized version of parse() method. DO NOT EDIT THIS CODE DIRECTLY. # Edit the debug version above, then copy any modifications to the method # below while removing #--! DEBUG sections. # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! def parseopt(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): lookahead = None # Current lookahead symbol lookaheadstack = [ ] # Stack of lookahead symbols actions = self.action # Local reference to action table (to avoid lookup on self.) goto = self.goto # Local reference to goto table (to avoid lookup on self.) prod = self.productions # Local reference to production list (to avoid lookup on self.) pslice = YaccProduction(None) # Production object passed to grammar rules errorcount = 0 # Used during error recovery # If no lexer was given, we will try to use the lex module if not lexer: lex = load_ply_lex() lexer = lex.lexer # Set up the lexer and parser objects on pslice pslice.lexer = lexer pslice.parser = self # If input was supplied, pass to lexer if input is not None: lexer.input(input) if tokenfunc is None: # Tokenize function get_token = lexer.token else: get_token = tokenfunc # Set up the state and symbol stacks statestack = [ ] # Stack of parsing states self.statestack = statestack symstack = [ ] # Stack of grammar symbols self.symstack = symstack pslice.stack = symstack # Put in the production errtoken = None # Err token # The start state is assumed to be (0,$end) statestack.append(0) sym = YaccSymbol() sym.type = '$end' symstack.append(sym) state = 0 while 1: # Get the next symbol on the input. If a lookahead symbol # is already set, we just use that. Otherwise, we'll pull # the next token off of the lookaheadstack or from the lexer if not lookahead: if not lookaheadstack: lookahead = get_token() # Get the next token else: lookahead = lookaheadstack.pop() if not lookahead: lookahead = YaccSymbol() lookahead.type = '$end' # Check the action table ltype = lookahead.type t = actions[state].get(ltype) if t is not None: if t > 0: # shift a symbol on the stack statestack.append(t) state = t symstack.append(lookahead) lookahead = None # Decrease error count on successful shift if errorcount: errorcount -=1 continue if t < 0: # reduce a symbol on the stack, emit a production p = prod[-t] pname = p.name plen = p.len # Get production function sym = YaccSymbol() sym.type = pname # Production name sym.value = None if plen: targ = symstack[-plen-1:] targ[0] = sym # --! TRACKING if tracking: t1 = targ[1] sym.lineno = t1.lineno sym.lexpos = t1.lexpos t1 = targ[-1] sym.endlineno = getattr(t1,"endlineno",t1.lineno) sym.endlexpos = getattr(t1,"endlexpos",t1.lexpos) # --! TRACKING # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # The code enclosed in this section is duplicated # below as a performance optimization. Make sure # changes get made in both locations. pslice.slice = targ try: # Call the grammar rule with our special slice object del symstack[-plen:] del statestack[-plen:] p.callable(pslice) symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state lookaheadstack.append(lookahead) symstack.pop() statestack.pop() state = statestack[-1] sym.type = 'error' lookahead = sym errorcount = error_count self.errorok = 0 continue # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! else: # --! TRACKING if tracking: sym.lineno = lexer.lineno sym.lexpos = lexer.lexpos # --! TRACKING targ = [ sym ] # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # The code enclosed in this section is duplicated # above as a performance optimization. Make sure # changes get made in both locations. pslice.slice = targ try: # Call the grammar rule with our special slice object p.callable(pslice) symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state lookaheadstack.append(lookahead) symstack.pop() statestack.pop() state = statestack[-1] sym.type = 'error' lookahead = sym errorcount = error_count self.errorok = 0 continue # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if t == 0: n = symstack[-1] return getattr(n,"value",None) if t == None: # We have some kind of parsing error here. To handle # this, we are going to push the current token onto # the tokenstack and replace it with an 'error' token. # If there are any synchronization rules, they may # catch it. # # In addition to pushing the error token, we call call # the user defined p_error() function if this is the # first syntax error. This function is only called if # errorcount == 0. if errorcount == 0 or self.errorok: errorcount = error_count self.errorok = 0 errtoken = lookahead if errtoken.type == '$end': errtoken = None # End of file! if self.errorfunc: global errok,token,restart errok = self.errok # Set some special functions available in error recovery token = get_token restart = self.restart if errtoken and not hasattr(errtoken,'lexer'): errtoken.lexer = lexer tok = self.errorfunc(errtoken) del errok, token, restart # Delete special functions if self.errorok: # User must have done some kind of panic # mode recovery on their own. The # returned token is the next lookahead lookahead = tok errtoken = None continue else: if errtoken: if hasattr(errtoken,"lineno"): lineno = lookahead.lineno else: lineno = 0 if lineno: sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) else: sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) else: sys.stderr.write("yacc: Parse error in input. EOF\n") return else: errorcount = error_count # case 1: the statestack only has 1 entry on it. If we're in this state, the # entire parse has been rolled back and we're completely hosed. The token is # discarded and we just keep going. if len(statestack) <= 1 and lookahead.type != '$end': lookahead = None errtoken = None state = 0 # Nuke the pushback stack del lookaheadstack[:] continue # case 2: the statestack has a couple of entries on it, but we're # at the end of the file. nuke the top entry and generate an error token # Start nuking entries on the stack if lookahead.type == '$end': # Whoa. We're really hosed here. Bail out return if lookahead.type != 'error': sym = symstack[-1] if sym.type == 'error': # Hmmm. Error is on top of stack, we'll just nuke input # symbol and continue lookahead = None continue t = YaccSymbol() t.type = 'error' if hasattr(lookahead,"lineno"): t.lineno = lookahead.lineno t.value = lookahead lookaheadstack.append(lookahead) lookahead = t else: symstack.pop() statestack.pop() state = statestack[-1] # Potential bug fix continue # Call an error function here raise RuntimeError("yacc: internal parser error!!!\n") # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # parseopt_notrack(). # # Optimized version of parseopt() with line number tracking removed. # DO NOT EDIT THIS CODE DIRECTLY. Copy the optimized version and remove # code in the #--! TRACKING sections # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! def parseopt_notrack(self,input=None,lexer=None,debug=0,tracking=0,tokenfunc=None): lookahead = None # Current lookahead symbol lookaheadstack = [ ] # Stack of lookahead symbols actions = self.action # Local reference to action table (to avoid lookup on self.) goto = self.goto # Local reference to goto table (to avoid lookup on self.) prod = self.productions # Local reference to production list (to avoid lookup on self.) pslice = YaccProduction(None) # Production object passed to grammar rules errorcount = 0 # Used during error recovery # If no lexer was given, we will try to use the lex module if not lexer: lex = load_ply_lex() lexer = lex.lexer # Set up the lexer and parser objects on pslice pslice.lexer = lexer pslice.parser = self # If input was supplied, pass to lexer if input is not None: lexer.input(input) if tokenfunc is None: # Tokenize function get_token = lexer.token else: get_token = tokenfunc # Set up the state and symbol stacks statestack = [ ] # Stack of parsing states self.statestack = statestack symstack = [ ] # Stack of grammar symbols self.symstack = symstack pslice.stack = symstack # Put in the production errtoken = None # Err token # The start state is assumed to be (0,$end) statestack.append(0) sym = YaccSymbol() sym.type = '$end' symstack.append(sym) state = 0 while 1: # Get the next symbol on the input. If a lookahead symbol # is already set, we just use that. Otherwise, we'll pull # the next token off of the lookaheadstack or from the lexer if not lookahead: if not lookaheadstack: lookahead = get_token() # Get the next token else: lookahead = lookaheadstack.pop() if not lookahead: lookahead = YaccSymbol() lookahead.type = '$end' # Check the action table ltype = lookahead.type t = actions[state].get(ltype) if t is not None: if t > 0: # shift a symbol on the stack statestack.append(t) state = t symstack.append(lookahead) lookahead = None # Decrease error count on successful shift if errorcount: errorcount -=1 continue if t < 0: # reduce a symbol on the stack, emit a production p = prod[-t] pname = p.name plen = p.len # Get production function sym = YaccSymbol() sym.type = pname # Production name sym.value = None if plen: targ = symstack[-plen-1:] targ[0] = sym # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # The code enclosed in this section is duplicated # below as a performance optimization. Make sure # changes get made in both locations. pslice.slice = targ try: # Call the grammar rule with our special slice object del symstack[-plen:] del statestack[-plen:] p.callable(pslice) symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state lookaheadstack.append(lookahead) symstack.pop() statestack.pop() state = statestack[-1] sym.type = 'error' lookahead = sym errorcount = error_count self.errorok = 0 continue # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! else: targ = [ sym ] # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # The code enclosed in this section is duplicated # above as a performance optimization. Make sure # changes get made in both locations. pslice.slice = targ try: # Call the grammar rule with our special slice object p.callable(pslice) symstack.append(sym) state = goto[statestack[-1]][pname] statestack.append(state) except SyntaxError: # If an error was set. Enter error recovery state lookaheadstack.append(lookahead) symstack.pop() statestack.pop() state = statestack[-1] sym.type = 'error' lookahead = sym errorcount = error_count self.errorok = 0 continue # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if t == 0: n = symstack[-1] return getattr(n,"value",None) if t == None: # We have some kind of parsing error here. To handle # this, we are going to push the current token onto # the tokenstack and replace it with an 'error' token. # If there are any synchronization rules, they may # catch it. # # In addition to pushing the error token, we call call # the user defined p_error() function if this is the # first syntax error. This function is only called if # errorcount == 0. if errorcount == 0 or self.errorok: errorcount = error_count self.errorok = 0 errtoken = lookahead if errtoken.type == '$end': errtoken = None # End of file! if self.errorfunc: global errok,token,restart errok = self.errok # Set some special functions available in error recovery token = get_token restart = self.restart if errtoken and not hasattr(errtoken,'lexer'): errtoken.lexer = lexer tok = self.errorfunc(errtoken) del errok, token, restart # Delete special functions if self.errorok: # User must have done some kind of panic # mode recovery on their own. The # returned token is the next lookahead lookahead = tok errtoken = None continue else: if errtoken: if hasattr(errtoken,"lineno"): lineno = lookahead.lineno else: lineno = 0 if lineno: sys.stderr.write("yacc: Syntax error at line %d, token=%s\n" % (lineno, errtoken.type)) else: sys.stderr.write("yacc: Syntax error, token=%s" % errtoken.type) else: sys.stderr.write("yacc: Parse error in input. EOF\n") return else: errorcount = error_count # case 1: the statestack only has 1 entry on it. If we're in this state, the # entire parse has been rolled back and we're completely hosed. The token is # discarded and we just keep going. if len(statestack) <= 1 and lookahead.type != '$end': lookahead = None errtoken = None state = 0 # Nuke the pushback stack del lookaheadstack[:] continue # case 2: the statestack has a couple of entries on it, but we're # at the end of the file. nuke the top entry and generate an error token # Start nuking entries on the stack if lookahead.type == '$end': # Whoa. We're really hosed here. Bail out return if lookahead.type != 'error': sym = symstack[-1] if sym.type == 'error': # Hmmm. Error is on top of stack, we'll just nuke input # symbol and continue lookahead = None continue t = YaccSymbol() t.type = 'error' if hasattr(lookahead,"lineno"): t.lineno = lookahead.lineno t.value = lookahead lookaheadstack.append(lookahead) lookahead = t else: symstack.pop() statestack.pop() state = statestack[-1] # Potential bug fix continue # Call an error function here raise RuntimeError("yacc: internal parser error!!!\n") # ----------------------------------------------------------------------------- # === Grammar Representation === # # The following functions, classes, and variables are used to represent and # manipulate the rules that make up a grammar. # ----------------------------------------------------------------------------- import re # regex matching identifiers _is_identifier = re.compile(r'^[a-zA-Z0-9_-]+$') # ----------------------------------------------------------------------------- # class Production: # # This class stores the raw information about a single production or grammar rule. # A grammar rule refers to a specification such as this: # # expr : expr PLUS term # # Here are the basic attributes defined on all productions # # name - Name of the production. For example 'expr' # prod - A list of symbols on the right side ['expr','PLUS','term'] # prec - Production precedence level # number - Production number. # func - Function that executes on reduce # file - File where production function is defined # lineno - Line number where production function is defined # # The following attributes are defined or optional. # # len - Length of the production (number of symbols on right hand side) # usyms - Set of unique symbols found in the production # ----------------------------------------------------------------------------- class Production(object): def __init__(self,number,name,prod,precedence=('right',0),func=None,file='',line=0): self.name = name self.prod = tuple(prod) self.number = number self.func = func self.callable = None self.file = file self.line = line self.prec = precedence # Internal settings used during table construction self.len = len(self.prod) # Length of the production # Create a list of unique production symbols used in the production self.usyms = [ ] for s in self.prod: if s not in self.usyms: self.usyms.append(s) # List of all LR items for the production self.lr_items = [] self.lr_next = None # Create a string representation if self.prod: self.str = "%s -> %s" % (self.name," ".join(self.prod)) else: self.str = "%s -> " % self.name def __str__(self): return self.str def __repr__(self): return "Production("+str(self)+")" def __len__(self): return len(self.prod) def __nonzero__(self): return 1 def __getitem__(self,index): return self.prod[index] # Return the nth lr_item from the production (or None if at the end) def lr_item(self,n): if n > len(self.prod): return None p = LRItem(self,n) # Precompute the list of productions immediately following. Hack. Remove later try: p.lr_after = Prodnames[p.prod[n+1]] except (IndexError,KeyError): p.lr_after = [] try: p.lr_before = p.prod[n-1] except IndexError: p.lr_before = None return p # Bind the production function name to a callable def bind(self,pdict): if self.func: self.callable = pdict[self.func] # This class serves as a minimal standin for Production objects when # reading table data from files. It only contains information # actually used by the LR parsing engine, plus some additional # debugging information. class MiniProduction(object): def __init__(self,str,name,len,func,file,line): self.name = name self.len = len self.func = func self.callable = None self.file = file self.line = line self.str = str def __str__(self): return self.str def __repr__(self): return "MiniProduction(%s)" % self.str # Bind the production function name to a callable def bind(self,pdict): if self.func: self.callable = pdict[self.func] # ----------------------------------------------------------------------------- # class LRItem # # This class represents a specific stage of parsing a production rule. For # example: # # expr : expr . PLUS term # # In the above, the "." represents the current location of the parse. Here # basic attributes: # # name - Name of the production. For example 'expr' # prod - A list of symbols on the right side ['expr','.', 'PLUS','term'] # number - Production number. # # lr_next Next LR item. Example, if we are ' expr -> expr . PLUS term' # then lr_next refers to 'expr -> expr PLUS . term' # lr_index - LR item index (location of the ".") in the prod list. # lookaheads - LALR lookahead symbols for this item # len - Length of the production (number of symbols on right hand side) # lr_after - List of all productions that immediately follow # lr_before - Grammar symbol immediately before # ----------------------------------------------------------------------------- class LRItem(object): def __init__(self,p,n): self.name = p.name self.prod = list(p.prod) self.number = p.number self.lr_index = n self.lookaheads = { } self.prod.insert(n,".") self.prod = tuple(self.prod) self.len = len(self.prod) self.usyms = p.usyms def __str__(self): if self.prod: s = "%s -> %s" % (self.name," ".join(self.prod)) else: s = "%s -> " % self.name return s def __repr__(self): return "LRItem("+str(self)+")" def __len__(self): return len(self.prod) def __getitem__(self,index): return self.prod[index] # ----------------------------------------------------------------------------- # rightmost_terminal() # # Return the rightmost terminal from a list of symbols. Used in add_production() # ----------------------------------------------------------------------------- def rightmost_terminal(symbols, terminals): i = len(symbols) - 1 while i >= 0: if symbols[i] in terminals: return symbols[i] i -= 1 return None # ----------------------------------------------------------------------------- # === GRAMMAR CLASS === # # The following class represents the contents of the specified grammar along # with various computed properties such as first sets, follow sets, LR items, etc. # This data is used for critical parts of the table generation process later. # ----------------------------------------------------------------------------- class GrammarError(YaccError): pass class Grammar(object): def __init__(self,terminals): self.Productions = [None] # A list of all of the productions. The first # entry is always reserved for the purpose of # building an augmented grammar self.Prodnames = { } # A dictionary mapping the names of nonterminals to a list of all # productions of that nonterminal. self.Prodmap = { } # A dictionary that is only used to detect duplicate # productions. self.Terminals = { } # A dictionary mapping the names of terminal symbols to a # list of the rules where they are used. for term in terminals: self.Terminals[term] = [] self.Terminals['error'] = [] self.Nonterminals = { } # A dictionary mapping names of nonterminals to a list # of rule numbers where they are used. self.First = { } # A dictionary of precomputed FIRST(x) symbols self.Follow = { } # A dictionary of precomputed FOLLOW(x) symbols self.Precedence = { } # Precedence rules for each terminal. Contains tuples of the # form ('right',level) or ('nonassoc', level) or ('left',level) self.UsedPrecedence = { } # Precedence rules that were actually used by the grammer. # This is only used to provide error checking and to generate # a warning about unused precedence rules. self.Start = None # Starting symbol for the grammar def __len__(self): return len(self.Productions) def __getitem__(self,index): return self.Productions[index] # ----------------------------------------------------------------------------- # set_precedence() # # Sets the precedence for a given terminal. assoc is the associativity such as # 'left','right', or 'nonassoc'. level is a numeric level. # # ----------------------------------------------------------------------------- def set_precedence(self,term,assoc,level): assert self.Productions == [None],"Must call set_precedence() before add_production()" if term in self.Precedence: raise GrammarError("Precedence already specified for terminal '%s'" % term) if assoc not in ['left','right','nonassoc']: raise GrammarError("Associativity must be one of 'left','right', or 'nonassoc'") self.Precedence[term] = (assoc,level) # ----------------------------------------------------------------------------- # add_production() # # Given an action function, this function assembles a production rule and # computes its precedence level. # # The production rule is supplied as a list of symbols. For example, # a rule such as 'expr : expr PLUS term' has a production name of 'expr' and # symbols ['expr','PLUS','term']. # # Precedence is determined by the precedence of the right-most non-terminal # or the precedence of a terminal specified by %prec. # # A variety of error checks are performed to make sure production symbols # are valid and that %prec is used correctly. # ----------------------------------------------------------------------------- def add_production(self,prodname,syms,func=None,file='',line=0): if prodname in self.Terminals: raise GrammarError("%s:%d: Illegal rule name '%s'. Already defined as a token" % (file,line,prodname)) if prodname == 'error': raise GrammarError("%s:%d: Illegal rule name '%s'. error is a reserved word" % (file,line,prodname)) if not _is_identifier.match(prodname): raise GrammarError("%s:%d: Illegal rule name '%s'" % (file,line,prodname)) # Look for literal tokens for n,s in enumerate(syms): if s[0] in "'\"": try: c = eval(s) if (len(c) > 1): raise GrammarError("%s:%d: Literal token %s in rule '%s' may only be a single character" % (file,line,s, prodname)) if not c in self.Terminals: self.Terminals[c] = [] syms[n] = c continue except SyntaxError: pass if not _is_identifier.match(s) and s != '%prec': raise GrammarError("%s:%d: Illegal name '%s' in rule '%s'" % (file,line,s, prodname)) # Determine the precedence level if '%prec' in syms: if syms[-1] == '%prec': raise GrammarError("%s:%d: Syntax error. Nothing follows %%prec" % (file,line)) if syms[-2] != '%prec': raise GrammarError("%s:%d: Syntax error. %%prec can only appear at the end of a grammar rule" % (file,line)) precname = syms[-1] prodprec = self.Precedence.get(precname,None) if not prodprec: raise GrammarError("%s:%d: Nothing known about the precedence of '%s'" % (file,line,precname)) else: self.UsedPrecedence[precname] = 1 del syms[-2:] # Drop %prec from the rule else: # If no %prec, precedence is determined by the rightmost terminal symbol precname = rightmost_terminal(syms,self.Terminals) prodprec = self.Precedence.get(precname,('right',0)) # See if the rule is already in the rulemap map = "%s -> %s" % (prodname,syms) if map in self.Prodmap: m = self.Prodmap[map] raise GrammarError("%s:%d: Duplicate rule %s. " % (file,line, m) + "Previous definition at %s:%d" % (file,line, m.file, m.line)) # From this point on, everything is valid. Create a new Production instance pnumber = len(self.Productions) if not prodname in self.Nonterminals: self.Nonterminals[prodname] = [ ] # Add the production number to Terminals and Nonterminals for t in syms: if t in self.Terminals: self.Terminals[t].append(pnumber) else: if not t in self.Nonterminals: self.Nonterminals[t] = [ ] self.Nonterminals[t].append(pnumber) # Create a production and add it to the list of productions p = Production(pnumber,prodname,syms,prodprec,func,file,line) self.Productions.append(p) self.Prodmap[map] = p # Add to the global productions list try: self.Prodnames[prodname].append(p) except KeyError: self.Prodnames[prodname] = [ p ] return 0 # ----------------------------------------------------------------------------- # set_start() # # Sets the starting symbol and creates the augmented grammar. Production # rule 0 is S' -> start where start is the start symbol. # ----------------------------------------------------------------------------- def set_start(self,start=None): if not start: start = self.Productions[1].name if start not in self.Nonterminals: raise GrammarError("start symbol %s undefined" % start) self.Productions[0] = Production(0,"S'",[start]) self.Nonterminals[start].append(0) self.Start = start # ----------------------------------------------------------------------------- # find_unreachable() # # Find all of the nonterminal symbols that can't be reached from the starting # symbol. Returns a list of nonterminals that can't be reached. # ----------------------------------------------------------------------------- def find_unreachable(self): # Mark all symbols that are reachable from a symbol s def mark_reachable_from(s): if reachable[s]: # We've already reached symbol s. return reachable[s] = 1 for p in self.Prodnames.get(s,[]): for r in p.prod: mark_reachable_from(r) reachable = { } for s in list(self.Terminals) + list(self.Nonterminals): reachable[s] = 0 mark_reachable_from( self.Productions[0].prod[0] ) return [s for s in list(self.Nonterminals) if not reachable[s]] # ----------------------------------------------------------------------------- # infinite_cycles() # # This function looks at the various parsing rules and tries to detect # infinite recursion cycles (grammar rules where there is no possible way # to derive a string of only terminals). # ----------------------------------------------------------------------------- def infinite_cycles(self): terminates = {} # Terminals: for t in self.Terminals: terminates[t] = 1 terminates['$end'] = 1 # Nonterminals: # Initialize to false: for n in self.Nonterminals: terminates[n] = 0 # Then propagate termination until no change: while 1: some_change = 0 for (n,pl) in self.Prodnames.items(): # Nonterminal n terminates iff any of its productions terminates. for p in pl: # Production p terminates iff all of its rhs symbols terminate. for s in p.prod: if not terminates[s]: # The symbol s does not terminate, # so production p does not terminate. p_terminates = 0 break else: # didn't break from the loop, # so every symbol s terminates # so production p terminates. p_terminates = 1 if p_terminates: # symbol n terminates! if not terminates[n]: terminates[n] = 1 some_change = 1 # Don't need to consider any more productions for this n. break if not some_change: break infinite = [] for (s,term) in terminates.items(): if not term: if not s in self.Prodnames and not s in self.Terminals and s != 'error': # s is used-but-not-defined, and we've already warned of that, # so it would be overkill to say that it's also non-terminating. pass else: infinite.append(s) return infinite # ----------------------------------------------------------------------------- # undefined_symbols() # # Find all symbols that were used the grammar, but not defined as tokens or # grammar rules. Returns a list of tuples (sym, prod) where sym in the symbol # and prod is the production where the symbol was used. # ----------------------------------------------------------------------------- def undefined_symbols(self): result = [] for p in self.Productions: if not p: continue for s in p.prod: if not s in self.Prodnames and not s in self.Terminals and s != 'error': result.append((s,p)) return result # ----------------------------------------------------------------------------- # unused_terminals() # # Find all terminals that were defined, but not used by the grammar. Returns # a list of all symbols. # ----------------------------------------------------------------------------- def unused_terminals(self): unused_tok = [] for s,v in self.Terminals.items(): if s != 'error' and not v: unused_tok.append(s) return unused_tok # ------------------------------------------------------------------------------ # unused_rules() # # Find all grammar rules that were defined, but not used (maybe not reachable) # Returns a list of productions. # ------------------------------------------------------------------------------ def unused_rules(self): unused_prod = [] for s,v in self.Nonterminals.items(): if not v: p = self.Prodnames[s][0] unused_prod.append(p) return unused_prod # ----------------------------------------------------------------------------- # unused_precedence() # # Returns a list of tuples (term,precedence) corresponding to precedence # rules that were never used by the grammar. term is the name of the terminal # on which precedence was applied and precedence is a string such as 'left' or # 'right' corresponding to the type of precedence. # ----------------------------------------------------------------------------- def unused_precedence(self): unused = [] for termname in self.Precedence: if not (termname in self.Terminals or termname in self.UsedPrecedence): unused.append((termname,self.Precedence[termname][0])) return unused # ------------------------------------------------------------------------- # _first() # # Compute the value of FIRST1(beta) where beta is a tuple of symbols. # # During execution of compute_first1, the result may be incomplete. # Afterward (e.g., when called from compute_follow()), it will be complete. # ------------------------------------------------------------------------- def _first(self,beta): # We are computing First(x1,x2,x3,...,xn) result = [ ] for x in beta: x_produces_empty = 0 # Add all the non- symbols of First[x] to the result. for f in self.First[x]: if f == '': x_produces_empty = 1 else: if f not in result: result.append(f) if x_produces_empty: # We have to consider the next x in beta, # i.e. stay in the loop. pass else: # We don't have to consider any further symbols in beta. break else: # There was no 'break' from the loop, # so x_produces_empty was true for all x in beta, # so beta produces empty as well. result.append('') return result # ------------------------------------------------------------------------- # compute_first() # # Compute the value of FIRST1(X) for all symbols # ------------------------------------------------------------------------- def compute_first(self): if self.First: return self.First # Terminals: for t in self.Terminals: self.First[t] = [t] self.First['$end'] = ['$end'] # Nonterminals: # Initialize to the empty set: for n in self.Nonterminals: self.First[n] = [] # Then propagate symbols until no change: while 1: some_change = 0 for n in self.Nonterminals: for p in self.Prodnames[n]: for f in self._first(p.prod): if f not in self.First[n]: self.First[n].append( f ) some_change = 1 if not some_change: break return self.First # --------------------------------------------------------------------- # compute_follow() # # Computes all of the follow sets for every non-terminal symbol. The # follow set is the set of all symbols that might follow a given # non-terminal. See the Dragon book, 2nd Ed. p. 189. # --------------------------------------------------------------------- def compute_follow(self,start=None): # If already computed, return the result if self.Follow: return self.Follow # If first sets not computed yet, do that first. if not self.First: self.compute_first() # Add '$end' to the follow list of the start symbol for k in self.Nonterminals: self.Follow[k] = [ ] if not start: start = self.Productions[1].name self.Follow[start] = [ '$end' ] while 1: didadd = 0 for p in self.Productions[1:]: # Here is the production set for i in range(len(p.prod)): B = p.prod[i] if B in self.Nonterminals: # Okay. We got a non-terminal in a production fst = self._first(p.prod[i+1:]) hasempty = 0 for f in fst: if f != '' and f not in self.Follow[B]: self.Follow[B].append(f) didadd = 1 if f == '': hasempty = 1 if hasempty or i == (len(p.prod)-1): # Add elements of follow(a) to follow(b) for f in self.Follow[p.name]: if f not in self.Follow[B]: self.Follow[B].append(f) didadd = 1 if not didadd: break return self.Follow # ----------------------------------------------------------------------------- # build_lritems() # # This function walks the list of productions and builds a complete set of the # LR items. The LR items are stored in two ways: First, they are uniquely # numbered and placed in the list _lritems. Second, a linked list of LR items # is built for each production. For example: # # E -> E PLUS E # # Creates the list # # [E -> . E PLUS E, E -> E . PLUS E, E -> E PLUS . E, E -> E PLUS E . ] # ----------------------------------------------------------------------------- def build_lritems(self): for p in self.Productions: lastlri = p i = 0 lr_items = [] while 1: if i > len(p): lri = None else: lri = LRItem(p,i) # Precompute the list of productions immediately following try: lri.lr_after = self.Prodnames[lri.prod[i+1]] except (IndexError,KeyError): lri.lr_after = [] try: lri.lr_before = lri.prod[i-1] except IndexError: lri.lr_before = None lastlri.lr_next = lri if not lri: break lr_items.append(lri) lastlri = lri i += 1 p.lr_items = lr_items # ----------------------------------------------------------------------------- # == Class LRTable == # # This basic class represents a basic table of LR parsing information. # Methods for generating the tables are not defined here. They are defined # in the derived class LRGeneratedTable. # ----------------------------------------------------------------------------- class VersionError(YaccError): pass class LRTable(object): def __init__(self): self.lr_action = None self.lr_goto = None self.lr_productions = None self.lr_method = None def read_table(self,module): if isinstance(module,types.ModuleType): parsetab = module else: if sys.version_info[0] < 3: exec("import %s as parsetab" % module) else: env = { } exec("import %s as parsetab" % module, env, env) parsetab = env['parsetab'] if parsetab._tabversion != __tabversion__: raise VersionError("yacc table file version is out of date") self.lr_action = parsetab._lr_action self.lr_goto = parsetab._lr_goto self.lr_productions = [] for p in parsetab._lr_productions: self.lr_productions.append(MiniProduction(*p)) self.lr_method = parsetab._lr_method return parsetab._lr_signature # Bind all production function names to callable objects in pdict def bind_callables(self,pdict): for p in self.lr_productions: p.bind(pdict) # ----------------------------------------------------------------------------- # === LR Generator === # # The following classes and functions are used to generate LR parsing tables on # a grammar. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # digraph() # traverse() # # The following two functions are used to compute set valued functions # of the form: # # F(x) = F'(x) U U{F(y) | x R y} # # This is used to compute the values of Read() sets as well as FOLLOW sets # in LALR(1) generation. # # Inputs: X - An input set # R - A relation # FP - Set-valued function # ------------------------------------------------------------------------------ def digraph(X,R,FP): N = { } for x in X: N[x] = 0 stack = [] F = { } for x in X: if N[x] == 0: traverse(x,N,stack,F,X,R,FP) return F def traverse(x,N,stack,F,X,R,FP): stack.append(x) d = len(stack) N[x] = d F[x] = FP(x) # F(X) <- F'(x) rel = R(x) # Get y's related to x for y in rel: if N[y] == 0: traverse(y,N,stack,F,X,R,FP) N[x] = min(N[x],N[y]) for a in F.get(y,[]): if a not in F[x]: F[x].append(a) if N[x] == d: N[stack[-1]] = MAXINT F[stack[-1]] = F[x] element = stack.pop() while element != x: N[stack[-1]] = MAXINT F[stack[-1]] = F[x] element = stack.pop() class LALRError(YaccError): pass # ----------------------------------------------------------------------------- # == LRGeneratedTable == # # This class implements the LR table generation algorithm. There are no # public methods except for write() # ----------------------------------------------------------------------------- class LRGeneratedTable(LRTable): def __init__(self,grammar,method='LALR',log=None): if method not in ['SLR','LALR']: raise LALRError("Unsupported method %s" % method) self.grammar = grammar self.lr_method = method # Set up the logger if not log: log = NullLogger() self.log = log # Internal attributes self.lr_action = {} # Action table self.lr_goto = {} # Goto table self.lr_productions = grammar.Productions # Copy of grammar Production array self.lr_goto_cache = {} # Cache of computed gotos self.lr0_cidhash = {} # Cache of closures self._add_count = 0 # Internal counter used to detect cycles # Diagonistic information filled in by the table generator self.sr_conflict = 0 self.rr_conflict = 0 self.conflicts = [] # List of conflicts self.sr_conflicts = [] self.rr_conflicts = [] # Build the tables self.grammar.build_lritems() self.grammar.compute_first() self.grammar.compute_follow() self.lr_parse_table() # Compute the LR(0) closure operation on I, where I is a set of LR(0) items. def lr0_closure(self,I): self._add_count += 1 # Add everything in I to J J = I[:] didadd = 1 while didadd: didadd = 0 for j in J: for x in j.lr_after: if getattr(x,"lr0_added",0) == self._add_count: continue # Add B --> .G to J J.append(x.lr_next) x.lr0_added = self._add_count didadd = 1 return J # Compute the LR(0) goto function goto(I,X) where I is a set # of LR(0) items and X is a grammar symbol. This function is written # in a way that guarantees uniqueness of the generated goto sets # (i.e. the same goto set will never be returned as two different Python # objects). With uniqueness, we can later do fast set comparisons using # id(obj) instead of element-wise comparison. def lr0_goto(self,I,x): # First we look for a previously cached entry g = self.lr_goto_cache.get((id(I),x),None) if g: return g # Now we generate the goto set in a way that guarantees uniqueness # of the result s = self.lr_goto_cache.get(x,None) if not s: s = { } self.lr_goto_cache[x] = s gs = [ ] for p in I: n = p.lr_next if n and n.lr_before == x: s1 = s.get(id(n),None) if not s1: s1 = { } s[id(n)] = s1 gs.append(n) s = s1 g = s.get('$end',None) if not g: if gs: g = self.lr0_closure(gs) s['$end'] = g else: s['$end'] = gs self.lr_goto_cache[(id(I),x)] = g return g # Compute the LR(0) sets of item function def lr0_items(self): C = [ self.lr0_closure([self.grammar.Productions[0].lr_next]) ] i = 0 for I in C: self.lr0_cidhash[id(I)] = i i += 1 # Loop over the items in C and each grammar symbols i = 0 while i < len(C): I = C[i] i += 1 # Collect all of the symbols that could possibly be in the goto(I,X) sets asyms = { } for ii in I: for s in ii.usyms: asyms[s] = None for x in asyms: g = self.lr0_goto(I,x) if not g: continue if id(g) in self.lr0_cidhash: continue self.lr0_cidhash[id(g)] = len(C) C.append(g) return C # ----------------------------------------------------------------------------- # ==== LALR(1) Parsing ==== # # LALR(1) parsing is almost exactly the same as SLR except that instead of # relying upon Follow() sets when performing reductions, a more selective # lookahead set that incorporates the state of the LR(0) machine is utilized. # Thus, we mainly just have to focus on calculating the lookahead sets. # # The method used here is due to DeRemer and Pennelo (1982). # # DeRemer, F. L., and T. J. Pennelo: "Efficient Computation of LALR(1) # Lookahead Sets", ACM Transactions on Programming Languages and Systems, # Vol. 4, No. 4, Oct. 1982, pp. 615-649 # # Further details can also be found in: # # J. Tremblay and P. Sorenson, "The Theory and Practice of Compiler Writing", # McGraw-Hill Book Company, (1985). # # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # compute_nullable_nonterminals() # # Creates a dictionary containing all of the non-terminals that might produce # an empty production. # ----------------------------------------------------------------------------- def compute_nullable_nonterminals(self): nullable = {} num_nullable = 0 while 1: for p in self.grammar.Productions[1:]: if p.len == 0: nullable[p.name] = 1 continue for t in p.prod: if not t in nullable: break else: nullable[p.name] = 1 if len(nullable) == num_nullable: break num_nullable = len(nullable) return nullable # ----------------------------------------------------------------------------- # find_nonterminal_trans(C) # # Given a set of LR(0) items, this functions finds all of the non-terminal # transitions. These are transitions in which a dot appears immediately before # a non-terminal. Returns a list of tuples of the form (state,N) where state # is the state number and N is the nonterminal symbol. # # The input C is the set of LR(0) items. # ----------------------------------------------------------------------------- def find_nonterminal_transitions(self,C): trans = [] for state in range(len(C)): for p in C[state]: if p.lr_index < p.len - 1: t = (state,p.prod[p.lr_index+1]) if t[1] in self.grammar.Nonterminals: if t not in trans: trans.append(t) state = state + 1 return trans # ----------------------------------------------------------------------------- # dr_relation() # # Computes the DR(p,A) relationships for non-terminal transitions. The input # is a tuple (state,N) where state is a number and N is a nonterminal symbol. # # Returns a list of terminals. # ----------------------------------------------------------------------------- def dr_relation(self,C,trans,nullable): dr_set = { } state,N = trans terms = [] g = self.lr0_goto(C[state],N) for p in g: if p.lr_index < p.len - 1: a = p.prod[p.lr_index+1] if a in self.grammar.Terminals: if a not in terms: terms.append(a) # This extra bit is to handle the start state if state == 0 and N == self.grammar.Productions[0].prod[0]: terms.append('$end') return terms # ----------------------------------------------------------------------------- # reads_relation() # # Computes the READS() relation (p,A) READS (t,C). # ----------------------------------------------------------------------------- def reads_relation(self,C, trans, empty): # Look for empty transitions rel = [] state, N = trans g = self.lr0_goto(C[state],N) j = self.lr0_cidhash.get(id(g),-1) for p in g: if p.lr_index < p.len - 1: a = p.prod[p.lr_index + 1] if a in empty: rel.append((j,a)) return rel # ----------------------------------------------------------------------------- # compute_lookback_includes() # # Determines the lookback and includes relations # # LOOKBACK: # # This relation is determined by running the LR(0) state machine forward. # For example, starting with a production "N : . A B C", we run it forward # to obtain "N : A B C ." We then build a relationship between this final # state and the starting state. These relationships are stored in a dictionary # lookdict. # # INCLUDES: # # Computes the INCLUDE() relation (p,A) INCLUDES (p',B). # # This relation is used to determine non-terminal transitions that occur # inside of other non-terminal transition states. (p,A) INCLUDES (p', B) # if the following holds: # # B -> LAT, where T -> epsilon and p' -L-> p # # L is essentially a prefix (which may be empty), T is a suffix that must be # able to derive an empty string. State p' must lead to state p with the string L. # # ----------------------------------------------------------------------------- def compute_lookback_includes(self,C,trans,nullable): lookdict = {} # Dictionary of lookback relations includedict = {} # Dictionary of include relations # Make a dictionary of non-terminal transitions dtrans = {} for t in trans: dtrans[t] = 1 # Loop over all transitions and compute lookbacks and includes for state,N in trans: lookb = [] includes = [] for p in C[state]: if p.name != N: continue # Okay, we have a name match. We now follow the production all the way # through the state machine until we get the . on the right hand side lr_index = p.lr_index j = state while lr_index < p.len - 1: lr_index = lr_index + 1 t = p.prod[lr_index] # Check to see if this symbol and state are a non-terminal transition if (j,t) in dtrans: # Yes. Okay, there is some chance that this is an includes relation # the only way to know for certain is whether the rest of the # production derives empty li = lr_index + 1 while li < p.len: if p.prod[li] in self.grammar.Terminals: break # No forget it if not p.prod[li] in nullable: break li = li + 1 else: # Appears to be a relation between (j,t) and (state,N) includes.append((j,t)) g = self.lr0_goto(C[j],t) # Go to next set j = self.lr0_cidhash.get(id(g),-1) # Go to next state # When we get here, j is the final state, now we have to locate the production for r in C[j]: if r.name != p.name: continue if r.len != p.len: continue i = 0 # This look is comparing a production ". A B C" with "A B C ." while i < r.lr_index: if r.prod[i] != p.prod[i+1]: break i = i + 1 else: lookb.append((j,r)) for i in includes: if not i in includedict: includedict[i] = [] includedict[i].append((state,N)) lookdict[(state,N)] = lookb return lookdict,includedict # ----------------------------------------------------------------------------- # compute_read_sets() # # Given a set of LR(0) items, this function computes the read sets. # # Inputs: C = Set of LR(0) items # ntrans = Set of nonterminal transitions # nullable = Set of empty transitions # # Returns a set containing the read sets # ----------------------------------------------------------------------------- def compute_read_sets(self,C, ntrans, nullable): FP = lambda x: self.dr_relation(C,x,nullable) R = lambda x: self.reads_relation(C,x,nullable) F = digraph(ntrans,R,FP) return F # ----------------------------------------------------------------------------- # compute_follow_sets() # # Given a set of LR(0) items, a set of non-terminal transitions, a readset, # and an include set, this function computes the follow sets # # Follow(p,A) = Read(p,A) U U {Follow(p',B) | (p,A) INCLUDES (p',B)} # # Inputs: # ntrans = Set of nonterminal transitions # readsets = Readset (previously computed) # inclsets = Include sets (previously computed) # # Returns a set containing the follow sets # ----------------------------------------------------------------------------- def compute_follow_sets(self,ntrans,readsets,inclsets): FP = lambda x: readsets[x] R = lambda x: inclsets.get(x,[]) F = digraph(ntrans,R,FP) return F # ----------------------------------------------------------------------------- # add_lookaheads() # # Attaches the lookahead symbols to grammar rules. # # Inputs: lookbacks - Set of lookback relations # followset - Computed follow set # # This function directly attaches the lookaheads to productions contained # in the lookbacks set # ----------------------------------------------------------------------------- def add_lookaheads(self,lookbacks,followset): for trans,lb in lookbacks.items(): # Loop over productions in lookback for state,p in lb: if not state in p.lookaheads: p.lookaheads[state] = [] f = followset.get(trans,[]) for a in f: if a not in p.lookaheads[state]: p.lookaheads[state].append(a) # ----------------------------------------------------------------------------- # add_lalr_lookaheads() # # This function does all of the work of adding lookahead information for use # with LALR parsing # ----------------------------------------------------------------------------- def add_lalr_lookaheads(self,C): # Determine all of the nullable nonterminals nullable = self.compute_nullable_nonterminals() # Find all non-terminal transitions trans = self.find_nonterminal_transitions(C) # Compute read sets readsets = self.compute_read_sets(C,trans,nullable) # Compute lookback/includes relations lookd, included = self.compute_lookback_includes(C,trans,nullable) # Compute LALR FOLLOW sets followsets = self.compute_follow_sets(trans,readsets,included) # Add all of the lookaheads self.add_lookaheads(lookd,followsets) # ----------------------------------------------------------------------------- # lr_parse_table() # # This function constructs the parse tables for SLR or LALR # ----------------------------------------------------------------------------- def lr_parse_table(self): goto = self.lr_goto # Goto array action = self.lr_action # Action array log = self.log # Logger for output actionp = { } # Action production array (temporary) log.info("Parsing method: %s", self.lr_method) # Step 1: Construct C = { I0, I1, ... IN}, collection of LR(0) items # This determines the number of states C = self.lr0_items() if self.lr_method == 'LALR': self.add_lalr_lookaheads(C) # Build the parser table, state by state st = 0 for I in C: # Loop over each production in I actlist = [ ] # List of actions st_action = { } st_actionp = { } st_goto = { } log.info("") log.info("state %d", st) log.info("") for p in I: log.info(" (%d) %s", p.number, str(p)) log.info("") for p in I: if p.len == p.lr_index + 1: if p.name == "S'": # Start symbol. Accept! st_action["$end"] = 0 st_actionp["$end"] = p else: # We are at the end of a production. Reduce! if self.lr_method == 'LALR': laheads = p.lookaheads[st] else: laheads = self.grammar.Follow[p.name] for a in laheads: actlist.append((a,p,"reduce using rule %d (%s)" % (p.number,p))) r = st_action.get(a,None) if r is not None: # Whoa. Have a shift/reduce or reduce/reduce conflict if r > 0: # Need to decide on shift or reduce here # By default we favor shifting. Need to add # some precedence rules here. sprec,slevel = self.grammar.Productions[st_actionp[a].number].prec rprec,rlevel = self.grammar.Precedence.get(a,('right',0)) if (slevel < rlevel) or ((slevel == rlevel) and (rprec == 'left')): # We really need to reduce here. st_action[a] = -p.number st_actionp[a] = p if not slevel and not rlevel: log.info(" ! shift/reduce conflict for %s resolved as reduce",a) self.sr_conflicts.append((st,a,'reduce')) elif (slevel == rlevel) and (rprec == 'nonassoc'): st_action[a] = None else: # Hmmm. Guess we'll keep the shift if not rlevel: log.info(" ! shift/reduce conflict for %s resolved as shift",a) self.sr_conflicts.append((st,a,'shift')) elif r < 0: # Reduce/reduce conflict. In this case, we favor the rule # that was defined first in the grammar file oldp = self.grammar.Productions[-r] pp = self.grammar.Productions[p.number] if oldp.line > pp.line: st_action[a] = -p.number st_actionp[a] = p chosenp,rejectp = pp,oldp else: chosenp,rejectp = oldp,pp self.rr_conflicts.append((st,chosenp,rejectp)) log.info(" ! reduce/reduce conflict for %s resolved using rule %d (%s)", a,st_actionp[a].number, st_actionp[a]) else: raise LALRError("Unknown conflict in state %d" % st) else: st_action[a] = -p.number st_actionp[a] = p else: i = p.lr_index a = p.prod[i+1] # Get symbol right after the "." if a in self.grammar.Terminals: g = self.lr0_goto(I,a) j = self.lr0_cidhash.get(id(g),-1) if j >= 0: # We are in a shift state actlist.append((a,p,"shift and go to state %d" % j)) r = st_action.get(a,None) if r is not None: # Whoa have a shift/reduce or shift/shift conflict if r > 0: if r != j: raise LALRError("Shift/shift conflict in state %d" % st) elif r < 0: # Do a precedence check. # - if precedence of reduce rule is higher, we reduce. # - if precedence of reduce is same and left assoc, we reduce. # - otherwise we shift rprec,rlevel = self.grammar.Productions[st_actionp[a].number].prec sprec,slevel = self.grammar.Precedence.get(a,('right',0)) if (slevel > rlevel) or ((slevel == rlevel) and (rprec == 'right')): # We decide to shift here... highest precedence to shift st_action[a] = j st_actionp[a] = p if not rlevel: log.info(" ! shift/reduce conflict for %s resolved as shift",a) self.sr_conflicts.append((st,a,'shift')) elif (slevel == rlevel) and (rprec == 'nonassoc'): st_action[a] = None else: # Hmmm. Guess we'll keep the reduce if not slevel and not rlevel: log.info(" ! shift/reduce conflict for %s resolved as reduce",a) self.sr_conflicts.append((st,a,'reduce')) else: raise LALRError("Unknown conflict in state %d" % st) else: st_action[a] = j st_actionp[a] = p # Print the actions associated with each terminal _actprint = { } for a,p,m in actlist: if a in st_action: if p is st_actionp[a]: log.info(" %-15s %s",a,m) _actprint[(a,m)] = 1 log.info("") # Print the actions that were not used. (debugging) not_used = 0 for a,p,m in actlist: if a in st_action: if p is not st_actionp[a]: if not (a,m) in _actprint: log.debug(" ! %-15s [ %s ]",a,m) not_used = 1 _actprint[(a,m)] = 1 if not_used: log.debug("") # Construct the goto table for this state nkeys = { } for ii in I: for s in ii.usyms: if s in self.grammar.Nonterminals: nkeys[s] = None for n in nkeys: g = self.lr0_goto(I,n) j = self.lr0_cidhash.get(id(g),-1) if j >= 0: st_goto[n] = j log.info(" %-30s shift and go to state %d",n,j) action[st] = st_action actionp[st] = st_actionp goto[st] = st_goto st += 1 # ----------------------------------------------------------------------------- # write() # # This function writes the LR parsing tables to a file # ----------------------------------------------------------------------------- def write_table(self,modulename,outputdir='',signature=""): basemodulename = modulename.split(".")[-1] filename = os.path.join(outputdir,basemodulename) + ".py" try: f = open(filename,"w") f.write(""" # %s # This file is automatically generated. Do not edit. _tabversion = %r _lr_method = %r _lr_signature = %r """ % (filename, __tabversion__, self.lr_method, signature)) # Change smaller to 0 to go back to original tables smaller = 1 # Factor out names to try and make smaller if smaller: items = { } for s,nd in self.lr_action.items(): for name,v in nd.items(): i = items.get(name) if not i: i = ([],[]) items[name] = i i[0].append(s) i[1].append(v) f.write("\n_lr_action_items = {") for k,v in items.items(): f.write("%r:([" % k) for i in v[0]: f.write("%r," % i) f.write("],[") for i in v[1]: f.write("%r," % i) f.write("]),") f.write("}\n") f.write(""" _lr_action = { } for _k, _v in _lr_action_items.items(): for _x,_y in zip(_v[0],_v[1]): if not _x in _lr_action: _lr_action[_x] = { } _lr_action[_x][_k] = _y del _lr_action_items """) else: f.write("\n_lr_action = { "); for k,v in self.lr_action.items(): f.write("(%r,%r):%r," % (k[0],k[1],v)) f.write("}\n"); if smaller: # Factor out names to try and make smaller items = { } for s,nd in self.lr_goto.items(): for name,v in nd.items(): i = items.get(name) if not i: i = ([],[]) items[name] = i i[0].append(s) i[1].append(v) f.write("\n_lr_goto_items = {") for k,v in items.items(): f.write("%r:([" % k) for i in v[0]: f.write("%r," % i) f.write("],[") for i in v[1]: f.write("%r," % i) f.write("]),") f.write("}\n") f.write(""" _lr_goto = { } for _k, _v in _lr_goto_items.items(): for _x,_y in zip(_v[0],_v[1]): if not _x in _lr_goto: _lr_goto[_x] = { } _lr_goto[_x][_k] = _y del _lr_goto_items """) else: f.write("\n_lr_goto = { "); for k,v in self.lr_goto.items(): f.write("(%r,%r):%r," % (k[0],k[1],v)) f.write("}\n"); # Write production table f.write("_lr_productions = [\n") for p in self.lr_productions: if p.func: f.write(" (%r,%r,%d,%r,%r,%d),\n" % (p.str,p.name, p.len, p.func,p.file,p.line)) else: f.write(" (%r,%r,%d,None,None,None),\n" % (str(p),p.name, p.len)) f.write("]\n") f.close() except IOError: e = sys.exc_info()[1] sys.stderr.write("Unable to create '%s'\n" % filename) sys.stderr.write(str(e)+"\n") return # ----------------------------------------------------------------------------- # === INTROSPECTION === # # The following functions and classes are used to implement the PLY # introspection features followed by the yacc() function itself. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # get_caller_module_dict() # # This function returns a dictionary containing all of the symbols defined within # a caller further down the call stack. This is used to get the environment # associated with the yacc() call if none was provided. # ----------------------------------------------------------------------------- def get_caller_module_dict(levels): try: raise RuntimeError except RuntimeError: e,b,t = sys.exc_info() f = t.tb_frame while levels > 0: f = f.f_back levels -= 1 ldict = f.f_globals.copy() if f.f_globals != f.f_locals: ldict.update(f.f_locals) return ldict # ----------------------------------------------------------------------------- # parse_grammar() # # This takes a raw grammar rule string and parses it into production data # ----------------------------------------------------------------------------- def parse_grammar(doc,file,line): grammar = [] # Split the doc string into lines pstrings = doc.splitlines() lastp = None dline = line for ps in pstrings: dline += 1 p = ps.split() if not p: continue try: if p[0] == '|': # This is a continuation of a previous rule if not lastp: raise SyntaxError("%s:%d: Misplaced '|'" % (file,dline)) prodname = lastp syms = p[1:] else: prodname = p[0] lastp = prodname syms = p[2:] assign = p[1] if assign != ':' and assign != '::=': raise SyntaxError("%s:%d: Syntax error. Expected ':'" % (file,dline)) grammar.append((file,dline,prodname,syms)) except SyntaxError: raise except Exception: raise SyntaxError("%s:%d: Syntax error in rule '%s'" % (file,dline,ps.strip())) return grammar # ----------------------------------------------------------------------------- # ParserReflect() # # This class represents information extracted for building a parser including # start symbol, error function, tokens, precedence list, action functions, # etc. # ----------------------------------------------------------------------------- class ParserReflect(object): def __init__(self,pdict,log=None): self.pdict = pdict self.start = None self.error_func = None self.tokens = None self.files = {} self.grammar = [] self.error = 0 if log is None: self.log = PlyLogger(sys.stderr) else: self.log = log # Get all of the basic information def get_all(self): self.get_start() self.get_error_func() self.get_tokens() self.get_precedence() self.get_pfunctions() # Validate all of the information def validate_all(self): self.validate_start() self.validate_error_func() self.validate_tokens() self.validate_precedence() self.validate_pfunctions() self.validate_files() return self.error # Compute a signature over the grammar def signature(self): from binascii import crc32 sig = 0 try: if self.start: sig = crc32(self.start.encode('latin-1'),sig) if self.prec: sig = crc32("".join(["".join(p) for p in self.prec]).encode('latin-1'),sig) if self.tokens: sig = crc32(" ".join(self.tokens).encode('latin-1'),sig) for f in self.pfuncs: if f[3]: sig = crc32(f[3].encode('latin-1'),sig) except (TypeError,ValueError): pass return sig # ----------------------------------------------------------------------------- # validate_file() # # This method checks to see if there are duplicated p_rulename() functions # in the parser module file. Without this function, it is really easy for # users to make mistakes by cutting and pasting code fragments (and it's a real # bugger to try and figure out why the resulting parser doesn't work). Therefore, # we just do a little regular expression pattern matching of def statements # to try and detect duplicates. # ----------------------------------------------------------------------------- def validate_files(self): # Match def p_funcname( fre = re.compile(r'\s*def\s+(p_[a-zA-Z_0-9]*)\(') for filename in self.files.keys(): base,ext = os.path.splitext(filename) if ext != '.py': return 1 # No idea. Assume it's okay. try: f = open(filename) lines = f.readlines() f.close() except IOError: continue counthash = { } for linen,l in enumerate(lines): linen += 1 m = fre.match(l) if m: name = m.group(1) prev = counthash.get(name) if not prev: counthash[name] = linen else: self.log.warning("%s:%d: Function %s redefined. Previously defined on line %d", filename,linen,name,prev) # Get the start symbol def get_start(self): self.start = self.pdict.get('start') # Validate the start symbol def validate_start(self): if self.start is not None: if not isinstance(self.start,str): self.log.error("'start' must be a string") # Look for error handler def get_error_func(self): self.error_func = self.pdict.get('p_error') # Validate the error function def validate_error_func(self): if self.error_func: if isinstance(self.error_func,types.FunctionType): ismethod = 0 elif isinstance(self.error_func, types.MethodType): ismethod = 1 else: self.log.error("'p_error' defined, but is not a function or method") self.error = 1 return eline = func_code(self.error_func).co_firstlineno efile = func_code(self.error_func).co_filename self.files[efile] = 1 if (func_code(self.error_func).co_argcount != 1+ismethod): self.log.error("%s:%d: p_error() requires 1 argument",efile,eline) self.error = 1 # Get the tokens map def get_tokens(self): tokens = self.pdict.get("tokens",None) if not tokens: self.log.error("No token list is defined") self.error = 1 return if not isinstance(tokens,(list, tuple)): self.log.error("tokens must be a list or tuple") self.error = 1 return if not tokens: self.log.error("tokens is empty") self.error = 1 return self.tokens = tokens # Validate the tokens def validate_tokens(self): # Validate the tokens. if 'error' in self.tokens: self.log.error("Illegal token name 'error'. Is a reserved word") self.error = 1 return terminals = {} for n in self.tokens: if n in terminals: self.log.warning("Token '%s' multiply defined", n) terminals[n] = 1 # Get the precedence map (if any) def get_precedence(self): self.prec = self.pdict.get("precedence",None) # Validate and parse the precedence map def validate_precedence(self): preclist = [] if self.prec: if not isinstance(self.prec,(list,tuple)): self.log.error("precedence must be a list or tuple") self.error = 1 return for level,p in enumerate(self.prec): if not isinstance(p,(list,tuple)): self.log.error("Bad precedence table") self.error = 1 return if len(p) < 2: self.log.error("Malformed precedence entry %s. Must be (assoc, term, ..., term)",p) self.error = 1 return assoc = p[0] if not isinstance(assoc,str): self.log.error("precedence associativity must be a string") self.error = 1 return for term in p[1:]: if not isinstance(term,str): self.log.error("precedence items must be strings") self.error = 1 return preclist.append((term,assoc,level+1)) self.preclist = preclist # Get all p_functions from the grammar def get_pfunctions(self): p_functions = [] for name, item in self.pdict.items(): if name[:2] != 'p_': continue if name == 'p_error': continue if isinstance(item,(types.FunctionType,types.MethodType)): line = func_code(item).co_firstlineno file = func_code(item).co_filename p_functions.append((line,file,name,item.__doc__)) # Sort all of the actions by line number p_functions.sort() self.pfuncs = p_functions # Validate all of the p_functions def validate_pfunctions(self): grammar = [] # Check for non-empty symbols if len(self.pfuncs) == 0: self.log.error("no rules of the form p_rulename are defined") self.error = 1 return for line, file, name, doc in self.pfuncs: func = self.pdict[name] if isinstance(func, types.MethodType): reqargs = 2 else: reqargs = 1 if func_code(func).co_argcount > reqargs: self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,func.__name__) self.error = 1 elif func_code(func).co_argcount < reqargs: self.log.error("%s:%d: Rule '%s' requires an argument",file,line,func.__name__) self.error = 1 elif not func.__doc__: self.log.warning("%s:%d: No documentation string specified in function '%s' (ignored)",file,line,func.__name__) else: try: parsed_g = parse_grammar(doc,file,line) for g in parsed_g: grammar.append((name, g)) except SyntaxError: e = sys.exc_info()[1] self.log.error(str(e)) self.error = 1 # Looks like a valid grammar rule # Mark the file in which defined. self.files[file] = 1 # Secondary validation step that looks for p_ definitions that are not functions # or functions that look like they might be grammar rules. for n,v in self.pdict.items(): if n[0:2] == 'p_' and isinstance(v, (types.FunctionType, types.MethodType)): continue if n[0:2] == 't_': continue if n[0:2] == 'p_' and n != 'p_error': self.log.warning("'%s' not defined as a function", n) if ((isinstance(v,types.FunctionType) and func_code(v).co_argcount == 1) or (isinstance(v,types.MethodType) and func_code(v).co_argcount == 2)): try: doc = v.__doc__.split(" ") if doc[1] == ':': self.log.warning("%s:%d: Possible grammar rule '%s' defined without p_ prefix", func_code(v).co_filename, func_code(v).co_firstlineno,n) except Exception: pass self.grammar = grammar # ----------------------------------------------------------------------------- # yacc(module) # # Build a parser # ----------------------------------------------------------------------------- def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, start=None, check_recursion=1, optimize=0, write_tables=1, debugfile=debug_file,outputdir='', debuglog=None, errorlog = None): global parse # Reference to the parsing method of the last built parser if errorlog is None: errorlog = PlyLogger(sys.stderr) # Get the module dictionary used for the parser if module: _items = [(k,getattr(module,k)) for k in dir(module)] pdict = dict(_items) else: pdict = get_caller_module_dict(2) # Collect parser information from the dictionary pinfo = ParserReflect(pdict,log=errorlog) pinfo.get_all() if pinfo.error: raise YaccError("Unable to build parser") # Check signature against table files (if any) signature = pinfo.signature() # Read the tables try: lr = LRTable() read_signature = lr.read_table(tabmodule) if optimize or (read_signature == signature): try: lr.bind_callables(pinfo.pdict) parser = LRParser(lr,pinfo.error_func) parse = parser.parse return parser except Exception: e = sys.exc_info()[1] errorlog.warning("There was a problem loading the table file: %s", repr(e)) except VersionError: e = sys.exc_info() errorlog.warning(str(e)) except Exception: pass if debuglog is None: if debug: debuglog = PlyLogger(open(debugfile,"w")) else: debuglog = NullLogger() debuglog.info("Created by PLY version %s (http://www.dabeaz.com/ply)", __version__) errors = 0 # Validate the parser information if pinfo.validate_all(): raise YaccError("Unable to build parser") if not pinfo.error_func: errorlog.warning("no p_error() function is defined") # Create a grammar object grammar = Grammar(pinfo.tokens) # Set precedence level for terminals for term, assoc, level in pinfo.preclist: try: grammar.set_precedence(term,assoc,level) except GrammarError: e = sys.exc_info()[1] errorlog.warning("%s",str(e)) # Add productions to the grammar for funcname, gram in pinfo.grammar: file, line, prodname, syms = gram try: grammar.add_production(prodname,syms,funcname,file,line) except GrammarError: e = sys.exc_info()[1] errorlog.error("%s",str(e)) errors = 1 # Set the grammar start symbols try: grammar.set_start(pinfo.start) except GrammarError: e = sys.exc_info()[1] errorlog.error(str(e)) errors = 1 if errors: raise YaccError("Unable to build parser") # Verify the grammar structure undefined_symbols = grammar.undefined_symbols() for sym, prod in undefined_symbols: errorlog.error("%s:%d: Symbol '%s' used, but not defined as a token or a rule",prod.file,prod.line,sym) errors = 1 unused_terminals = grammar.unused_terminals() if unused_terminals: debuglog.info("") debuglog.info("Unused terminals:") debuglog.info("") for term in unused_terminals: errorlog.warning("Token '%s' defined, but not used", term) debuglog.info(" %s", term) # Print out all productions to the debug log if debug: debuglog.info("") debuglog.info("Grammar") debuglog.info("") for n,p in enumerate(grammar.Productions): debuglog.info("Rule %-5d %s", n+1, p) # Find unused non-terminals unused_rules = grammar.unused_rules() for prod in unused_rules: errorlog.warning("%s:%d: Rule '%s' defined, but not used", prod.file, prod.line, prod.name) if len(unused_terminals) == 1: errorlog.warning("There is 1 unused token") if len(unused_terminals) > 1: errorlog.warning("There are %d unused tokens", len(unused_terminals)) if len(unused_rules) == 1: errorlog.warning("There is 1 unused rule") if len(unused_rules) > 1: errorlog.warning("There are %d unused rules", len(unused_rules)) if debug: debuglog.info("") debuglog.info("Terminals, with rules where they appear") debuglog.info("") terms = list(grammar.Terminals) terms.sort() for term in terms: debuglog.info("%-20s : %s", term, " ".join([str(s) for s in grammar.Terminals[term]])) debuglog.info("") debuglog.info("Nonterminals, with rules where they appear") debuglog.info("") nonterms = list(grammar.Nonterminals) nonterms.sort() for nonterm in nonterms: debuglog.info("%-20s : %s", nonterm, " ".join([str(s) for s in grammar.Nonterminals[nonterm]])) debuglog.info("") if check_recursion: unreachable = grammar.find_unreachable() for u in unreachable: errorlog.warning("Symbol '%s' is unreachable",u) infinite = grammar.infinite_cycles() for inf in infinite: errorlog.error("Infinite recursion detected for symbol '%s'", inf) errors = 1 unused_prec = grammar.unused_precedence() for term, assoc in unused_prec: errorlog.error("Precedence rule '%s' defined for unknown symbol '%s'", assoc, term) errors = 1 if errors: raise YaccError("Unable to build parser") # Run the LRGeneratedTable on the grammar if debug: errorlog.debug("Generating %s tables", method) lr = LRGeneratedTable(grammar,method,debuglog) num_sr = len(lr.sr_conflicts) # Report shift/reduce and reduce/reduce conflicts if num_sr == 1: errorlog.warning("1 shift/reduce conflict") elif num_sr > 1: errorlog.warning("%d shift/reduce conflicts", num_sr) num_rr = len(lr.rr_conflicts) if num_rr == 1: errorlog.warning("1 reduce/reduce conflict") elif num_rr > 1: errorlog.warning("%d reduce/reduce conflicts", num_rr) # Write out conflicts to the output file if debug and (lr.sr_conflicts or lr.rr_conflicts): debuglog.warning("") debuglog.warning("Conflicts:") debuglog.warning("") for state, tok, resolution in lr.sr_conflicts: debuglog.warning("shift/reduce conflict for %s in state %d resolved as %s", tok, state, resolution) for state, rule, rejected in lr.rr_conflicts: debuglog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule) debuglog.warning("rejected rule (%s)", rejected) errorlog.warning("reduce/reduce conflict in state %d resolved using rule (%s)", state, rule) errorlog.warning("rejected rule (%s)", rejected) # Write the table file if requested if write_tables: lr.write_table(tabmodule,outputdir,signature) # Build the parser lr.bind_callables(pinfo.pdict) parser = LRParser(lr,pinfo.error_func) parse = parser.parse return parser pywbem-0.8.0~dev/pywbem/cim_operations.py0000644000175000017500000007743212413747174020530 0ustar bzedbzed00000000000000# # (C) Copyright 2003-2007 Hewlett-Packard Development Company, L.P. # (C) Copyright 2006-2007 Novell, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter # Martin Pool # Bart Whiteley # This is meant to be safe for import *; ie the only global names # should be ones that all clients can see. import sys, string from types import StringTypes from xml.dom import minidom from datetime import datetime, timedelta from pywbem import cim_obj, cim_xml, cim_http, cim_types from pywbem.cim_obj import CIMClassName, CIMInstanceName, CIMInstance, CIMClass, NocaseDict from pywbem.tupletree import dom_to_tupletree, xml_to_tupletree from pywbem.tupleparse import parse_cim """CIM-XML/HTTP operations. The WBEMConnection class opens a connection to a remote WBEM server. Across this you can run various CIM operations. Each method of this object corresponds fairly directly to a single CIM method call. """ DEFAULT_NAMESPACE = 'root/cimv2' # TODO: Many methods have more parameters that aren't set yet. # helper functions for validating arguments def _check_classname(val): if not isinstance(val, StringTypes): raise ValueError("string expected for classname, not %s" % `val`) class CIMError(Exception): """Raised when something bad happens. The associated value is a tuple of (error_code, description). An error code of zero indicates an XML parsing error in PyWBEM.""" class WBEMConnection(object): """Class representing a client's connection to a WBEM server. At the moment there is no persistent TCP connection; the connectedness is only conceptual. After creating a connection, various methods may be called on the object, which causes a remote call to the server. All these operations take regular Python or cim_types values for parameters, and return the same. The caller should not need to know about the XML encoding. (It should be possible to use a different transport below this layer without disturbing any clients.) The connection remembers the XML for the last request and last reply. This may be useful in debugging: if a problem occurs, you can examine the last_request and last_reply fields of the connection. These are the prettified request and response; the real request is sent without indents so as not to corrupt whitespace. The caller may also register callback functions which are passed the request before it is sent, and the reply before it is unpacked. verify_callback is used to verify the server certificate. It is passed to M2Crypto.SSL.Context.set_verify, and is called during the SSL handshake. verify_callback should take five arguments: An SSL Context object, an X509 object, and three integer variables, which are in turn potential error number, error depth and return code. verify_callback should return True if verification passes and False otherwise. The value of the x509 argument is used only when the url contains 'https'. x509 must be a dictionary containing the keys 'cert_file' and 'key_file'. The value of 'cert_file' must consist of the filename of an certificate and the value of 'key_file' must consist of a filename containing the private key belonging to the public key that is part of the certificate in cert_file. ca_certs specifies where CA certificates for verification purposes are located. These are trusted certificates. Note that the certificates have to be in PEM format. Either it is a directory prepared using the c_rehash tool included with OpenSSL or an pemfile. If None, default system path will be used. no_verification allows to disable peer's verification. This is insecure and should be avoided. If True, peer's certificate is not verified and ca_certs argument is ignored. """ def __init__(self, url, creds = None, default_namespace = DEFAULT_NAMESPACE, x509 = None, verify_callback = None, ca_certs = None, no_verification = False): self.url = url self.creds = creds self.x509 = x509 self.verify_callback = verify_callback self.ca_certs = ca_certs self.no_verification = no_verification self.last_request = self.last_reply = '' self.default_namespace = default_namespace self.debug = False def __repr__(self): if self.creds is None: user = 'anonymous' else: user = 'user=%s' % `self.creds[0]` return "%s(%s, %s, namespace=%s)" % (self.__class__.__name__, `self.url`, user, `self.default_namespace`) def imethodcall(self, methodname, namespace, **params): """Make an intrinsic method call. Returns a tupletree with a IRETURNVALUE element at the root. A CIMError exception is thrown if there was an error parsing the call response, or an ERROR element was returned. The parameters are automatically converted to the right CIM_XML objects. In general clients should call one of the method-specific methods of the connection, such as EnumerateInstanceNames, etc.""" # Create HTTP headers headers = ['CIMOperation: MethodCall', 'CIMMethod: %s' % methodname, cim_http.get_object_header(namespace)] # Create parameter list plist = map(lambda x: cim_xml.IPARAMVALUE(x[0], cim_obj.tocimxml(x[1])), params.items()) # Build XML request req_xml = cim_xml.CIM( cim_xml.MESSAGE( cim_xml.SIMPLEREQ( cim_xml.IMETHODCALL( methodname, cim_xml.LOCALNAMESPACEPATH( [cim_xml.NAMESPACE(ns) for ns in string.split(namespace, '/')]), plist)), '1001', '1.0'), '2.0', '2.0') if self.debug: self.last_raw_request = req_xml.toxml() self.last_request = req_xml.toprettyxml(indent=' ') # Reset replies in case we fail before they are set self.last_reply = None self.last_raw_reply = None # Get XML response try: resp_xml = cim_http.wbem_request(self.url, req_xml.toxml(), self.creds, headers, x509 = self.x509, verify_callback = self.verify_callback, ca_certs = self.ca_certs, no_verification = self.no_verification) except cim_http.AuthError: raise except cim_http.Error, arg: # Convert cim_http exceptions to CIMError exceptions raise CIMError(0, str(arg)) ## TODO: Perhaps only compute this if it's required? Should not be ## all that expensive. reply_dom = minidom.parseString(resp_xml) if self.debug: self.last_reply = reply_dom.toprettyxml(indent=' ') self.last_raw_reply = resp_xml # Parse response tt = parse_cim(dom_to_tupletree(reply_dom)) if tt[0] != 'CIM': raise CIMError(0, 'Expecting CIM element, got %s' % tt[0]) tt = tt[2] if tt[0] != 'MESSAGE': raise CIMError(0, 'Expecting MESSAGE element, got %s' % tt[0]) tt = tt[2] if len(tt) != 1 or tt[0][0] != 'SIMPLERSP': raise CIMError(0, 'Expecting one SIMPLERSP element') tt = tt[0][2] if tt[0] != 'IMETHODRESPONSE': raise CIMError( 0, 'Expecting IMETHODRESPONSE element, got %s' % tt[0]) if tt[1]['NAME'] != methodname: raise CIMError(0, 'Expecting attribute NAME=%s, got %s' % (methodname, tt[1]['NAME'])) tt = tt[2] # At this point we either have a IRETURNVALUE, ERROR element # or None if there was no child nodes of the IMETHODRESPONSE # element. if tt is None: return None if tt[0] == 'ERROR': code = int(tt[1]['CODE']) if tt[1].has_key('DESCRIPTION'): raise CIMError(code, tt[1]['DESCRIPTION']) raise CIMError(code, 'Error code %s' % tt[1]['CODE']) if tt[0] != 'IRETURNVALUE': raise CIMError(0, 'Expecting IRETURNVALUE element, got %s' % tt[0]) return tt def methodcall(self, methodname, localobject, **params): """Make an extrinsic method call. Returns a tupletree with a RETURNVALUE element at the root. A CIMError exception is thrown if there was an error parsing the call response, or an ERROR element was returned. The parameters are automatically converted to the right CIM_XML objects.""" # METHODCALL only takes a LOCALCLASSPATH or LOCALINSTANCEPATH if hasattr(localobject, 'host') and localobject.host is not None: localobject = localobject.copy() localobject.host = None # Create HTTP headers headers = ['CIMOperation: MethodCall', 'CIMMethod: %s' % methodname, cim_http.get_object_header(localobject)] # Create parameter list def paramtype(obj): """Return a string to be used as the CIMTYPE for a parameter.""" if isinstance(obj, cim_types.CIMType): return obj.cimtype elif type(obj) == bool: return 'boolean' elif isinstance(obj, StringTypes): return 'string' elif isinstance(obj, (datetime, timedelta)): return 'datetime' elif isinstance(obj, (CIMClassName, CIMInstanceName)): return 'reference' elif isinstance(obj, (CIMClass, CIMInstance)): return 'string' elif isinstance(obj, list): if obj: return paramtype(obj[0]) else: return None raise TypeError('Unsupported parameter type "%s"' % type(obj)) def paramvalue(obj): """Return a cim_xml node to be used as the value for a parameter.""" if isinstance(obj, (datetime, timedelta)): obj = cim_types.CIMDateTime(obj) if isinstance(obj, (cim_types.CIMType, bool, StringTypes)): return cim_xml.VALUE(cim_types.atomic_to_cim_xml(obj)) if isinstance(obj, (CIMClassName, CIMInstanceName)): return cim_xml.VALUE_REFERENCE(obj.tocimxml()) if isinstance(obj, (CIMClass, CIMInstance)): return cim_xml.VALUE(obj.tocimxml().toxml()) if isinstance(obj, list): if obj and isinstance(obj[0], (CIMClassName, CIMInstanceName)): return cim_xml.VALUE_REFARRAY([paramvalue(x) for x in obj]) return cim_xml.VALUE_ARRAY([paramvalue(x) for x in obj]) raise TypeError('Unsupported parameter type "%s"' % type(obj)) def is_embedded(obj): """Determine if an object requires an EmbeddedObject attribute""" if isinstance(obj,list) and obj: return is_embedded(obj[0]) elif isinstance(obj, CIMClass): return 'object' elif isinstance(obj, CIMInstance): return 'instance' return None plist = [cim_xml.PARAMVALUE(x[0], paramvalue(x[1]), paramtype(x[1]), embedded_object=is_embedded(x[1])) for x in params.items()] # Build XML request req_xml = cim_xml.CIM( cim_xml.MESSAGE( cim_xml.SIMPLEREQ( cim_xml.METHODCALL( methodname, localobject.tocimxml(), plist)), '1001', '1.0'), '2.0', '2.0') if self.debug: self.last_request = req_xml.toprettyxml(indent=' ') self.last_raw_request = req_xml.toxml() # Reset replies in case we fail before they are set self.last_reply = None self.last_raw_reply = None # Get XML response try: resp_xml = cim_http.wbem_request(self.url, req_xml.toxml(), self.creds, headers, x509 = self.x509, verify_callback = self.verify_callback, ca_certs = self.ca_certs, no_verification = self.no_verification) except cim_http.Error, arg: # Convert cim_http exceptions to CIMError exceptions raise CIMError(0, str(arg)) if self.debug: self.last_raw_reply = resp_xml resp_dom = minidom.parseString(resp_xml) self.last_reply = resp_dom.toprettyxml(indent=' ') tt = parse_cim(xml_to_tupletree(resp_xml)) if tt[0] != 'CIM': raise CIMError(0, 'Expecting CIM element, got %s' % tt[0]) tt = tt[2] if tt[0] != 'MESSAGE': raise CIMError(0, 'Expecting MESSAGE element, got %s' % tt[0]) tt = tt[2] if len(tt) != 1 or tt[0][0] != 'SIMPLERSP': raise CIMError(0, 'Expecting one SIMPLERSP element') tt = tt[0][2] if tt[0] != 'METHODRESPONSE': raise CIMError( 0, 'Expecting METHODRESPONSE element, got %s' % tt[0]) if tt[1]['NAME'] != methodname: raise CIMError(0, 'Expecting attribute NAME=%s, got %s' % (methodname, tt[1]['NAME'])) tt = tt[2] # At this point we have an optional RETURNVALUE and zero or # more PARAMVALUE elements representing output parameters. if len(tt) > 0 and tt[0][0] == 'ERROR': code = int(tt[0][1]['CODE']) if tt[0][1].has_key('DESCRIPTION'): raise CIMError(code, tt[0][1]['DESCRIPTION']) raise CIMError(code, 'Error code %s' % tt[0][1]['CODE']) return tt # # Instance provider API # def EnumerateInstanceNames(self, ClassName, namespace = None, **params): """Enumerate instance names of a given classname. Returns a list of CIMInstanceName objects.""" if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'EnumerateInstanceNames', namespace, ClassName = CIMClassName(ClassName), **params) names = [] if result is not None: names = result[2] [setattr(n, 'namespace', namespace) for n in names] return names def EnumerateInstances(self, ClassName, namespace = None, **params): """Enumerate instances of a given classname. Returns a list of CIMInstance objects with paths.""" if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'EnumerateInstances', namespace, ClassName = CIMClassName(ClassName), **params) instances = [] if result is not None: instances = result[2] [setattr(i.path, 'namespace', namespace) for i in instances] return instances def GetInstance(self, InstanceName, **params): """Fetch an instance given by instancename. Returns a CIMInstance object.""" # Strip off host and namespace to make this a "local" object iname = InstanceName.copy() iname.host = None iname.namespace = None if InstanceName.namespace is None: namespace = self.default_namespace else: namespace = InstanceName.namespace result = self.imethodcall( 'GetInstance', namespace, InstanceName = iname, **params) instance = result[2][0] instance.path = InstanceName instance.path.namespace = namespace return instance def DeleteInstance(self, InstanceName, **params): """Delete the instance given by instancename.""" # Strip off host and namespace to make this a "local" object iname = InstanceName.copy() iname.host = None iname.namespace = None if InstanceName.namespace is None: namespace = self.default_namespace else: namespace = InstanceName.namespace self.imethodcall( 'DeleteInstance', namespace, InstanceName = iname, **params) def CreateInstance(self, NewInstance, **params): """Create an instance. Returns the name for the instance.""" # Take namespace path from object parameter if NewInstance.path is not None and \ NewInstance.path.namespace is not None: namespace = NewInstance.path.namespace else: namespace = self.default_namespace # Strip off path to avoid producing a VALUE.NAMEDINSTANCE # element instead of an INSTANCE element. instance = NewInstance.copy() instance.path = None result = self.imethodcall( 'CreateInstance', namespace, NewInstance = instance, **params) name = result[2][0] name.namespace = namespace return name def ModifyInstance(self, ModifiedInstance, **params): """Modify properties of a named instance.""" # Must pass a named CIMInstance here (i.e path attribute set) if ModifiedInstance.path is None: raise ValueError( 'ModifiedInstance parameter must have path attribute set') # Take namespace path from object parameter if ModifiedInstance.path.namespace is None: namespace = self.default_namespace else: namespace = ModifiedInstance.path.namespace instance = ModifiedInstance.copy() instance.path.namespace = None self.imethodcall( 'ModifyInstance', namespace, ModifiedInstance = instance, **params) def ExecQuery(self, QueryLanguage, Query, namespace = None): if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'ExecQuery', namespace, QueryLanguage = QueryLanguage, Query = Query) instances = [] if result is not None: instances = [tt[2] for tt in result[2]] [setattr(i.path, 'namespace', namespace) for i in instances] return instances # # Schema management API # def _map_classname_param(self, params): """Convert string ClassName parameter to a CIMClassName.""" if params.has_key('ClassName') and \ isinstance(params['ClassName'], StringTypes): params['ClassName'] = cim_obj.CIMClassName(params['ClassName']) return params def EnumerateClassNames(self, namespace = None, **params): """Return a list of CIM class names. Names are returned as strings.""" params = self._map_classname_param(params) if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'EnumerateClassNames', namespace, **params) if result is None: return [] else: return map(lambda x: x.classname, result[2]) def EnumerateClasses(self, namespace = None, **params): """Return a list of CIM class objects.""" params = self._map_classname_param(params) if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'EnumerateClasses', namespace, **params) if result is None: return [] return result[2] def GetClass(self, ClassName, namespace = None, **params): """Return a CIMClass representing the named class.""" params = self._map_classname_param(params) if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'GetClass', namespace, ClassName = CIMClassName(ClassName), **params) return result[2][0] def DeleteClass(self, ClassName, namespace = None, **params): """Delete a class by class name.""" # UNSUPPORTED (but actually works) params = self._map_classname_param(params) if namespace is None: namespace = self.default_namespace self.imethodcall( 'DeleteClass', namespace, ClassName = CIMClassName(ClassName), **params) def ModifyClass(self, ModifiedClass, namespace = None, **params): """Modify a CIM class.""" # UNSUPPORTED if namespace is None: namespace = self.default_namespace self.imethodcall( 'ModifyClass', namespace, ModifiedClass = ModifiedClass, **params) def CreateClass(self, NewClass, namespace = None, **params): """Create a CIM class.""" # UNSUPPORTED if namespace is None: namespace = self.default_namespace self.imethodcall( 'CreateClass', namespace, NewClass = NewClass, **params) # # Association provider API # def _add_objectname_param(self, params, object): """Add an object name (either a class name or an instance name) to a dictionary of parameter names.""" if isinstance(object, (CIMClassName, CIMInstanceName)): params['ObjectName'] = object.copy() params['ObjectName'].namespace = None elif isinstance(object, StringTypes): params['ObjectName'] = CIMClassName(object) else: raise ValueError('Expecting a classname, CIMClassName or ' 'CIMInstanceName object') return params def _map_association_params(self, params): """Convert various convenience parameters and types into their correct form for passing to the imethodcall() function.""" # ResultClass and Role parameters that are strings should be # mapped to CIMClassName objects. if params.has_key('ResultClass') and \ isinstance(params['ResultClass'], StringTypes): params['ResultClass'] = cim_obj.CIMClassName(params['ResultClass']) if params.has_key('AssocClass') and \ isinstance(params['AssocClass'], StringTypes): params['AssocClass'] = cim_obj.CIMClassName(params['AssocClass']) return params def Associators(self, ObjectName, **params): """Enumerate CIM classes or instances that are associated to a particular source CIM Object. Pass a keyword parameter of 'ClassName' to return associators for a CIM class, pass 'InstanceName' to return the associators for a CIM instance.""" params = self._map_association_params(params) params = self._add_objectname_param(params, ObjectName) namespace = self.default_namespace if isinstance(ObjectName, CIMInstanceName) and \ ObjectName.namespace is not None: namespace = ObjectName.namespace result = self.imethodcall( 'Associators', namespace, **params) if result is None: return [] return map(lambda x: x[2], result[2]) def AssociatorNames(self, ObjectName, **params): """Enumerate the names of CIM classes or instances names that are associated to a particular source CIM Object. Pass a keyword parameter of 'ClassName' to return associator names for a CIM class, pass 'InstanceName' to return the associator names for a CIM instance. Returns a list of CIMInstanceName objects with the host and namespace attributes set.""" params = self._map_association_params(params) params = self._add_objectname_param(params, ObjectName) namespace = self.default_namespace if isinstance(ObjectName, CIMInstanceName) and \ ObjectName.namespace is not None: namespace = ObjectName.namespace result = self.imethodcall( 'AssociatorNames', namespace, **params) if result is None: return [] return map(lambda x: x[2], result[2]) def References(self, ObjectName, **params): """Enumerate the association objects that refer to a particular target CIM class or instance. Pass a keyword parameter of 'ClassName' to return associators for a CIM class, pass 'InstanceName' to return the associators for a CIM instance.""" params = self._map_association_params(params) params = self._add_objectname_param(params, ObjectName) namespace = self.default_namespace if isinstance(ObjectName, CIMInstanceName) and \ ObjectName.namespace is not None: namespace = ObjectName.namespace result = self.imethodcall( 'References', namespace, **params) if result is None: return [] return map(lambda x: x[2], result[2]) def ReferenceNames(self, ObjectName, **params): """Enumerate the name of association objects that refer to a particular target CIM class or instance. Pass a keyword parameter of 'ClassName' to return associators for a CIM class, pass 'InstanceName' to return the associators for a CIM instance.""" params = self._map_association_params(params) params = self._add_objectname_param(params, ObjectName) namespace = self.default_namespace if isinstance(ObjectName, CIMInstanceName) and \ ObjectName.namespace is not None: namespace = ObjectName.namespace result = self.imethodcall( 'ReferenceNames', namespace, **params) if result is None: return [] return map(lambda x: x[2], result[2]) # # Method provider API # def InvokeMethod(self, MethodName, ObjectName, **params): # Convert string to CIMClassName obj = ObjectName if isinstance(obj, StringTypes): obj = CIMClassName(obj, namespace = self.default_namespace) if isinstance(obj, CIMInstanceName) and obj.namespace is None: obj = ObjectName.copy() obj.namespace = self.default_namespace # Make the method call result = self.methodcall(MethodName, obj, **params) # Convert optional RETURNVALUE into a Python object returnvalue = None if len(result) > 0 and result[0][0] == 'RETURNVALUE': returnvalue = cim_obj.tocimobj(result[0][1]['PARAMTYPE'], result[0][2]) result = result[1:] # Convert zero or more PARAMVALUE elements into dictionary output_params = NocaseDict() for p in result: if p[1] == 'reference': output_params[p[0]] = p[2] else: output_params[p[0]] = cim_obj.tocimobj(p[1], p[2]) return returnvalue, output_params # # Qualifiers API # def EnumerateQualifiers(self, namespace = None, **params): """Enumerate qualifier declarations. Returns a list of CIMQualifier objects.""" if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'EnumerateQualifiers', namespace, **params) qualifiers = [] if result is not None: names = result[2] else: names = [] return names def GetQualifier(self, QualifierName, namespace = None, **params): """Retrieve a qualifier by name. Returns a CIMQualifier object.""" if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'GetQualifier', namespace, QualifierName = QualifierName, **params) if result is not None: names = result[2][0] return names def SetQualifier(self, QualifierDeclaration, namespace = None, **params): """Set a qualifier.""" if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'SetQualifier', namespace, QualifierDeclaration = QualifierDeclaration, **params) def DeleteQualifier(self, QualifierName, namespace = None, **params): """Delete a qualifier by name.""" if namespace is None: namespace = self.default_namespace result = self.imethodcall( 'DeleteQualifier', namespace, QualifierName = QualifierName, **params) def is_subclass(ch, ns, super, sub): """Determine if one class is a subclass of another Keyword Arguments: ch -- A CIMOMHandle. Either a pycimmb.CIMOMHandle or a pywbem.WBEMConnection. ns -- Namespace. super -- A string containing the super class name. sub -- The subclass. This can either be a string or a pywbem.CIMClass. """ lsuper = super.lower() if isinstance(sub, CIMClass): subname = sub.classname subclass = sub else: subname = sub subclass = None if subname.lower() == lsuper: return True if subclass is None: subclass = ch.GetClass(subname, ns, LocalOnly=True, IncludeQualifiers=False, PropertyList=[], IncludeClassOrigin=False) while subclass.superclass is not None: if subclass.superclass.lower() == lsuper: return True subclass = ch.GetClass(subclass.superclass, ns, LocalOnly=True, IncludeQualifiers=False, PropertyList=[], IncludeClassOrigin=False) return False def PegasusUDSConnection(creds = None, **kwargs): return WBEMConnection('/var/run/tog-pegasus/cimxml.socket', creds, **kwargs) def SFCBUDSConnection(creds = None, **kwargs): return WBEMConnection('/tmp/sfcbHttpSocket', creds, **kwargs) def OpenWBEMUDSConnection(creds = None, **kwargs): return WBEMConnection('/tmp/OW@LCL@APIIPC_72859_Xq47Bf_P9r761-5_J-7_Q', creds, **kwargs) pywbem-0.8.0~dev/pywbem/LICENSE.txt0000644000175000017500000006350412413731640016750 0ustar bzedbzed00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! pywbem-0.8.0~dev/pywbem/cim_constants.py0000644000175000017500000000436712413747174020356 0ustar bzedbzed00000000000000# # (C) Copyright 2003, 2004 Hewlett-Packard Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter """Useful CIM constants.""" # CIMError error code constants CIM_ERR_FAILED = 1 # A general error occurred CIM_ERR_ACCESS_DENIED = 2 # Resource not available CIM_ERR_INVALID_NAMESPACE = 3 # The target namespace does not exist CIM_ERR_INVALID_PARAMETER = 4 # Parameter value(s) invalid CIM_ERR_INVALID_CLASS = 5 # The specified Class does not exist CIM_ERR_NOT_FOUND = 6 # Requested object could not be found CIM_ERR_NOT_SUPPORTED = 7 # Operation not supported CIM_ERR_CLASS_HAS_CHILDREN = 8 # Class has subclasses CIM_ERR_CLASS_HAS_INSTANCES = 9 # Class has instances CIM_ERR_INVALID_SUPERCLASS = 10 # Superclass does not exist CIM_ERR_ALREADY_EXISTS = 11 # Object already exists CIM_ERR_NO_SUCH_PROPERTY = 12 # Property does not exist CIM_ERR_TYPE_MISMATCH = 13 # Value incompatible with type CIM_ERR_QUERY_LANGUAGE_NOT_SUPPORTED = 14 # Query language not supported CIM_ERR_INVALID_QUERY = 15 # Query not valid CIM_ERR_METHOD_NOT_AVAILABLE = 16 # Extrinsic method not executed CIM_ERR_METHOD_NOT_FOUND = 17 # Extrinsic method does not exist # Provider types PROVIDERTYPE_CLASS = 1 PROVIDERTYPE_INSTANCE = 2 PROVIDERTYPE_ASSOCIATION = 3 PROVIDERTYPE_INDICATION = 4 PROVIDERTYPE_METHOD = 5 PROVIDERTYPE_CONSUMER = 6 # Indication consumer PROVIDERTYPE_QUERY = 7 pywbem-0.8.0~dev/pywbem/cim_types.py0000644000175000017500000002077612413747174017510 0ustar bzedbzed00000000000000# # (C) Copyright 2003, 2004 Hewlett-Packard Development Company, L.P. # (C) Copyright 2006, 2007 Novell, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter # Author: Bart Whiteley """ Subclasses of builtin Python types to remember CIM types. This is necessary as we need to remember whether an integer property is a uint8, uint16, uint32 etc, while still being able to treat it as a integer. """ from datetime import tzinfo, datetime, timedelta import re class MinutesFromUTC(tzinfo): """Fixed offset in minutes from UTC.""" def __init__(self, offset): self.__offset = timedelta(minutes = offset) def utcoffset(self, dt): return self.__offset def dst(self, dt): return timedelta(0) class CIMType(object): """Base type for all CIM types.""" class CIMDateTime(CIMType) : """A CIM DateTime.""" def __init__(self, dtarg): """Construct a new CIMDateTime Arguments: dtarg -- Can be a string in CIM datetime format, a datetime.datetime, a datetime.timedelta, or a CIMDateTime. """ self.cimtype = 'datetime' self.__timedelta = None self.__datetime = None if isinstance(dtarg, basestring): date_pattern = re.compile(r'^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\.(\d{6})([+|-])(\d{3})') s = date_pattern.search(dtarg) if s is not None: g = s.groups() offset = int(g[8]) if g[7] == '-': offset = -offset try: self.__datetime = datetime(int(g[0]), int(g[1]), int(g[2]), int(g[3]), int(g[4]), int(g[5]), int(g[6]), MinutesFromUTC(offset)) except ValueError as exc: raise ValueError('dtarg argument "%s" has invalid field '\ 'values for CIM datetime timestamp '\ 'format: %s' % (dtarg, exc)) else: tv_pattern = re.compile(r'^(\d{8})(\d{2})(\d{2})(\d{2})\.(\d{6})(:)(000)') s = tv_pattern.search(dtarg) if s is not None: g = s.groups() # Because the input values are limited by the matched pattern, # timedelta() never throws any exception. self.__timedelta = timedelta(days=int(g[0]), hours=int(g[1]), minutes=int(g[2]), seconds=int(g[3]), microseconds=int(g[4])) else: raise ValueError('dtarg argument "%s" has an invalid CIM '\ 'datetime format' % dtarg) elif isinstance(dtarg, datetime): self.__datetime = dtarg; elif isinstance(dtarg, timedelta): self.__timedelta = dtarg elif isinstance(dtarg, CIMDateTime): self.__datetime = dtarg.__datetime self.__timedelta = dtarg.__timedelta else: raise TypeError('dtarg argument "%s" has an invalid type: %s '\ '(expected datetime, timedelta, string, or '\ 'CIMDateTime)' % (dtarg, type(dtarg))) @property def minutes_from_utc(self): """Return the timezone as +/- minutes from UTC""" offset = 0 if self.__datetime is not None and \ self.__datetime.utcoffset() is not None: offset = self.__datetime.utcoffset().seconds / 60 if self.__datetime.utcoffset().days == -1: offset = -(60*24 - offset) return offset @property def datetime(self): return self.__datetime @property def timedelta(self): return self.__timedelta @property def is_interval(self): return self.__timedelta is not None @staticmethod def get_local_utcoffset(): """Return minutes +/- UTC for the local timezone""" utc = datetime.utcnow() local = datetime.now() if local < utc: return - int(float((utc - local).seconds) / 60 + .5) else: return int(float((local - utc).seconds) / 60 + .5) @classmethod def now(cls, tzi=None): if tzi is None: tzi = MinutesFromUTC(cls.get_local_utcoffset()) return cls(datetime.now(tzi)) @classmethod def fromtimestamp(cls, ts, tzi=None): if tzi is None: tzi = MinutesFromUTC(cls.get_local_utcoffset()) return cls(datetime.fromtimestamp(ts, tzi)) def __str__ (self): if self.is_interval: hour = self.__timedelta.seconds / 3600 minute = (self.__timedelta.seconds - hour * 3600) / 60 second = self.__timedelta.seconds - hour * 3600 - minute * 60 return '%08d%02d%02d%02d.%06d:000' % \ (self.__timedelta.days, hour, minute, second, self.__timedelta.microseconds) else: offset = self.minutes_from_utc sign = '+' if offset < 0: sign = '-' offset = -offset return '%d%02d%02d%02d%02d%02d.%06d%s%03d' % \ (self.__datetime.year, self.__datetime.month, self.__datetime.day, self.__datetime.hour, self.__datetime.minute, self.__datetime.second, self.__datetime.microsecond, sign, offset) def __repr__ (self): return '%s(%s)'%(self.__class__.__name__, `str(self)`) def __getstate__(self): return str(self) def __setstate__(self, arg): self.__init__(arg) def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, CIMDateTime): return 1 return (cmp(self.__datetime, other.__datetime) or cmp(self.__timedelta, other.__timedelta)) # CIM integer types class CIMInt(CIMType, long): pass class Uint8(CIMInt): cimtype = 'uint8' class Sint8(CIMInt): cimtype = 'sint8' class Uint16(CIMInt): cimtype = 'uint16' class Sint16(CIMInt): cimtype = 'sint16' class Uint32(CIMInt): cimtype = 'uint32' class Sint32(CIMInt): cimtype = 'sint32' class Uint64(CIMInt): cimtype = 'uint64' class Sint64(CIMInt): cimtype = 'sint64' # CIM float types class CIMFloat(CIMType, float): pass class Real32(CIMFloat): cimtype = 'real32' class Real64(CIMFloat): cimtype = 'real64' def cimtype(obj): """Return the CIM type name of an object as a string. For a list, the type is the type of the first element as CIM arrays must be homogeneous.""" if isinstance(obj, CIMType): return obj.cimtype if isinstance(obj, bool): return 'boolean' if isinstance(obj, (str, unicode)): return 'string' if isinstance(obj, list): return cimtype(obj[0]) if isinstance(obj, (datetime, timedelta)): return 'datetime' raise TypeError("Invalid CIM type for %s" % str(obj)) def atomic_to_cim_xml(obj): """Convert an atomic type to CIM external form""" if isinstance(obj, bool): if obj: return "true" else: return "false" elif isinstance(obj, CIMDateTime): return unicode(obj) elif isinstance(obj, datetime): return unicode(CIMDateTime(obj)) elif obj is None: return obj elif cimtype(obj) == 'real32': return u'%.8E' % obj elif cimtype(obj) == 'real64': return u'%.16E' % obj elif isinstance(obj, str): return obj.decode('utf-8') else: # e.g. unicode, int return unicode(obj) pywbem-0.8.0~dev/pywbem/twisted_client.py0000644000175000017500000005555112413747174020534 0ustar bzedbzed00000000000000# # (C) Copyright 2005,2007 Hewlett-Packard Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter """pywbem.twisted - WBEM client bindings for Twisted Python. This module contains factory classes that produce WBEMClient instances that perform WBEM requests over HTTP using the twisted.protocols.http.HTTPClient base class. """ from twisted.internet import reactor, protocol, defer from twisted.web import http, client, error from pywbem import CIMClass, CIMClassName, CIMInstance, CIMInstanceName, CIMError, CIMDateTime, cim_types, cim_xml, cim_obj try: from elementtree.ElementTree import fromstring, tostring except ImportError, arg: from xml.etree.ElementTree import fromstring, tostring import string, base64 from types import StringTypes from datetime import datetime, timedelta class WBEMClient(http.HTTPClient): """A HTTPClient subclass that handles WBEM requests.""" status = None def connectionMade(self): """Send a HTTP POST command with the appropriate CIM over HTTP headers and payload.""" self.factory.request_xml = str(self.factory.payload) self.sendCommand('POST', '/cimom') self.sendHeader('Host', '%s:%d' % (self.transport.addr[0], self.transport.addr[1])) self.sendHeader('User-Agent', 'pywbem/twisted') self.sendHeader('Content-length', len(self.factory.payload)) self.sendHeader('Content-type', 'application/xml') if self.factory.creds: auth = base64.b64encode('%s:%s' % (self.factory.creds[0], self.factory.creds[1])) self.sendHeader('Authorization', 'Basic %s' % auth) self.sendHeader('CIMOperation', str(self.factory.operation)) self.sendHeader('CIMMethod', str(self.factory.method)) self.sendHeader('CIMObject', str(self.factory.object)) self.endHeaders() # TODO: Figure out why twisted doesn't support unicode. An # exception should be thrown by the str() call if the payload # can't be converted to the current codepage. self.transport.write(str(self.factory.payload)) def handleResponse(self, data): """Called when all response data has been received.""" self.factory.response_xml = data if self.status == '200': self.factory.parseErrorAndResponse(data) self.factory.deferred = None self.transport.loseConnection() def handleStatus(self, version, status, message): """Save the status code for processing when we get to the end of the headers.""" self.status = status self.message = message def handleHeader(self, key, value): """Handle header values.""" import urllib if key == 'CIMError': self.CIMError = urllib.unquote(value) if key == 'PGErrorDetail': self.PGErrorDetail = urllib.unquote(value) def handleEndHeaders(self): """Check whether the status was OK and raise an error if not using previously saved header information.""" if self.status != '200': if not hasattr(self, 'cimerror') or \ not hasattr(self, 'errordetail'): self.factory.deferred.errback( CIMError(0, 'HTTP error %s: %s' % (self.status, self.message))) else: self.factory.deferred.errback( CIMError(0, '%s: %s' % (cimerror, errordetail))) class WBEMClientFactory(protocol.ClientFactory): """Create instances of the WBEMClient class.""" request_xml = None response_xml = None xml_header = '' def __init__(self, creds, operation, method, object, payload): self.creds = creds self.operation = operation self.method = method self.object = object self.payload = payload self.protocol = lambda: WBEMClient() self.deferred = defer.Deferred() def clientConnectionFailed(self, connector, reason): if self.deferred is not None: reactor.callLater(0, self.deferred.errback, reason) def clientConnectionLost(self, connector, reason): if self.deferred is not None: reactor.callLater(0, self.deferred.errback, reason) def imethodcallPayload(self, methodname, localnsp, **kwargs): """Generate the XML payload for an intrinsic methodcall.""" param_list = [pywbem.IPARAMVALUE(x[0], pywbem.tocimxml(x[1])) for x in kwargs.items()] payload = pywbem.CIM( pywbem.MESSAGE( pywbem.SIMPLEREQ( pywbem.IMETHODCALL( methodname, pywbem.LOCALNAMESPACEPATH( [pywbem.NAMESPACE(ns) for ns in string.split(localnsp, '/')]), param_list)), '1001', '1.0'), '2.0', '2.0') return self.xml_header + payload.toxml() def methodcallPayload(self, methodname, obj, namespace, **kwargs): """Generate the XML payload for an extrinsic methodcall.""" if isinstance(obj, CIMInstanceName): path = obj.copy() path.host = None path.namespace = None localpath = pywbem.LOCALINSTANCEPATH( pywbem.LOCALNAMESPACEPATH( [pywbem.NAMESPACE(ns) for ns in string.split(namespace, '/')]), path.tocimxml()) else: localpath = pywbem.LOCALCLASSPATH( pywbem.LOCALNAMESPACEPATH( [pywbem.NAMESPACE(ns) for ns in string.split(namespace, '/')]), obj) def paramtype(obj): """Return a string to be used as the CIMTYPE for a parameter.""" if isinstance(obj, cim_types.CIMType): return obj.cimtype elif type(obj) == bool: return 'boolean' elif isinstance(obj, StringTypes): return 'string' elif isinstance(obj, (datetime, timedelta)): return 'datetime' elif isinstance(obj, (CIMClassName, CIMInstanceName)): return 'reference' elif isinstance(obj, (CIMClass, CIMInstance)): return 'string' elif isinstance(obj, list): return paramtype(obj[0]) raise TypeError('Unsupported parameter type "%s"' % type(obj)) def paramvalue(obj): """Return a cim_xml node to be used as the value for a parameter.""" if isinstance(obj, (datetime, timedelta)): obj = CIMDateTime(obj) if isinstance(obj, (cim_types.CIMType, bool, StringTypes)): return cim_xml.VALUE(cim_types.atomic_to_cim_xml(obj)) if isinstance(obj, (CIMClassName, CIMInstanceName)): return cim_xml.VALUE_REFERENCE(obj.tocimxml()) if isinstance(obj, (CIMClass, CIMInstance)): return cim_xml.VALUE(obj.tocimxml().toxml()) if isinstance(obj, list): if isinstance(obj[0], (CIMClassName, CIMInstanceName)): return cim_xml.VALUE_REFARRAY([paramvalue(x) for x in obj]) return cim_xml.VALUE_ARRAY([paramvalue(x) for x in obj]) raise TypeError('Unsupported parameter type "%s"' % type(obj)) param_list = [pywbem.PARAMVALUE(x[0], paramvalue(x[1]), paramtype(x[1])) for x in kwargs.items()] payload = pywbem.CIM( pywbem.MESSAGE( pywbem.SIMPLEREQ( pywbem.METHODCALL(methodname, localpath, param_list)), '1001', '1.0'), '2.0', '2.0') return self.xml_header + payload.toxml() def parseErrorAndResponse(self, data): """Parse returned XML for errors, then convert into appropriate Python objects.""" xml = fromstring(data) error = xml.find('.//ERROR') if error is None: self.deferred.callback(self.parseResponse(xml)) return try: code = int(error.attrib['CODE']) except ValueError: code = 0 self.deferred.errback(CIMError(code, error.attrib['DESCRIPTION'])) def parseResponse(self, xml): """Parse returned XML and convert into appropriate Python objects. Override in subclass""" pass # TODO: Eww - we should get rid of the tupletree, tupleparse modules # and replace with elementtree based code. import pywbem.tupletree class EnumerateInstances(WBEMClientFactory): """Factory to produce EnumerateInstances WBEM clients.""" def __init__(self, creds, classname, namespace = 'root/cimv2', **kwargs): self.classname = classname self.namespace = namespace payload = self.imethodcallPayload( 'EnumerateInstances', namespace, ClassName = CIMClassName(classname), **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'EnumerateInstances', object = namespace, payload = payload) def __repr__(self): return '<%s(/%s:%s) at 0x%x>' % \ (self.__class__, self.namespace, self.classname, id(self)) def parseResponse(self, xml): tt = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//VALUE.NAMEDINSTANCE')] return [pywbem.tupleparse.parse_value_namedinstance(x) for x in tt] class EnumerateInstanceNames(WBEMClientFactory): """Factory to produce EnumerateInstanceNames WBEM clients.""" def __init__(self, creds, classname, namespace = 'root/cimv2', **kwargs): self.classname = classname self.namespace = namespace payload = self.imethodcallPayload( 'EnumerateInstanceNames', namespace, ClassName = CIMClassName(classname), **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'EnumerateInstanceNames', object = namespace, payload = payload) def __repr__(self): return '<%s(/%s:%s) at 0x%x>' % \ (self.__class__, self.namespace, self.classname, id(self)) def parseResponse(self, xml): tt = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//INSTANCENAME')] names = [pywbem.tupleparse.parse_instancename(x) for x in tt] [setattr(n, 'namespace', self.namespace) for n in names] return names class GetInstance(WBEMClientFactory): """Factory to produce GetInstance WBEM clients.""" def __init__(self, creds, instancename, namespace = 'root/cimv2', **kwargs): self.instancename = instancename self.namespace = namespace payload = self.imethodcallPayload( 'GetInstance', namespace, InstanceName = instancename, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'GetInstance', object = namespace, payload = payload) def __repr__(self): return '<%s(/%s:%s) at 0x%x>' % \ (self.__class__, self.namespace, self.instancename, id(self)) def parseResponse(self, xml): tt = pywbem.tupletree.xml_to_tupletree( tostring(xml.find('.//INSTANCE'))) return pywbem.tupleparse.parse_instance(tt) class DeleteInstance(WBEMClientFactory): """Factory to produce DeleteInstance WBEM clients.""" def __init__(self, creds, instancename, namespace = 'root/cimv2', **kwargs): self.instancename = instancename self.namespace = namespace payload = self.imethodcallPayload( 'DeleteInstance', namespace, InstanceName = instancename, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'DeleteInstance', object = namespace, payload = payload) def __repr__(self): return '<%s(/%s:%s) at 0x%x>' % \ (self.__class__, self.namespace, self.instancename, id(self)) class CreateInstance(WBEMClientFactory): """Factory to produce CreateInstance WBEM clients.""" # TODO: Implement __repr__ method def __init__(self, creds, instance, namespace = 'root/cimv2', **kwargs): payload = self.imethodcallPayload( 'CreateInstance', namespace, NewInstance = instance, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'CreateInstance', object = namespace, payload = payload) def parseResponse(self, xml): tt = pywbem.tupletree.xml_to_tupletree( tostring(xml.find('.//INSTANCENAME'))) return pywbem.tupleparse.parse_instancename(tt) class ModifyInstance(WBEMClientFactory): """Factory to produce ModifyInstance WBEM clients.""" # TODO: Implement __repr__ method def __init__(self, creds, instancename, instance, namespace = 'root/cimv2', **kwargs): wrapped_instance = CIMNamedInstance(instancename, instance) payload = self.imethodcallPayload( 'ModifyInstance', namespace, ModifiedInstance = wrapped_instance, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'ModifyInstance', object = namespace, payload = payload) class EnumerateClassNames(WBEMClientFactory): """Factory to produce EnumerateClassNames WBEM clients.""" def __init__(self, creds, namespace = 'root/cimv2', **kwargs): self.localnsp = LocalNamespacePath payload = self.imethodcallPayload( 'EnumerateClassNames', namespace, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'EnumerateClassNames', object = LocalNamespacePath, payload = payload) def __repr__(self): return '<%s(/%s) at 0x%x>' % \ (self.__class__, self.namespace, id(self)) def parseResponse(self, xml): tt = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//CLASSNAME')] return [pywbem.tupleparse.parse_classname(x) for x in tt] class EnumerateClasses(WBEMClientFactory): """Factory to produce EnumerateClasses WBEM clients.""" def __init__(self, creds, namespace = 'root/cimv2', **kwargs): self.localnsp = LocalNamespacePath payload = self.imethodcallPayload( 'EnumerateClasses', namespace, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'EnumerateClasses', object = namespace, payload = payload) def __repr__(self): return '<%s(/%s) at 0x%x>' % \ (self.__class__, self.namespace, id(self)) def parseResponse(self, xml): tt = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//CLASS')] return [pywbem.tupleparse.parse_class(x) for x in tt] class GetClass(WBEMClientFactory): """Factory to produce GetClass WBEM clients.""" def __init__(self, creds, classname, namespace = 'root/cimv2', **kwargs): self.classname = classname self.namespace = namespace payload = self.imethodcallPayload( 'GetClass', namespace, ClassName = CIMClassName(classname), **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'GetClass', object = namespace, payload = payload) def __repr__(self): return '<%s(/%s:%s) at 0x%x>' % \ (self.__class__, self.namespace, self.classname, id(self)) def parseResponse(self, xml): tt = pywbem.tupletree.xml_to_tupletree( tostring(xml.find('.//CLASS'))) return pywbem.tupleparse.parse_class(tt) class Associators(WBEMClientFactory): """Factory to produce Associators WBEM clients.""" # TODO: Implement __repr__ method def __init__(self, creds, obj, namespace = 'root/cimv2', **kwargs): if isinstance(obj, CIMInstanceName): kwargs['ObjectName'] = obj else: kwargs['ObjectName'] = CIMClassName(obj) payload = self.imethodcallPayload( 'Associators', namespace, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'Associators', object = namespace, payload = payload) class AssociatorNames(WBEMClientFactory): """Factory to produce AssociatorNames WBEM clients.""" # TODO: Implement __repr__ method def __init__(self, creds, obj, namespace = 'root/cimv2', **kwargs): if isinstance(obj, CIMInstanceName): kwargs['ObjectName'] = obj else: kwargs['ObjectName'] = CIMClassName(obj) payload = self.imethodcallPayload( 'AssociatorNames', namespace, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'AssociatorNames', object = namespace, payload = payload) def parseResponse(self, xml): if len(xml.findall('.//INSTANCENAME')) > 0: tt = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//INSTANCENAME')] return [pywbem.tupleparse.parse_instancename(x) for x in tt] else: tt = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//OBJECTPATH')] return [pywbem.tupleparse.parse_objectpath(x)[2] for x in tt] class References(WBEMClientFactory): """Factory to produce References WBEM clients.""" def __init__(self, creds, obj, namespace = 'root/cimv2', **kwargs): if isinstance(obj, CIMInstanceName): kwargs['ObjectName'] = obj else: kwargs['ObjectName'] = CIMClassName(obj) payload = self.imethodcallPayload( 'References', namespace, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'References', object = namespace, payload = payload) class ReferenceNames(WBEMClientFactory): """Factory to produce ReferenceNames WBEM clients.""" # TODO: Implement __repr__ method def __init__(self, creds, obj, namespace = 'root/cimv2', **kwargs): if isinstance(obj, CIMInstanceName): kwargs['ObjectName'] = obj else: kwargs['ObjectName'] = CIMClassName(obj) payload = self.imethodcallPayload( 'ReferenceNames', namespace, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = 'ReferenceNames', object = namespace, payload = payload) def parseResponse(self, xml): if len(xml.findall('.//INSTANCENAME')) > 0: tt = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//INSTANCENAME')] return [pywbem.tupleparse.parse_instancename(x) for x in tt] else: tt = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//OBJECTPATH')] return [pywbem.tupleparse.parse_objectpath(x)[2] for x in tt] class InvokeMethod(WBEMClientFactory): """Factory to produce InvokeMethod WBEM clients.""" def __init__(self, creds, MethodName, ObjectName, namespace = 'root/cimv2', **kwargs): # Convert string to CIMClassName obj = ObjectName if isinstance(obj, StringTypes): obj = CIMClassName(obj, namespace = namespace) if isinstance(obj, CIMInstanceName) and obj.namespace is None: obj = ObjectName.copy() obj.namespace = namespace # Make the method call payload = self.methodcallPayload( MethodName, obj, namespace, **kwargs) WBEMClientFactory.__init__( self, creds, operation = 'MethodCall', method = MethodName, object = obj, payload = payload) def parseResponse(self, xml): # Return value of method result_xml = pywbem.tupletree.xml_to_tupletree( tostring(xml.find('.//RETURNVALUE'))) result_tt = pywbem.tupleparse.parse_any(result_xml) result = cim_obj.tocimobj(result_tt[1]['PARAMTYPE'], result_tt[2]) # Output parameters params_xml = [pywbem.tupletree.xml_to_tupletree(tostring(x)) for x in xml.findall('.//PARAMVALUE')] params_tt = [pywbem.tupleparse.parse_any(x) for x in params_xml] params = {} for p in params_tt: if p[1] == 'reference': params[p[0]] = p[2] else: params[p[0]] = cim_obj.tocimobj(p[1], p[2]) return (result, params) pywbem-0.8.0~dev/pywbem/NEWS0000644000175000017500000003631612413731640015625 0ustar bzedbzed00000000000000pywbem-0.8.0~dev (last updated: 2014-09-11, includes commits up to r642) ENHANCEMENTS: * Verify certificates against platform provided CA trust store in /etc/pki/tls/certs. Linux only. (Peter Hatina) * Added '-d' option to MOF compiler that causes the compiler to perform a dry-run and just check the MOF file syntax. This allows to more easily detect included MOF files when used together with the '-v' option. (Jan Safranek) * Added support for non-ASCII characters. (Michal Minar) * Improved information in the message text of some exceptions (TypeError and KeyError in cim_obj.py, ValueError in cim_obj.py, and ParseError in tupleparse.py). (Andreas Maier) * Moved the definition of the pywbem version from setup.py to __init__.py, in order to make it available to programs using pywbem as pywbem.__version__. (Andreas Maier) * Added support for direct iteration over NocaseDict objects using 'for' and 'in' by adding __iter__(), e.g. for use with CIMInstance.properties. (Andreas Maier) BUG FIXES: * Fix syntax error in CIM DTDVERSION error path. Allow KEYVALUE VALUETYPE attribute to be optional as specified in the DTD. (Andreas Linke) * Added parsing of InvokeMethod return value and output parameters for Twisted Python client. (Tim Potter) * Fixed cim_provider2.py to properly support shutdown() and can_unload() (called from CMPI cleanup() functions). Support was recently added to cmpi-bindings for this. (Bart Whiteley) * Fixed XML parsing to accept SFCB-style embedded instance parameters. (Mihai Ibanescu) * Use getpass module instead of pwd to detect local user to fix Win32. (Tim Potter) * Re-throw KeyError exceptions with capitalised key string instead of lower cased version in NocaseDict.__getitem__(). (Tim Potter) * Use base64.b64encode() instead of base64.encodestring() in Twisted client. (Mihai Ibanescu) * Fix missing CIMDateTime import in Twisted client. (Mihai Ibanescu) * Fixed CIMInstanceName rendering to string. It is now possible to pass the rendered string value as an instance path argument of a CIM method. (Jan Safranek, Michal Minar) * For Python providers, fixed the comparsion of the Role parameter in association operations to be case insensitive, and removed an erroneous test that raised an exception when the property specified in the Role parameter was not also in the property list specified by the Properties parameter. (Jan Safranek) * For Python providers, converted debug 'print' statements to trace messages that end up in the system log. (Jan Safranek) * The CIM-XML parser no longer throws an exception when parsing a qualifier declaration. (Jan Safranek) Note: The CIM-XML supported by this fix does not conform to DSP0201 so far. Further fixes are pending. * Fixed parsing errors for connection URLs with IPv6 addresses. (Peter Hatina) Note: The parsing support does not address all issues with IPv6 addresses, and it does not support zone indexes (aka scope IDs). Further fixes are pending. * Fixed the hard coded socket addressing family used for HTTPS that was incorrect in some IPv6 cases, by determining it dynamically. (Peter Hatina) * Fixed the list of output parameters of extrinsic method calls to be returned as a case insensitive dictionary (using cim_obj.NocaseDict). (Jan Safranek) * Fixed the checking of CIMVERSION attributes in CIM-XML to only verify the major version, consistent with DSP0201 (see subclause 5.2.1, in DSP0201 version 2.3.1). (Jan Safranek) * Fixed error in cim_http.py related to stronger type checking of Python 2.7. (Eduardo de Barros Lima) * Removed erroneous qualifier scopes SCHEMA and QUALIFIER from the MOF compiler (see DSP0004). (Andreas Maier) * Fixed debug logging of CIM-XML payload (that is, conn.last_*request/reply attributes) for extrinsic method calls, to now be consistent with intrinsic method calls. (Andreas Maier) * Fixed TOCTOU (time-of-check-time-of-use) error when validating peer's certificate. (Michal Minar) PACKAGING: * Fix grammatical funkiness in the license text. No change to actual license - still LGPLv2. (Tim Potter) * Added LICENSE.txt file to release. (Tim Potter) * Added NEWS, README and INSTALL files to distribution archive. (Andreas Maier) * Removed confusing section about build from INSTALL file, to scope it just to the topic of installation. (Andreas Maier) pywbem-0.7 2008-12-12 BUG FIXES: * Fixed enumInstances and references in cim_provider to do a deep copy of the model before filtering instances so provider writers are less surprised. (Bart Whiteley) * Added CIMDateTime.__cmp__() so that CIMDateTime instances can be compared. (Bart Whiteley) * Fixed data types of method return values for python providers. (Bart Whiteley) * Fixed REF array out parameters in tupleparse.py. (Bart Whiteley) * Fixed Array parameters with no elements. (Bart Whiteley) * Fixed precision for real32 and real64 types. (Bart Whiteley) * Fixed Array properties where is_array isn't set in __init__. (Bart Whiteley) * Added NocaseDict.__cmp__(self, other). (Bart Whiteley) * Fixed WBEMConnection.__repr__ for anonymous connections. (Tim Potter) * Fixed XML encoding of CIMQualifierDeclarations. (Bart Whiteley) * Fixed EnumerateQualifiers if there are no qualifiers. (Bart Whiteley) * Fixed InvokeMethod to only send a LOCALCLASSPATH or LOCALINSTANCEPATH, not a CLASSPATH or INSTANCEPATH. (Bart Whiteley) * Fix unexpected line break in basic auth header for long credentials. (Daniel Hiltgen) * Fix Host: HTTP header when connecting to a unix domain socket. (Bart Whiteley) * Fix deprecation warnings with Python 2.6. (Bart Whiteley) ENHANCEMENTS: * Added support for generating Pegasus provider registration MOF in cim_provider.codegen(). (Bart Whiteley) * Implemented methods to parse indication export requests. (Bart Whiteley) * Python provider code generation enhancements. (Bart Whiteley) * Support for Pegasus Local authentication. (Bart Whiteley) * Support for Pegasus and OpenWBEM Unix Domain Socket. (Tim and Bart) * Added support for Pegasus non-compliant EMBEDDEDOBJECT XML attribute. (Bart Whiteley) * Added CIMQualifierDeclaration.tomof(). (Bart Whiteley) * Added a powerful MOF compiler. (Bart Whiteley) * Added property filtering to CIMInstance. (Bart Whiteley) * Added value attribute to CIMParameter. (Bart Whiteley) * Rigged CIMInstance to automagically update CIMInstance.path.keybindings as key properties are set. (Bart Whiteley) * Added cim_provider2.py: A new provider interface. Python providers using this interface can use the cmpi-bindings project within OMC (http://omc-project.org/) to run under any CIMOM supporting the CMPI interface. This is prefered to the old cim_provider.py interface that was used with the Python Provider Managers for OpenWBEM and Pegasus. * Changed __init__.py to not import anything from cim_provider.py (or cim_provider2.py) into the pywbem namespace. Existing providers based on cim_provider.py can still work with a minor adjustment involving importing CIMProvider from pywbem.cim_provider. The codegen funtion can now be obtained with 'from pywbem.cim_provider import codegen', or 'from pywbem.cim_provider2 import codegen' or similar. * Added wbemcli.py command line utility. (Tim Potter) * Pass keyword args in unix domain socket connection functions down to WBEMConnection(). (Tim Potter) pywbem-0.6 2007-10-26 LICENSING: * Relicensed from the GNU GPLv2 to the GNU LGPLv2. API CHANGES: * Add a type keyword arg and attribute to CIMQualifier, similar to the CIMProperty object, to allow the creation of null qualifiers. (Tim Potter) * Remove the toxml() method from CIM object classes. Use tocimxml().toxml() instead which specifies the CIM-XML representation of the object. (Tim Potter) * CIMDateTime class should now be used instead of datetime.datetime and datetime.timedelta. * Added a new method, CIMInstance.update_existing(). This behaves like update() on a dict, but only assigns new values to existing properties. It skips values for properties not already present in the instance. This is useful for honoring PropertyList within python providers. BUG FIXES: * Explicitly specify charset="utf-8" in HTTP Content-type header as this is required now by the Pegasus cimserver. (Tim Potter) * Parse VALUETYPE elements that contain a TYPE attribute. This feature was introduced in version 2.2 of the CIM-XML DTD and produced by some CIMOMs such as the Java WBEM Server. (Tim Potter) * Don't require CreateInstance to have the path attribute set but if it is, use the namespace from it. (Tim Potter) * Allow extrinsic methods to return object references. (Tim Potter) * Fix CIMInstanceName to support more numeric types of keybindings. (Bart Whiteley) * Fix datetime values to support utc offset. (Bart Whiteley) * Fix http client to monitor the connection more closely (RFC 2616 section 8.2.2). Previously, a large request could cause a socket exception with no ability to read the response and respond to an authentication challenge. * Fix NULL qualifiers to have a (required) type. (Martin Mrazik) * Fix initialising CIMInstanceName keys from a NocaseDict. (Bart Whiteley) * Return correct namespace in path for return value from GetInstance. (Tim Potter) * Numerous bugfixes to Twisted Python client. (Tim Potter) * Fix for x.509 SSL certificate handling. (Bas ten Berge) * EnumerateClassNames() now returns an empty list instead of None if there are no classes. (Bart Whiteley) ENHANCEMENTS: * Support for OpenWBEM password-less local authentication. (Bart Whiteley) * Support for embedded objects is described in DSP0201-2.2.0 (Bart Whiteley) * New CIMDateTime class to deal with CIM-isms of datetimes. Most notably, datetime deals with timezone info poorly. (Bart Whiteley) * Add InvokeMethod() support in Twisted Python client. (Tim Potter) pywbem-0.5 2006-11-21 API CHANGES: * Many API changes were made to simplify the function and object interface of PyWBEM. Aspects of just about every CIM operation call and CIM object have changed. The major changes are: - The "LocalNamespacePath" keyword argument has been renamed to simply "namespace" for all CIM operations. - Replaced all object location classes with CIMInstanceName, and all instance classes with CIMInstance. CIMInstanceName now has "host" and "namespace" attributes to fully name a reference to an instance. The CIMInstance class now has a "path" attribute which is of type CIMInstanceName. - EnumerateInstances() now returns a list of CIMInstance objects (with path attribute set) instead of a list of CIMNamedInstance or tuples of (CIMInstanceName, CIMInstance). - All representations of properties can now be represented with the CIMProperty class. * All classes now have a copy() method which return a deep copy of the object. PyWBEM makes extensive use of dictionary objects which are passed by reference in Python. Use the copy() method to create and manipulate objects without modifying them by accident. BUG FIXES: * Fix parse bug when a CIMInstanceName is passed as the localobject parameter to WBEMConnection.InvokeMethod(). * Fix parsing of INSTANCE elements containing PROPERTY.REFERENCE elements bug found by Bart Whiteley. This turns up when processing associations. (Tim Potter) * Handle extrinsic method calls that don't return a value or any output parameters. (Tim Potter) * Fixed parsing of PARAMETER.ARRAY and PARAMETER.REFARRAY to not require optional attrs. (Bart Whiteley) * Atomic_to_cim_xml string generation for a datetime - was missing a >> '.' in the string. (Norm Paxton) * InvokeMethod did not provide for 'None' in output parameters. (Norm Paxton) ENHANCEMENTS: * More parts of the class provider interface have been implemented. (Tim Potter, Bart Whiteley) * Many case-sensitivity bugs, mostly in __cmp__ methods, were found and fixed. (Tim Potter) * Implemented a test suite for maintaining backward compatibility and testing new features. (Tim Potter) * Implemented ExecQuery. (Bart Whiteley) * Allow a string classname to be passed as the localobject parameter to WBEMConnection.InvokeMethod(). (Tim Potter) * Add missing qualifiers on array properties. (Bart Whiteley) * Added code for performing asynchronous WBEM client operations using the Twisted Python framework. (Tim Potter) * Allow extrinsic method calls that take parameters. (Tim Potter) * Added cim_http.AuthError exception class. This is raised if the CIMOM returns a 401 (Unauthorized). Now the client can distinguish this condition, and (re)prompt for credentials. (Bart Whiteley) * Created cim_obj.CIMParameter class. Added return type, class origin, propagated to CIMMethod. CIMParameter object now allows parameter types and qualifiers to be obtained. (Bart Whiteley) * Implemented case-insensitive keys for property and qualifier dictionaries, as per the CIM specification. (Tim Potter, Bart Whitely) pywbem-0.4 2005-11-15 BUG FIXES: * Correctly calculate value of Content-Length HTTP header to include opening XML stanza. (Szalai Ferenc) * Fix syntax error when re-raising socket errors. (Pat Knight) ENHANCEMENTS: * Support for marshaling and unmarshaling CIM dates object into Python datetime objects. (Szalai Ferenc) * Experimental module for making asynchronous WBEM calls with PyWBEM in Twisted Python. (Tim Potter) * Add parameter type checking for object location classes. (Tim Potter) * Allow caller to pass in a dictionary containing the location of the SSL certificate and key files as per the httplib.HTTPSConnection() class constructor. (Pat Knight) API CHANGES: * Change association provider API functions to take a fixed parameter for the named object instead of a keyword argument. This breaks backward compatibility. (Tim Potter) * Remove the CIMLocalNamespacePath class and replaced by a Python string. (Tim Potter) PORTABILITY: * Don't use UserDict.DictMixin base class as it only exists in Python 2.3 and higher. (Tim Potter) TESTS: * Add tests for parameter type checking for object location classes. (Tim Potter) * Add tests for string representation of object location classes. (Tim Potter) pywbem-0.8.0~dev/pywbem/tupletree.py0000644000175000017500000000617312413747174017520 0ustar bzedbzed00000000000000# # (C) Copyright 2003, 2004 Hewlett-Packard Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Martin Pool """ tupletree - Convert XML DOM objects to and from tuple trees. DOM is the standard in-memory representation of XML documents, but it is very cumbersome for some types of processing where XML encodes object structures rather than text documents. Direct mapping to Python classes may not be a good match either. tupletrees may be created from an in-memory DOM using dom_to_tupletree(), or from a string using xml_to_tupletree(). Since the Python XML libraries deal mostly with Unicode strings they are also returned here. If plain Strings are passed in they will be converted by xmldom. Each node of the tuple tree is a Python 4-tuple, corresponding to an XML Element (i.e. ): (NAME, ATTRS, CONTENTS, None) The NAME is the name of the element. The ATTRS are a name-value hash of element attributes. The CONTENTS is a list of child elements. The fourth element is reserved. """ def dom_to_tupletree(node): """Convert a DOM object to a pyRXP-style tuple tree. Each element is a 4-tuple of (NAME, ATTRS, CONTENTS, None). Very nice for processing complex nested trees. """ import types if node.nodeType == node.DOCUMENT_NODE: # boring; pop down one level return dom_to_tupletree(node.firstChild) assert node.nodeType == node.ELEMENT_NODE name = node.nodeName attrs = {} contents = [] for child in node.childNodes: if child.nodeType == child.ELEMENT_NODE: contents.append(dom_to_tupletree(child)) elif child.nodeType == child.TEXT_NODE: assert isinstance(child.nodeValue, types.StringTypes), \ "text node %s is not a string" % `child` contents.append(child.nodeValue) elif child.nodeType == child.CDATA_SECTION_NODE: contents.append(child.nodeValue) else: raise RuntimeError("can't handle %s" % child) for i in range(node.attributes.length): attr_node = node.attributes.item(i) attrs[attr_node.nodeName] = attr_node.nodeValue # XXX: Cannot yet handle comments, cdata, processing instructions and # other XML batshit. # it's so easy in retrospect! return (name, attrs, contents, None) def xml_to_tupletree(xml_string): """Parse XML straight into tupletree.""" import xml.dom.minidom dom_xml = xml.dom.minidom.parseString(xml_string) return dom_to_tupletree(dom_xml) pywbem-0.8.0~dev/pywbem/cim_provider.py0000644000175000017500000023154112413747174020170 0ustar bzedbzed00000000000000# # (C) Copyright 2003-2007 Hewlett-Packard Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Bart Whiteley # Jon Carey #### r"""Python CIM Providers (aka "nirvana") This module is an abstraction and utility layer between a CIMOM and Python providers. The CIMOM uses this module to load Python providers, and route requests to those providers. Python Provider Modules Python Providers are implemented as Python modules. By convention these modules are installed into /usr/lib/pycim. However, they can be anywhere. These modules are loaded on demand using load_source() from the imp module. The CIMOM's pycim interface stores the timestamp of the provider modules. If the modules change, the CIMOM reloads the modules. This is very useful while developing providers, since the latest code will always be loaded and used. A Python Provider Module will contain functions, attributes, and instances that will be accessed and manipulated by this module. Providers are often classified in the following catagories: Instance -- Instrument the retrieval, creation, modification, and deletion of CIM instances. Association -- Instrument CIM associations (CIM classes with the Association qualifier). Method -- Instrument methods as defined on CIM instances or CIM classes. Indication -- Generates indications based on indication subscriptions. Indication Consumer -- "Consumes" (or "Handles") an indication, possibly delivering it through some other means, such as email. Polled -- A polled provider is allowed to run periodically (by calling its poll function). This allows a provider to do some periodic work, without the need to create its own thread. An Instance, Association, and/or Method provider is created by defining one or more subclasses of CIMProvider within the provider module, and registering instances of the subclass(es) with CIM class names by way of the get_providers function (described below). Refer to the documentation for CIMProvider in this module. Indication, Indication Consumer, and Polled providers are defined by implementing some functions within the provider module. Provider module functions: init(env): This module function is optional. It is called immediately after the provider module is imported. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) get_providers(env): Return a dict that maps CIM class names to instances of CIMProvider subclasses. Note that multiple classes can be instrumented by the same instance of a CIMProvider subclass. The CIM class names are case-insensitive, since this dict is converted to a NocaseDict. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) For example, a Python Provider Module may contain the following: class Py_FooBarProvider(CIMProvider): ... def get_providers(env): _fbp = Py_FooBarProvider() return {'Py_Foo':_fbp, 'Py_Bar':_fbp} get_initial_polling_interval(env): Return the number of seconds before the first call to poll. If this method returns zero, then the poll method is never called. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) poll(env): Do some work, and return the number of seconds until the next poll. A polled provider's poll function will be called periodically by the CIMOM. The polled provider can use this opportunity to do some work, such as checking on some conditions, and generating indications. The poll function returns the number of seconds the CIMOM should wait before calling poll again. A return value of -1 indicates to the CIMOM that the previous poll value should be used. A return value of 0 indicates that the poll function should never be called again. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) can_unload(env): Return True if the provider can be unloaded. The CIMOM may try to unload a provider after a period of inactivity. Before unloading a provider, the CIMOM asks the provider if it can be unloaded. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) shutdown(env): Perform any cleanup tasks prior to being unloaded. The provider will shortly be unloaded, and is given an opportunity to perform any needed cleanup. The provider may be unloaded after a period of inactivity (see the documentation for can_unload), or because the CIMOM is shutting down. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) handle_indication(env, ns, handler_instance, indication_instance): Process an indication. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) ns -- The namespace where the even occurred handler_instance -- indication_instance -- The indication activate_filter (env, filter, ns, classes, first_activation): Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) filter -- namespace -- classes -- first_activation -- deactivate_filter(env, filter, ns, classes, last_activation): Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) filter -- ns -- classes -- last_activation -- Provider Environment A pycimmb.ProviderEnvironment is passed to many functions. This is a handle back into the CIMOM. You can use it for logging and for making "up-calls" to the CIMOM. For example: logger = env.get_logger() logger.log_debug('Debug Info') ch = env.get_cimom_handle() other_inst = ch.GetInstance(inst_path, LocalOnly=False, IncludeQualifiers=False, IncludeClassOrigin=False) The API of the pycimmb.CIMOMHandle resembles that of pywbem.WBEMConnection. For more information on the ProviderEnvironments, and other features provided by pycimmb, refer to the pycimmb documentation. CodeGen The codegen function can be used to generate provider stub code for a given CIM class. This is a quick way to get started writing a provider. """ import sys from os.path import dirname from imp import load_source import types import pywbem __all__ = ['CIMProvider'] def _path_equals_ignore_host(lhs, rhs): """If one object path doesn't inlcude a host, don't include the hosts in the comparison """ if lhs is rhs: return True if lhs.host is not None and rhs.host is not None and lhs.host != rhs.host: return False # need to make sure this stays in sync with CIMInstanceName.__cmp__() return not (pywbem.cmpname(rhs.classname, lhs.classname) or cmp(rhs.keybindings, lhs.keybindings) or pywbem.cmpname(rhs.namespace, lhs.namespace)) class CIMProvider(object): """Base class for CIM Providers. A derived class might normally override the following: - enum_instances - get_instance - set_instance - delete_instance - references If the provider is a "read-only" instance provider, set_instance and delete_instance need not be overridden. Only association providers need to override references. A method provider should implement a method of the form: def cim_method_(self, env, object_name, method, param_, param_, ...): Where is the name of the method from the CIM schema. needs to be all lowercase, regardless of the case of the method name in the CIM schema (CIM method names are case insensitive). Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) object_name -- A pywbem.CIMInstanceName or pywbem.CIMClassname specifying the object on which the method is to be invoked. method -- A pywbem.CIMMethod, representing the method to execute. param_ -- Corresponds to the input parameter from the CIM schema. needs to be all lowercase, regardless of the case of the parameter name in the CIM schema (CIM parameter names are case insensitive). The method returns a two-tuple containing the return value of the method, and a dictionary containing the output parameters. Example: def cim_method_requeststatechange(self, env, object_name, method, param_requestedstate, param_timeoutperiod): # do stuff. out_params = {'job': pywbem.CIMInstanceName(...)} rval = pywbem.Uint32(0) return (rval, out_params) The methods prefixed with "MI_" correspond to the WBEM operations from http://www.dmtf.org/standards/published_documents/DSP200.html The default implementations of these methods call the methods described above. These will not normally be overridden or extended by a subclass. """ def get_instance (self, env, model, cim_class): """Return an instance. Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) model -- A template of the pywbem.CIMInstance to be returned. The key properties are set on this instance to correspond to the instanceName that was requested. The properties of the model are already filtered according to the PropertyList from the request. Only properties present in the model need to be given values. If you prefer, you can set all of the values, and the instance will be filtered for you. cim_class -- The pywbem.CIMClass Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_NOT_FOUND (the CIM Class does exist, but the requested CIM Instance does not exist in the specified namespace) CIM_ERR_FAILED (some other unspecified error occurred) """ return None def enum_instances(self, env, model, cim_class, keys_only): """Enumerate instances. The WBEM operations EnumerateInstances and EnumerateInstanceNames are both mapped to this method. This method is a python generator Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) model -- A template of the pywbem.CIMInstances to be generated. The properties of the model are already filtered according to the PropertyList from the request. Only properties present in the model need to be given values. If you prefer, you can always set all of the values, and the instance will be filtered for you. cim_class -- The pywbem.CIMClass keys_only -- A boolean. True if only the key properties should be set on the generated instances. Possible Errors: CIM_ERR_FAILED (some other unspecified error occurred) """ pass def set_instance(self, env, instance, previous_instance, cim_class): """Return a newly created or modified instance. Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) instance -- The new pywbem.CIMInstance. If modifying an existing instance, the properties on this instance have been filtered by the PropertyList from the request. previous_instance -- The previous pywbem.CIMInstance if modifying an existing instance. None if creating a new instance. cim_class -- The pywbem.CIMClass Return the new instance. The keys must be set on the new instance. Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_NOT_SUPPORTED CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_ALREADY_EXISTS (the CIM Instance already exists -- only valid if previous_instance is None, indicating that the operation was CreateInstance) CIM_ERR_NOT_FOUND (the CIM Instance does not exist -- only valid if previous_instance is not None, indicating that the operation was ModifyInstance) CIM_ERR_FAILED (some other unspecified error occurred) """ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED, "") def delete_instance(self, env, instance_name): """Delete an instance. Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) instance_name -- A pywbem.CIMInstanceName specifying the instance to delete. Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_NOT_SUPPORTED CIM_ERR_INVALID_NAMESPACE CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_INVALID_CLASS (the CIM Class does not exist in the specified namespace) CIM_ERR_NOT_FOUND (the CIM Class does exist, but the requested CIM Instance does not exist in the specified namespace) CIM_ERR_FAILED (some other unspecified error occurred) """ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED, "") def references(self, env, object_name, model, assoc_class, result_class_name, role, result_role, keys_only): """Instrument Associations. All four association-related operations (Associators, AssociatorNames, References, ReferenceNames) are mapped to this method. This method is a python generator Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) object_name -- A pywbem.CIMInstanceName that defines the source CIM Object whose associated Objects are to be returned. model -- A template pywbem.CIMInstance to serve as a model of the objects to be returned. Only properties present on this model need to be set. assoc_class -- The pywbem.CIMClass. result_class_name -- If not empty, this string acts as a filter on the returned set of Instances by mandating that each returned Instances MUST represent an association between object_name and an Instance of a Class whose name matches this parameter or a subclass. role -- If not empty, MUST be a valid Property name. It acts as a filter on the returned set of Instances by mandating that each returned Instance MUST refer to object_name via a Property whose name matches the value of this parameter. result_role -- If not empty, MUST be a valid Property name. It acts as a filter on the returned set of Instances by mandating that each returned Instance MUST represent associations of object_name to other Instances, where the other Instances play the specified result_role in the association (i.e. the name of the Property in the Association Class that refers to the Object related to object_name MUST match the value of this parameter). keys_only -- A boolean. True if only the key properties should be set on the generated instances. The following diagram may be helpful in understanding the role, result_role, and result_class_name parameters. +------------------------+ +-------------------+ | object_name.classname | | result_class_name | | ~~~~~~~~~~~~~~~~~~~~~ | | ~~~~~~~~~~~~~~~~~ | +------------------------+ +-------------------+ | +-----------------------------------+ | | | [Association] assoc_class | | | object_name | ~~~~~~~~~~~~~~~~~~~~~~~~~ | | +--------------+ object_name.classname REF role | | (CIMInstanceName) | result_class_name REF result_role +------+ | |(CIMInstanceName) +-----------------------------------+ Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_NOT_SUPPORTED CIM_ERR_INVALID_NAMESPACE CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_FAILED (some other unspecified error occurred) """ pass def _set_filter_results(self, value): self._filter_results = value def _get_filter_results(self): if hasattr(self, '_filter_results'): return self._filter_results return True filter_results = property(_get_filter_results, _set_filter_results, None, """Determines if the CIMProvider base class should filter results If True, the subclass of CIMProvider in the provider module does not need to filter returned results based on property_list, and in the case of association providers, role, result_role, and result_class_name. The results will be filtered by the CIMProvider base class. If False, the CIMProvider base class will do no filtering. Therefore the subclass of CIMProvider in the provider module will have to filter based on property_list, and in the case of association providers, role, result_role, and result_class_name.""") def MI_enumInstanceNames(self, env, ns, cimClass): """Return instance names of a given CIM class Implements the WBEM operation EnumerateInstanceNames in terms of the enum_instances method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_enumInstanceNames called...') provClass = False keys = pywbem.NocaseDict() [keys.__setitem__(p.name, p) for p in cimClass.properties.values()\ if 'key' in p.qualifiers] _strip_quals(keys) path = pywbem.CIMInstanceName(classname=cimClass.classname, namespace=ns) model = pywbem.CIMInstance(classname=cimClass.classname, properties=keys, path=path) gen = self.enum_instances(env=env, model=model, cim_class=cimClass, keys_only=True) try: iter(gen) except TypeError: logger.log_debug('CIMProvider MI_enumInstanceNames returning') return for inst in gen: rval = build_instance_name(inst) yield rval logger.log_debug('CIMProvider MI_enumInstanceNames returning') def MI_enumInstances(self, env, ns, propertyList, requestedCimClass, cimClass): """Return instances of a given CIM class Implements the WBEM operation EnumerateInstances in terms of the enum_instances method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_enumInstances called...') keyNames = get_keys_from_class(cimClass) plist = None if propertyList is not None: lkns = [kn.lower() for kn in keyNames] props = pywbem.NocaseDict() plist = [s.lower() for s in propertyList] pklist = plist + lkns [props.__setitem__(p.name, p) for p in cimClass.properties.values() if p.name.lower() in pklist] else: props = cimClass.properties _strip_quals(props) path = pywbem.CIMInstanceName(classname=cimClass.classname, namespace=ns) model = pywbem.CIMInstance(classname=cimClass.classname, properties=props, path=path) gen = self.enum_instances(env=env, model=model, cim_class=cimClass, keys_only=False) try: iter(gen) except TypeError: logger.log_debug('CIMProvider MI_enumInstances returning') return for inst in gen: inst.path = build_instance_name(inst, keyNames) if self.filter_results and plist is not None: inst = inst.copy() filter_instance(inst, plist) yield inst logger.log_debug('CIMProvider MI_enumInstances returning') def MI_getInstance(self, env, instanceName, propertyList, cimClass): """Return a specific CIM instance Implements the WBEM operation GetInstance in terms of the get_instance method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_getInstance called...') keyNames = get_keys_from_class(cimClass) plist = None if propertyList is not None: lkns = [kn.lower() for kn in keyNames] props = pywbem.NocaseDict() plist = [s.lower() for s in propertyList] pklist = plist + lkns [props.__setitem__(p.name, p) for p in cimClass.properties.values() if p.name.lower() in pklist] else: props = cimClass.properties _strip_quals(props) model = pywbem.CIMInstance(classname=instanceName.classname, properties=props, path=instanceName) for k, v in instanceName.keybindings.items(): type = cimClass.properties[k].type if type != 'reference': v = val = pywbem.tocimobj(type, v) model.__setitem__(k, pywbem.CIMProperty(name=k, type=type, value=v)) rval = self.get_instance(env=env, model=model, cim_class=cimClass) if self.filter_results: filter_instance(rval, plist) logger.log_debug('CIMProvider MI_getInstance returning') if rval is None: raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "") return rval def MI_createInstance(self, env, instance): """Create a CIM instance, and return its instance name Implements the WBEM operation CreateInstance in terms of the set_instance method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_createInstance called...') rval = None ch = env.get_cimom_handle() cimClass = ch.GetClass(instance.classname, instance.path.namespace, LocalOnly=False, IncludeQualifiers=True) # CIMOM has already filled in default property values for # props with default values, if values not supplied by client. rval = self.set_instance(env=env, instance=instance, previous_instance=None, cim_class=cimClass) rval = build_instance_name(rval, cimClass) logger.log_debug('CIMProvider MI_createInstance returning') return rval def MI_modifyInstance(self, env, modifiedInstance, previousInstance, propertyList, cimClass): """Modify a CIM instance Implements the WBEM operation ModifyInstance in terms of the set_instance method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_modifyInstance called...') if propertyList is not None: plist = [p.lower() for p in propertyList] filter_instance(modifiedInstance, plist) modifiedInstance.update(modifiedInstance.path) self.set_instance(env=env, instance=modifiedInstance, previous_instance=previousInstance, cim_class=cimClass) logger.log_debug('CIMProvider MI_modifyInstance returning') def MI_deleteInstance(self, env, instanceName): """Delete a CIM instance Implements the WBEM operation DeleteInstance in terms of the delete_instance method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_deleteInstance called...') self.delete_instance(env=env, instance_name=instanceName) logger.log_debug('CIMProvider MI_deleteInstance returning') def MI_associators(self, env, objectName, assocClassName, resultClassName, role, resultRole, propertyList): """Return instances associated to a given object. Implements the WBEM operation Associators in terms of the references method. A derived class will not normally override this method. """ # NOTE: This should honor the parameters resultClassName, role, resultRole, # and propertyList logger = env.get_logger() logger.log_debug('CIMProvider MI_associators called. assocClass: %s' % (assocClassName)) ch = env.get_cimom_handle() if not assocClassName: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Empty assocClassName passed to Associators") assocClass = ch.GetClass(assocClassName, objectName.namespace, LocalOnly=False, IncludeQualifiers=True) plist = pywbem.NocaseDict() [plist.__setitem__(p.name, p) for p in assocClass.properties.values() if 'key' in p.qualifiers or p.type == 'reference'] _strip_quals(plist) model = pywbem.CIMInstance(classname=assocClass.classname, properties=plist) model.path = pywbem.CIMInstanceName(classname=assocClass.classname, namespace=objectName.namespace) for inst in self.references(env=env, object_name=objectName, model=model, assoc_class=assocClass, result_class_name=resultClassName, role=role, result_role=None, keys_only=False): for prop in inst.properties.values(): lpname = prop.name.lower() if prop.type != 'reference': continue if role and role.lower() == lpname: continue if resultRole and resultRole.lower() != lpname: continue if _path_equals_ignore_host(prop.value, objectName): continue if resultClassName and self.filter_results and \ not pywbem.is_subclass(ch, objectName.namespace, sub=prop.value.classname, super=resultClassName): continue try: if prop.value.namespace is None: prop.value.namespace = objectName.namespace inst = ch.GetInstance(prop.value, IncludeQualifiers=True, IncludeClassOrigin=True, PropertyList=propertyList) except pywbem.CIMError, (num, msg): if num == pywbem.CIM_ERR_NOT_FOUND: continue else: raise if inst.path is None: inst.path = prop.value yield inst logger.log_debug('CIMProvider MI_associators returning') def MI_associatorNames(self, env, objectName, assocClassName, resultClassName, role, resultRole): """Return instances names associated to a given object. Implements the WBEM operation AssociatorNames in terms of the references method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_associatorNames called. assocClass: %s' % (assocClassName)) ch = env.get_cimom_handle() if not assocClassName: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Empty assocClassName passed to AssociatorNames") assocClass = ch.GetClass(assocClassName, objectName.namespace, LocalOnly=False, IncludeQualifiers=True) keys = pywbem.NocaseDict() [keys.__setitem__(p.name, p) for p in assocClass.properties.values() if 'key' in p.qualifiers or p.type == 'reference' ] _strip_quals(keys) model = pywbem.CIMInstance(classname=assocClass.classname, properties=keys) model.path = pywbem.CIMInstanceName(classname=assocClass.classname, namespace=objectName.namespace) for inst in self.references(env=env, object_name=objectName, model=model, assoc_class=assocClass, result_class_name=resultClassName, role=role, result_role=None, keys_only=False): for prop in inst.properties.values(): lpname = prop.name.lower() if prop.type != 'reference': continue if role and role.lower() == lpname: continue if resultRole and resultRole.lower() != lpname: continue if _path_equals_ignore_host(prop.value, objectName): continue if resultClassName and self.filter_results and \ not pywbem.is_subclass(ch, objectName.namespace, sub=prop.value.classname, super=resultClassName): continue if prop.value.namespace is None: prop.value.namespace = objectName.namespace yield prop.value logger.log_debug('CIMProvider MI_associatorNames returning') def MI_references(self, env, objectName, resultClassName, role, propertyList): """Return instances of an association class. Implements the WBEM operation References in terms of the references method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_references called. resultClass: %s' % (resultClassName)) ch = env.get_cimom_handle() if not resultClassName: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Empty resultClassName passed to References") assocClass = ch.GetClass(resultClassName, objectName.namespace, LocalOnly=False, IncludeQualifiers=True) keyNames = get_keys_from_class(assocClass) plist = None if propertyList is not None: lkns = [kn.lower() for kn in keyNames] props = pywbem.NocaseDict() plist = [s.lower() for s in propertyList] pklist = plist + lkns [props.__setitem__(p.name, p) for p in \ assocClass.properties.values() \ if p.name.lower() in pklist] else: props = assocClass.properties _strip_quals(props) model = pywbem.CIMInstance(classname=assocClass.classname, properties=props) model.path = pywbem.CIMInstanceName(classname=assocClass.classname, namespace=objectName.namespace) #if role is None: # raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, # "** this shouldn't happen") if role: if role not in model.properties: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "** this shouldn't happen") model[role] = objectName for inst in self.references(env=env, object_name=objectName, model=model, assoc_class=assocClass, result_class_name='', role=role, result_role=None, keys_only=False): inst.path = build_instance_name(inst, keyNames) if self.filter_results and plist is not None: inst = inst.copy() filter_instance(inst, plist) for prop in inst.properties.values(): if hasattr(prop.value, 'namespace') and prop.value.namespace is None: prop.value.namespace = objectName.namespace yield inst logger.log_debug('CIMProvider MI_references returning') def MI_referenceNames(self, env, objectName, resultClassName, role): """Return instance names of an association class. Implements the WBEM operation ReferenceNames in terms of the references method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_referenceNames <2> called. resultClass: %s' % (resultClassName)) ch = env.get_cimom_handle() if not resultClassName: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Empty resultClassName passed to ReferenceNames") assocClass = ch.GetClass(resultClassName, objectName.namespace, LocalOnly=False, IncludeQualifiers=True) keys = pywbem.NocaseDict() keyNames = [p.name for p in assocClass.properties.values() if 'key' in p.qualifiers] for keyName in keyNames: p = assocClass.properties[keyName] keys.__setitem__(p.name, p) _strip_quals(keys) model = pywbem.CIMInstance(classname=assocClass.classname, properties=keys) model.path = pywbem.CIMInstanceName(classname=assocClass.classname, namespace=objectName.namespace) #if role is None: # raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, # "** this shouldn't happen") if role: if role not in model.properties: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "** this shouldn't happen") model[role] = objectName for inst in self.references(env=env, object_name=objectName, model=model, assoc_class=assocClass, result_class_name='', role=role, result_role=None, keys_only=True): for prop in inst.properties.values(): if hasattr(prop.value, 'namespace') and prop.value.namespace is None: prop.value.namespace = objectName.namespace yield build_instance_name(inst, keyNames) logger.log_debug('CIMProvider MI_referenceNames returning') def MI_invokeMethod(self, env, objectName, metaMethod, inputParams): """Invoke an extrinsic method. Implements the InvokeMethod WBEM operation by calling the method on a derived class called cim_method_, where is the name of the CIM method, in all lower case. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) objectName -- The InstanceName or ClassName of the object on which the method is invoked. metaMethod -- The CIMMethod representing the method to be invoked. inputParams -- A Dictionary where the key is the parameter name and the value is the parameter value. The return value for invokeMethod must be a tuple of size 2 where: element 0 is a tuple of size 2 where element 0 is the return data type name and element 1 is the actual data value. element 1 is a dictionary where the key is the output parameter name and the value is a tuple of size 2 where element 0 is the data type name for the output parameter and element 1 is the actual value of the output parameter. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider MI_invokeMethod called. method: %s:%s' \ % (objectName.classname,metaMethod.name)) lmethName = "cim_method_%s" % metaMethod.name.lower() if hasattr(self, lmethName) : method = getattr(self, lmethName) new_inputs = dict([('param_%s' % k.lower(), v) \ for k, v in inputParams.items()]) (rval, outs) = method(env=env, object_name=objectName, method=metaMethod, **new_inputs) def add_type(v, _tp): lv = v if type(v) == list and len(v) > 0: lv = v[0] if isinstance(lv, pywbem.CIMClass): tp = 'class' elif isinstance(lv, pywbem.CIMInstance): tp = 'instance' elif isinstance(lv, pywbem.CIMInstanceName): tp = 'reference' elif v is None or (type(v) == list and len(v) == 0): tp = _tp else: tp = pywbem.cimtype(v) return (tp, v) for k, v in outs.items(): if hasattr(v, 'namespace') and v.namespace is None: v.namespace = objectName.namespace outs[k] = add_type(v, metaMethod.parameters[k].type) rval = add_type(rval, metaMethod.return_type) rval = (rval, outs) else: raise pywbem.CIMError(pywbem.CIM_ERR_METHOD_NOT_FOUND, "%s:%s"%(objectName.classname, metaMethod.name)) logger.log_debug('CIMProvider MI_invokeMethod returning') return rval def filter_instance(inst, plist): """Remove properties from an instance that aren't in the PropertyList inst -- The CIMInstance plist -- The property List, or None. The list items must be all lowercase. """ if plist is not None: for pname in inst.properties.keys(): if pname.lower() not in plist: del inst.properties[pname] def get_keys_from_class(cc): """Return list of the key property names for a class """ return [prop.name for prop in cc.properties.values() \ if 'key' in prop.qualifiers] def build_instance_name(inst, obj=None): """Return an instance name from an instance, and set instance.path """ if obj is None: for _ in inst.properties.values(): inst.path.keybindings.__setitem__(_.name, _.value) return inst.path if not isinstance(obj, list): return build_instance_name(inst, get_keys_from_class(obj)) keys = {} for _ in obj: if _ not in inst.properties: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Instance of %s is missing key property %s" \ %(inst.classname, _)) keys[_] = inst[_] inst.path = pywbem.CIMInstanceName(classname=inst.classname, keybindings=keys, namespace=inst.path.namespace, host=inst.path.host) return inst.path def _strip_quals(props): for prop in props.values(): # remove all but key quals try: prop.qualifiers = pywbem.NocaseDict({'KEY': prop.qualifiers['KEY']}) except KeyError: prop.qualifiers = pywbem.NocaseDict() def codegen (cc): """Generate a Python Provider template. Parameters: cc - A CIMClass to generate code for. Returns a two-tuple containing the Python provider code stubs, and the provider registration MOF. """ import inspect def format_desc (obj, indent): linelen = 75 - indent if isinstance(obj, basestring): raw = obj else: try: raw = obj.qualifiers['description'].value except KeyError: return '' txt = '' beg = 0 end = 0 while beg < len(raw): beg = end end += linelen while beg < len(raw) and raw[beg].isspace(): beg = beg+1 while end < len(raw) and end > beg and not raw[end].isspace(): end = end-1 if beg == end: # a long URL while end < len(raw) and not raw[end].isspace(): end+= 1 line = raw[beg:end] line = line.replace('\n',' ') line = line.replace('\r','') txt += '\n%s%s'% (''.ljust(indent), line) return txt ################# def map_value(obj, val): rv = str(val) if 'ValueMap' not in obj.qualifiers: return rv if 'Values' not in obj.qualifiers: return rv vals = [str(x) for x in obj.qualifiers['Values'].value] maps = [str(x) for x in obj.qualifiers['ValueMap'].value] d = dict(zip(maps, vals)) try: tmp = d[str(val)] rv = '' for ch in tmp: rv+= ch.isalnum() and ch or '_' except KeyError: pass return rv ################# def type_hint (obj, method_name=None): if hasattr(obj, 'type'): tx = obj.type if 'embeddedinstance' in obj.qualifiers: tx = "pywbem.CIMInstance(classname='%s', ...)" % \ obj.qualifiers['embeddedinstance'].value elif tx == 'reference': tx = "pywbem.CIMInstanceName(classname='%s', ...)" % \ obj.reference_class else: tx = obj.return_type if hasattr(obj, 'value') and obj.value is not None: defval = str(obj.value) else: defval = '' if not tx.startswith('pywbem.'): if tx == 'boolean': tx = 'bool(%s)' % defval elif tx == 'datetime': tx = 'pywbem.CIMDateTime()' elif tx == 'string': tx = "''" else: tx = 'pywbem.%s(%s)' % (tx.capitalize(), defval) if 'valuemap' in obj.qualifiers: if defval: defval = map_value(obj, defval) else: defval = '' tx = 'self.Values.%s%s.%s' % \ (method_name and '%s.'%method_name or '', obj.name, defval) if hasattr(obj, 'is_array') and obj.is_array: tx = '[%s,]' % tx return tx ################# def type_str (obj, method_name=None): if hasattr(obj, 'type'): tx = obj.type if 'embeddedinstance' in obj.qualifiers: return "pywbem.CIMInstance(classname='%s', ...)" % \ obj.qualifiers['embeddedinstance'].value elif tx == 'reference': return "REF (pywbem.CIMInstanceName(classname='%s', ...)" % \ obj.reference_class else: tx = obj.return_type if tx == 'boolean': tx = 'bool' elif tx == 'datetime': tx = 'pywbem.CIMDateTime' elif tx == 'string': tx = 'unicode' else: tx = 'pywbem.%s' % tx.capitalize() if hasattr(obj, 'is_array') and obj.is_array: tx = '[%s,]' % tx if 'valuemap' in obj.qualifiers: tx+= ' self.Values.%s%s' % \ (method_name and '%s.'%method_name or '',obj.name) return tx ################# def is_required (obj): if 'required' in obj.qualifiers and obj.qualifiers['required'].value: return '(Required)' return '' ################# def build_val_map(obj): vm = obj.qualifiers['valuemap'].value if 'values' in obj.qualifiers: vals = obj.qualifiers['values'].value else: vals = vm tmap = zip(vals,vm) map = [] for t in tmap: nname = '' for ch in t[0]: if ch.isalnum(): nname+= ch else: nname+= '_' if hasattr(obj, 'return_type'): tp = obj.return_type else: tp = obj.type if tp == 'string': val = "'%s'" % t[1] else: try: int(t[1]) val = 'pywbem.%s(%s)' % (tp.capitalize(), t[1]) except ValueError: val = t[1] nname = "# "+nname map.append((nname,val)) return map valuemaps = {} for obj in cc.properties.values() + cc.methods.values(): if 'valuemap' in obj.qualifiers: valuemaps[obj.name] = {'':build_val_map(obj)} for meth in cc.methods.values(): for parm in meth.parameters.values(): if 'valuemap' in parm.qualifiers: if meth.name not in valuemaps: valuemaps[meth.name] = {} valuemaps[meth.name][parm.name] = build_val_map(parm) mappings = {'classname':cc.classname, 'classname_l':cc.classname.lower()} isAssoc = 'association' in cc.qualifiers code = '''"""Python Provider for %(classname)s Instruments the CIM class %(classname)s """ import pywbem class %(classname)sProvider(pywbem.CIMProvider): """Instrument the CIM class %(classname)s \n''' % mappings code+= format_desc(cc, 4) code+= ''' """''' args = inspect.getargspec(CIMProvider.get_instance)[0] args = ', '.join(args) code+= ''' def __init__ (self, env): logger = env.get_logger() logger.log_debug('Initializing provider %%s from %%s' \\ %% (self.__class__.__name__, __file__)) # If you will be filtering instances yourself according to # property_list, role, result_role, and result_class_name # parameters, set self.filter_results to False # self.filter_results = False def get_instance(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.get_instance()' \\ %% self.__class__.__name__) ''' % (args, CIMProvider.get_instance.__doc__ ) keyProps = [p for p in cc.properties.values() \ if 'key' in p.qualifiers] code+= ''' ux = model.update_existing # TODO fetch system resource matching the following keys:''' for kp in keyProps: code+= ''' # model['%s']''' % kp.name code+= '\n' props = cc.properties.values() props.sort() for prop in props: if 'key' in prop.qualifiers: continue #line = "#ux(%s=%s) # TODO (type = %s) %s" % \ # (prop.name, type_hint(prop), type_str(prop), is_required(prop)) line = "#ux(%s=%s) # TODO %s" % \ (prop.name, type_hint(prop), is_required(prop)) code+= ''' %s''' % line args = inspect.getargspec(CIMProvider.enum_instances)[0] args = ', '.join(args) code+= ''' return model def enum_instances(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.enum_instances()' \\ %% self.__class__.__name__) while False: # TODO more instances? # TODO fetch system resource # Key properties''' % (args, CIMProvider.enum_instances.__doc__) for kp in keyProps: if kp.name == 'CreationClassName': line = "model['%s'] = '%s'" % (kp.name, cc.classname) else: line = "#model['%s'] = # TODO (type = %s)" % \ (kp.name, type_str(kp)) code+=''' %s''' % line code+=''' if keys_only: yield model else: try: yield self.get_instance(env, model, cim_class) except pywbem.CIMError, (num, msg): if num not in (pywbem.CIM_ERR_NOT_FOUND, pywbem.CIM_ERR_ACCESS_DENIED): raise\n''' args = inspect.getargspec(CIMProvider.set_instance)[0] args = ', '.join(args) code+= ''' def set_instance(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.set_instance()' \\ %% self.__class__.__name__) # TODO create or modify the instance raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement return instance''' % (args, CIMProvider.set_instance.__doc__) args = inspect.getargspec(CIMProvider.delete_instance)[0] args = ', '.join(args) code+= ''' def delete_instance(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.delete_instance()' \\ %% self.__class__.__name__) # TODO delete the resource raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement ''' % (args, CIMProvider.delete_instance.__doc__) for method in cc.methods.values(): inParms = [ p for p in method.parameters.values() if \ 'in' in p.qualifiers and p.qualifiers['in'].value ] outParms = [ p for p in method.parameters.values() if \ 'out' in p.qualifiers and p.qualifiers['out'].value ] code+= ''' def cim_method_%s(self, env, object_name, method''' % method.name.lower() for p in inParms: code+= ''',\n%sparam_%s''' % (''.rjust(len(method.name)+20), p.name.lower()) code+= '''): """Implements %s.%s()\n''' % (cc.classname, method.name) code+= format_desc(method, 8) code+= ''' Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName specifying the object on which the method %s() should be invoked. method -- A pywbem.CIMMethod representing the method meta-data'''\ % method.name for p in inParms: code+= ''' param_%s -- The input parameter %s (type %s) %s''' \ % (p.name.lower(), p.name, type_str(p, method.name), is_required(p)) code+= format_desc(p, 12) code+=''' Returns a two-tuple containing the return value (type %s) and a dictionary with the out-parameters Output parameters:''' % type_str(method) if not outParms: code+= ' none' else: for p in outParms: code+=''' %s -- (type %s) %s''' % (p.name, type_str(p, method.name), is_required(p)) code+= format_desc(p, 12) code+=''' Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_NOT_FOUND (the target CIM Class or instance does not exist in the specified namespace) CIM_ERR_METHOD_NOT_AVAILABLE (the CIM Server is unable to honor the invocation request) CIM_ERR_FAILED (some other unspecified error occurred) """ logger = env.get_logger() logger.log_debug('Entering %%s.cim_method_%s()' \\ %% self.__class__.__name__) # TODO do something raise pywbem.CIMError(pywbem.CIM_ERR_METHOD_NOT_AVAILABLE) # Remove to implemented out_params = {}''' % method.name.lower() for p in outParms: code+=''' #out_params['%s'] = %s # TODO''' % (p.name.lower(), type_hint(p, method.name)) code+=''' rval = None # TODO (type %s) return (rval, out_params) ''' % type_str(method) if isAssoc: args = inspect.getargspec(CIMProvider.references)[0] args = format_desc(', '.join(args), 19).strip() code+= ''' def references(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.references()' \\ %% self.__class__.__name__) ch = env.get_cimom_handle() # This is a common pattern. YMMV''' % \ (args, CIMProvider.references.__doc__) refprops = [] for prop in cc.properties.values(): if prop.reference_class is not None: refprops.append((prop.name, prop.reference_class)) for refprop in refprops: code+= ''' if (not role or role.lower() == '%(refpropnamel)s') and \\ pywbem.is_subclass(ch, object_name.namespace, sub=object_name.classname, super='%(rolecname)s'): model['%(refpropname)s'] = object_name yield model # TODO: Add other REF properties. # Yield association instances where # object_name is %(refpropnamel)s. # Only appropriate if object_name.classname # is '%(rolecname)s' or a subclass.\n''' \ % {'refpropname':refprop[0], 'refpropnamel':refprop[0].lower(), 'rolecname':refprop[1]} if valuemaps: code+= ''' class Values(object):''' for group, maps in valuemaps.items(): code+= ''' class %s(object):''' % group if '' in maps: for value, vm in maps['']: if value in maps: value = value+'_' code+= ''' %s = %s''' % (value, vm) for pname, vms in maps.items(): if pname == '': continue code+= ''' class %s(object):''' % pname for value, vm in vms: code+= ''' %s = %s''' % (value, vm) code+= '\n' code+= ''' ## end of class %(classname)sProvider def get_providers(env): %(classname_l)s_prov = %(classname)sProvider(env) return {'%(classname)s': %(classname_l)s_prov} ''' % mappings owtypes = ['1', 'Instance'] pegtypes = ['2', 'Instance'] if isAssoc: owtypes[0]+= ',3' owtypes[1]+= ', Associator' pegtypes[0]+= ',3' pegtypes[1]+= ', Associator' if cc.methods: owtypes[0]+= ',6' owtypes[1]+= ', Method' pegtypes[0]+= ',5' pegtypes[1]+= ', Method' mof =''' // OpenWBEM Provider registration for %(classname)s instance of OpenWBEM_PyProviderRegistration { InstanceID = ""; // TODO NamespaceNames = {"root/cimv2"}; // TODO ClassName = "%(classname)s"; ProviderTypes = {%(owtypeNums)s}; // %(owtypeStrs)s ModulePath = "/usr/lib/pycim/%(classname)sProvider.py"; // TODO }; // Pegasus Provider registration for %(classname)s instance of PG_ProviderModule { Name = "/usr/lib/pycim/%(classname)sProvider.py"; InterfaceType = "Python"; InterfaceVersion = "1.0.0"; Location = "/usr/lib/pycim/%(classname)sProvider.py"; UserContext = 2; // Requestor Vendor = "TODO"; // TODO Version = "1.0"; }; instance of PG_Provider { Name = "%(classname)s"; ProviderModuleName = "/usr/lib/pycim/%(classname)sProvider.py"; }; instance of PG_ProviderCapabilities { CapabilityID = "%(classname)s"; ProviderModuleName = "/usr/lib/pycim/%(classname)sProvider.py"; ProviderName = "%(classname)s"; ClassName = "%(classname)s"; Namespaces = {"root/cimv2"}; // TODO ProviderType = {%(pegtypeNum)s}; // %(pegtypeStr)s };\n''' % {'classname': cc.classname, 'owtypeNums': owtypes[0], 'owtypeStrs': owtypes[1], 'pegtypeNum': pegtypes[0], 'pegtypeStr': pegtypes[1]} return code, mof class ProviderProxy(object): """Wraps a provider module, and routes requests into the module """ def __init__ (self, env, provid): if isinstance(provid, types.ModuleType): self.provmod = provid self.provid = provid.__name__ self.filename = provid.__file__ else: self.provid = provid # odd chars in a module name tend to break things provider_name = 'pyprovider_' for ch in provid: provider_name+= ch.isalnum() and ch or '_' # let providers import other providers in the same directory provdir = dirname(provid) if provdir not in sys.path: sys.path.append(provdir) # use full path in module name for uniqueness. try: self.provmod = load_source(provider_name, provid) except IOError, arg: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Error loading provider %s: %s" % (provid, arg)) self.filename = self.provmod.__file__ self.provregs = {} if hasattr(self.provmod, 'init'): self.provmod.init(env) if hasattr(self.provmod, 'get_providers'): self.provregs = pywbem.NocaseDict(self.provmod.get_providers(env)) def _get_callable (self, classname, cname): """Return a function or method object appropriate to fulfill a request classname -- The CIM class name associated with the request. cname -- The function or method name to look for. """ callable = None if classname in self.provregs: provClass = self.provregs[classname] if hasattr(provClass, cname): callable = getattr(provClass, cname) elif hasattr(self.provmod, cname): callable = getattr(self.provmod, cname) if callable is None: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "No callable for %s:%s on provider %s"%(classname, cname, self.provid)) return callable ############################################################################## # enumInstanceNames ############################################################################## def MI_enumInstanceNames (self, env, ns, cimClass): logger = env.get_logger() logger.log_debug('ProviderProxy MI_enumInstanceNames called...') for i in self._get_callable(cimClass.classname, 'MI_enumInstanceNames') \ (env, ns, cimClass): yield i logger.log_debug('CIMProvider MI_enumInstanceNames returning') ############################################################################## # enumInstances ############################################################################## def MI_enumInstances(self, env, ns, propertyList, requestedCimClass, cimClass): logger = env.get_logger() logger.log_debug('CIMProvider MI_enumInstances called...') for i in self._get_callable(cimClass.classname, 'MI_enumInstances') \ (env, ns, propertyList, requestedCimClass, cimClass): yield i logger.log_debug('CIMProvider MI_enumInstances returning') ############################################################################## # getInstance ############################################################################## def MI_getInstance(self, env, instanceName, propertyList, cimClass): logger = env.get_logger() logger.log_debug('CIMProvider MI_getInstance called...') rval = self._get_callable(cimClass.classname, 'MI_getInstance') \ (env, instanceName, propertyList, cimClass) logger.log_debug('CIMProvider MI_getInstance returning') return rval ############################################################################## # createInstance ############################################################################## def MI_createInstance(self, env, instance): logger = env.get_logger() logger.log_debug('CIMProvider MI_createInstance called...') rval = self._get_callable(instance.classname, 'MI_createInstance') \ (env, instance) logger.log_debug('CIMProvider MI_createInstance returning') return rval ############################################################################## # modifyInstance ############################################################################## def MI_modifyInstance(self, env, modifiedInstance, previousInstance, propertyList, cimClass): logger = env.get_logger() logger.log_debug('CIMProvider MI_modifyInstance called...') self._get_callable(cimClass.classname, 'MI_modifyInstance') \ (env, modifiedInstance, previousInstance, propertyList, cimClass) logger.log_debug('CIMProvider MI_modifyInstance returning') ############################################################################## # deleteInstance ############################################################################## def MI_deleteInstance(self, env, instanceName): logger = env.get_logger() logger.log_debug('CIMProvider MI_deleteInstance called...') self._get_callable(instanceName.classname, 'MI_deleteInstance') \ (env, instanceName) logger.log_debug('CIMProvider MI_deleteInstance returning') ############################################################################## # associators ############################################################################## def MI_associators(self, env, objectName, assocClassName, resultClassName, role, resultRole, propertyList): # NOTE: This should honor the parameters resultClassName, role, resultRole, # and propertyList logger = env.get_logger() logger.log_debug('CIMProvider MI_associators called. assocClass: %s' % (assocClassName)) cname = assocClassName for i in self._get_callable(cname, 'MI_associators') \ (env, objectName, assocClassName, resultClassName, role, resultRole, propertyList): yield i logger.log_debug('CIMProvider MI_associators returning') ############################################################################## # associatorNames ############################################################################## def MI_associatorNames(self, env, objectName, assocClassName, resultClassName, role, resultRole): logger = env.get_logger() logger.log_debug('CIMProvider MI_associatorNames called. assocClass: %s' % (assocClassName)) cname = assocClassName for i in self._get_callable(cname, 'MI_associatorNames') \ (env, objectName, assocClassName, resultClassName, role, resultRole): yield i logger.log_debug('CIMProvider MI_associatorNames returning') ############################################################################## # references ############################################################################## def MI_references(self, env, objectName, resultClassName, role, propertyList): logger = env.get_logger() logger.log_debug('CIMProvider MI_references called. resultClass: %s' % (resultClassName)) cname = resultClassName if not cname: return for i in self._get_callable(cname, 'MI_references') \ (env, objectName, resultClassName, role, propertyList): yield i logger.log_debug('CIMProvider MI_references returning') ############################################################################## # referenceNames ############################################################################## def MI_referenceNames(self, env, objectName, resultClassName, role): logger = env.get_logger() logger.log_debug('CIMProvider MI_referenceNames <1> called. resultClass: %s' % (resultClassName)) cname = resultClassName if not cname: return for i in self._get_callable(cname, 'MI_referenceNames') \ (env, objectName, resultClassName, role): yield i logger.log_debug('CIMProvider MI_referenceNames returning') ############################################################################## # invokeMethod # inputParam is a Dictionary where the key is the parameter name # and the value is the parameter value # The return value for invokeMethod must be a tuple of size 2 where # element 0 is a tuple of size 2 where element 0 is the return data type name # and element 1 is the actual data value # element 1 is a dictionary where the key is the output parameter name # and the value is a tuple of size 2 where element 0 is the data type name # for the output parameter and element 1 is the actual value of the # output parameter. ############################################################################## def MI_invokeMethod(self, env, objectName, metaMethod, inputParams): logger = env.get_logger() logger.log_debug('CIMProvider MI_invokeMethod called. method: %s:%s' \ % (objectName.classname,metaMethod.name)) rval = self._get_callable(objectName.classname, 'MI_invokeMethod') \ (env, objectName, metaMethod, inputParams) logger.log_debug('CIMProvider MI_invokeMethod returning') return rval ############################################################################## def MI_poll (self, env): logger = env.get_logger() logger.log_debug('CIMProvider MI_poll called') if hasattr(self.provmod, 'poll'): rval = self.provmod.poll(env) elif hasattr(self.provmod, 'MI_poll'): rval = self.provmod.MI_poll(env) else: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Provider %s has no support for polling"%self.provid) logger.log_debug('CIMProvider MI_poll returning %s' % str(rval)) return rval ############################################################################## def MI_getInitialPollingInterval (self, env): logger = env.get_logger() logger.log_debug('CIMProvider MI_poll called') if hasattr(self.provmod, 'get_initial_polling_interval'): rval = self.provmod.get_initial_polling_interval(env) elif hasattr(self.provmod, 'MI_getInitialPollingInterval'): rval = self.provmod.MI_getInitialPollingInterval(env) else: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Provider %s has no support for polling"%self.provid) logger.log_debug('CIMProvider MI_poll returning %s' % str(rval)) return rval ############################################################################## def MI_activateFilter (self, env, filter, namespace, classes, firstActivation): logger = env.get_logger() logger.log_debug('CIMProvider MI_activateFilter called') if hasattr(self.provmod, 'activate_filter'): self.provmod.activate_filter(env, filter, namespace, classes, firstActivation) elif hasattr(self.provmod, 'MI_activateFilter'): self.provmod.MI_activateFilter(env, filter, namespace, classes, firstActivation) else: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Provider %s has no support for activate filter"%self.provid) logger.log_debug('CIMProvider MI_activateFilter returning') ############################################################################## def MI_deActivateFilter(self, env, filter, namespace, classes, lastActivation): logger = env.get_logger() logger.log_debug('CIMProvider MI_deActivateFilter called') if hasattr(self.provmod, 'deactivate_filter'): self.provmod.deactivate_filter(env, filter, namespace, classes, lastActivation) elif hasattr(self.provmod, 'MI_deActivateFilter'): self.provmod.MI_deActivateFilter(env, filter, namespace, classes, lastActivation) else: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Provider %s has no support for deactivate filter"%self.provid) logger.log_debug('CIMProvider MI_deActivateFilter returning') ############################################################################## def MI_shutdown (self, env): modname = self.provmod.__name__ if hasattr(self.provmod, "shutdown"): self.provmod.shutdown(env) self.provmod = None del sys.modules[modname] #TODO concurrency problems here?? ############################################################################## def MI_canunload(self, env): if hasattr(self.provmod, "canunload"): return self.provmod.canunload else: return True ############################################################################## def MI_consumeIndication(self, env, destinationPath, indicationInstance): logger = env.get_logger() logger.log_debug('ProviderProxy MI_consumeIndication called') if hasattr(self.provmod, 'consume_indication'): self.provmod.consume_indication(env, destinationPath, indicationInstance) elif hasattr(self.provmod, 'MI_consumeIndication'): self.provmod.MI_consumeIndication(env, destinationPath, indicationInstance) else: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Provider %s has no support for consume indication" % \ self.provid) logger.log_debug('ProviderProxy MI_consumeIndication returning') ############################################################################## def MI_handleIndication(self, env, ns, handlerInstance, indicationInstance): logger = env.get_logger() logger.log_debug('ProviderProxy MI_handleIndication called') if hasattr(self.provmod, 'handle_indication'): self.provmod.handle_indication(env, ns, handlerInstance, indicationInstance) elif hasattr(self.provmod, 'MI_handleIndication'): self.provmod.MI_handleIndication(env, ns, handlerInstance, indicationInstance) else: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Provider %s has no support for handle indication"%self.provid) logger.log_debug('ProviderProxy MI_handleIndication returning') pywbem-0.8.0~dev/pywbem/tupleparse.py0000644000175000017500000012230612413747174017670 0ustar bzedbzed00000000000000# # (C) Copyright 2003, 2004 Hewlett-Packard Development Company, L.P. # (C) Copyright 2006-2007 Novell, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Martin Pool # Tim Potter # Bart Whiteley '''Tuple parser for the XML schema representing CIM messages. This framework is meant to add some value to the tuple-tree representation of CIM in XML by having the following properties: - Silently ignoring whitespace text elements - Conversion from tuple-tree representation into a python dictionary which can then be accessed in a readable fashion. - Validation of the XML elements and attributes without having to use the DTD file or any external tools. ''' # Implementation: this works by a recursive descent down the CIM XML # tupletree. As we walk down, we produce cim_obj and cim_type # objects representing the CIM message in digested form. # For each XML node type FOO there is one function parse_foo, which # returns the digested form by examining a tuple tree rooted at FOO. # The resulting objects are constrained to the shape of the CIM XML # tree: if one node in XML contains another, then the corresponding # CIM object will contain the second. However, there can be local # transformations at each node: some levels are ommitted, some are # transformed into lists or hashes. # We try to validate that the tree is well-formed too. The validation # is more strict than the DTD, but it is forgiving of implementation # quirks and bugs in Pegasus. # Bear in mind in the parse functions that each tupletree tuple is # structured as # tt[0]: name string == name(tt) # tt[1]: hash of attributes == attrs(tt) # tt[2]: sequence of children == kids(tt) # At the moment this layer is a little inconsistent: in some places it # returns tupletrees, and in others Python objects. It may be better # to hide the tupletree/XML representation from higher level code. # TODO: Maybe take a DTD fragment like "(DECLGROUP | # DECLGROUP.WITHNAME | DECLGROUP.WITHPATH)*", parse that and check it # directly. # TODO: Syntax-check some attributes with defined formats, such as NAME # TODO: Implement qualifiers by making subclasses of CIM types with a # .qualifiers property. import string, types from types import StringTypes from pywbem import cim_obj from pywbem.cim_obj import CIMProperty, byname from pywbem.tupletree import xml_to_tupletree class ParseError(Exception): """This exception is raised when there is a validation error detected by the parser.""" pass def filter_tuples(l): """Return only the tuples in a list. In a tupletree, tuples correspond to XML elements. Useful for stripping out whitespace data in a child list.""" if l is None: return [] else: return [x for x in l if type(x) == tuple] def pcdata(tt): """Return the concatenated character data within a tt. The tt must not have non-character children.""" import types for x in tt[2]: if not isinstance(x, types.StringTypes): raise ParseError, 'unexpected node %s under %s' % (`x`, `tt`) return ''.join(tt[2]) def name(tt): return tt[0] def attrs(tt): return tt[1] def kids(tt): return filter_tuples(tt[2]) def check_node(tt, nodename, required_attrs = [], optional_attrs = [], allowed_children = None, allow_pcdata = False): """Check static local constraints on a single node. The node must have the given name. The required attrs must be present, and the optional attrs may be. If allowed_children is not None, the node may have children of the given types. It can be [] for nodes that may not have any children. If it's None, it is assumed the children are validated in some other way. If allow_pcdata is true, then non-whitespace text children are allowed. (Whitespace text nodes are always allowed.) """ if name(tt) <> nodename: raise ParseError('expected node type %s, not %s' % (nodename, name(tt))) # Check we have all the required attributes, and no unexpected ones tt_attrs = {} if attrs(tt) is not None: tt_attrs = attrs(tt).copy() for attr in required_attrs: if not tt_attrs.has_key(attr): raise ParseError('expected %s attribute on %s node, but only ' 'have %s' % (attr, name(tt),attrs(tt).keys())) del tt_attrs[attr] for attr in optional_attrs: if tt_attrs.has_key(attr): del tt_attrs[attr] if len(tt_attrs.keys()) > 0: raise ParseError('invalid extra attributes %s' % tt_attrs.keys()) if allowed_children is not None: for c in kids(tt): if name(c) not in allowed_children: raise ParseError('unexpected node %s under %s; wanted %s' % (name(c), name(tt), allowed_children)) if not allow_pcdata: for c in tt[2]: if isinstance(c, types.StringTypes): if c.lstrip(' \t\n') <> '': raise ParseError('unexpected non-blank pcdata node %s ' 'under %s' % (`c`, name(tt))) def one_child(tt, acceptable): """Parse children of a node with exactly one child node. PCData is ignored. """ k = kids(tt) if len(k) <> 1: raise ParseError('In element %s with attributes %s, expected just '\ 'one child element %s, but got child elements %s' %\ (name(tt), attrs(tt), acceptable, [t[0] for t in k])) child = k[0] if name(child) not in acceptable: raise ParseError('In element %s with attributes %s, expected one '\ 'child element %s, but got child element %s' %\ (name(tt), attrs(tt), acceptable, name(child))) return parse_any(child) def optional_child(tt, allowed): """Parse exactly zero or one of a list of elements from the child nodes.""" k = kids(tt) if len(k) > 1: raise ParseError('In element %s with attributes %s, expected zero or '\ 'one child element %s, but got child elements %s' %\ (name(tt), attrs(tt), allowed, [t[0] for t in k])) elif len(k) == 1: return one_child(tt, allowed) else: return None def list_of_various(tt, acceptable): """Parse zero or more of a list of elements from the child nodes. Each element of the list can be any type from the list of acceptable nodes.""" r = [] for child in kids(tt): if name(child) not in acceptable: raise ParseError('In element %s with attributes %s, expected zero '\ 'or more child elements %s, but got child element %s' %\ (name(tt), attrs(tt), acceptable, name(child))) r.append(parse_any(child)) return r def list_of_matching(tt, matched): """Parse only the children of particular types under tt. Other children are ignored rather than giving an error.""" r = [] for child in kids(tt): if name(child) not in matched: continue r.append(parse_any(child)) return r def list_of_same(tt, acceptable): """Parse a list of elements from child nodes. The children can be any of the listed acceptable types, but they must all be the same. """ k = kids(tt) if not k: # empty list, consistent with list_of_various return [] w = name(k[0]) if w not in acceptable: raise ParseError('In element %s with attributes %s, expected child '\ 'elements %s, but got child element %s' %\ (name(tt), attrs(tt), acceptable, w)) r = [] for child in k: if name(child) <> w: raise ParseError('In element %s with attributes %s, expected '\ 'sequence of only child elements %s, but got child '\ 'element %s' % (name(tt), attrs(tt), w, name(child))) r.append(parse_any(child)) return r def notimplemented(tt): raise ParseError('parser for %s not implemented' % name(tt)) # # Root element # def parse_cim(tt): """ """ check_node(tt, 'CIM', ['CIMVERSION', 'DTDVERSION']) if not attrs(tt)['CIMVERSION'].startswith('2.'): raise ParseError('CIMVERSION is %s, expected 2.x.y' % attrs(tt)['CIMVERSION']) child = one_child(tt, ['MESSAGE', 'DECLARATION']) return name(tt), attrs(tt), child # # Object value elements # def parse_value(tt): '''Return VALUE contents as a string''' ## check_node(tt, 'VALUE', [], [], [], True) return pcdata(tt) def parse_value_array(tt): """Return list of strings.""" ## check_node(tt, 'VALUE.ARRAY', [], [], ['VALUE']) return list_of_same(tt, ['VALUE']) def parse_value_reference(tt): """ """ check_node(tt, 'VALUE.REFERENCE', []) child = one_child(tt, ['CLASSPATH', 'LOCALCLASSPATH', 'CLASSNAME', 'INSTANCEPATH', 'LOCALINSTANCEPATH', 'INSTANCENAME']) # The VALUE.REFERENCE wrapper element is discarded return child def parse_value_refarray(tt): """ """ check_node(tt, 'VALUE.REFARRAY') children = list_of_various(tt, ['VALUE.REFERENCE']) # The VALUE.REFARRAY wrapper element is discarded return children def parse_value_object(tt): """ """ check_node(tt, 'VALUE.OBJECT') child = one_child(tt, ['CLASS', 'INSTANCE', 'QUALIFIER.DECLARATION']) return (name(tt), attrs(tt), child) def parse_value_namedinstance(tt): """ """ check_node(tt, 'VALUE.NAMEDINSTANCE') k = kids(tt) if len(k) <> 2: raise ParseError('expecting (INSTANCENAME, INSTANCE), got %s' % `k`) instancename = parse_instancename(k[0]) instance = parse_instance(k[1]) instance.path = instancename return instance def parse_value_namedobject(tt): """ """ check_node(tt, 'VALUE.NAMEDOBJECT') k = kids(tt) if len(k) == 1: object = parse_class(k[0]) elif len(k) == 2: path = parse_instancename(kids(tt)[0]) object = parse_instance(kids(tt)[1]) object.path = path else: raise ParseError('Expecting one or two elements, got %s' % `kids(tt)`) return (name(tt), attrs(tt), object) def parse_value_objectwithlocalpath(tt): """ """ check_node(tt, 'VALUE.OBJECTWITHLOCALPATH') if len(kids(tt)) != 2: raise ParseError('Expecting two elements, got %s' % len(kids(tt))); if kids(tt)[0][0] == 'LOCALCLASSPATH': object = (parse_localclasspath(kids(tt)[0]), parse_class(kids(tt)[1])) else: path = parse_localinstancepath(kids(tt)[0]) object = parse_instance(kids(tt)[1]) object.path = path return (name(tt), attrs(tt), object) def parse_value_objectwithpath(tt): """ """ check_node(tt, 'VALUE.OBJECTWITHPATH') k = kids(tt) if len(k) != 2: raise ParseError('Expecting two elements, got %s' % k) if name(k[0]) == 'CLASSPATH': object = (parse_classpath(k[0]), parse_class(k[1])) else: path = parse_instancepath(k[0]) object = parse_instance(k[1]) object.path = path return (name(tt), attrs(tt), object) # # Object naming and locating elements # def parse_namespacepath(tt): """ """ check_node(tt, 'NAMESPACEPATH') if len(kids(tt)) != 2: raise ParseError('Expecting (HOST, LOCALNAMESPACEPATH) ' 'got %s' % kids(tt).keys()) host = parse_host(kids(tt)[0]) localnspath = parse_localnamespacepath(kids(tt)[1]) return (host, localnspath) def parse_localnamespacepath(tt): """ """ check_node(tt, 'LOCALNAMESPACEPATH', [], [], ['NAMESPACE']) if len(kids(tt)) == 0: raise ParseError('Expecting one or more of NAMESPACE, got nothing') ns_list = list_of_various(tt, ['NAMESPACE']) return string.join(ns_list, '/') def parse_host(tt): """ """ check_node(tt, 'HOST', allow_pcdata=True) return pcdata(tt) def parse_namespace(tt): """ """ check_node(tt, 'NAMESPACE', ['NAME'], [], []) return attrs(tt)['NAME'] def parse_classpath(tt): """ """ check_node(tt, 'CLASSPATH') if len(kids(tt)) != 2: raise ParseError('Expecting (NAMESPACEPATH, CLASSNAME) ' 'got %s' % kids(tt).keys()) nspath = parse_namespacepath(kids(tt)[0]) classname = parse_classname(kids(tt)[1]) return cim_obj.CIMClassName(classname.classname, host = nspath[0], namespace = nspath[1]) def parse_localclasspath(tt): """ """ check_node(tt, 'LOCALCLASSPATH') if len(kids(tt)) != 2: raise ParseError('Expecting (LOCALNAMESPACEPATH, CLASSNAME) ' 'got %s' % kids(tt).keys()) localnspath = parse_localnamespacepath(kids(tt)[0]) classname = parse_classname(kids(tt)[1]) return cim_obj.CIMClassName(classname.classname, namespace = localnspath) def parse_classname(tt): """ """ check_node(tt, 'CLASSNAME', ['NAME'], [], []) return cim_obj.CIMClassName(attrs(tt)['NAME']) def parse_instancepath(tt): """ """ check_node(tt, 'INSTANCEPATH') if len(kids(tt)) != 2: raise ParseError('Expecting (NAMESPACEPATH, INSTANCENAME), got %s' % `kids(tt)`) nspath = parse_namespacepath(kids(tt)[0]) instancename = parse_instancename(kids(tt)[1]) instancename.host = nspath[0] instancename.namespace = nspath[1] return instancename def parse_localinstancepath(tt): """ """ check_node(tt, 'LOCALINSTANCEPATH') if len(kids(tt)) != 2: raise ParseError('Expecting (LOCALNAMESPACEPATH, INSTANCENAME), ' 'got %s' % kids(tt).keys()) localnspath = parse_localnamespacepath(kids(tt)[0]) instancename = parse_instancename(kids(tt)[1]) instancename.namespace = localnspath return instancename def parse_instancename(tt): """Parse XML INSTANCENAME into CIMInstanceName object.""" ## ## from cim_obj import CIMInstanceName check_node(tt, 'INSTANCENAME', ['CLASSNAME']) if len(kids(tt)) == 0: # probably not ever going to see this, but it's valid # according to the grammar return CIMInstanceName(attrs(tt)['CLASSNAME'], {}) k0 = kids(tt)[0] w = name(k0) classname = attrs(tt)['CLASSNAME'] if w == 'KEYVALUE' or w == 'VALUE.REFERENCE': if len(kids(tt)) != 1: raise ParseError('expected only one %s under %s' % w, name(tt)) # FIXME: This is probably not the best representation of these forms... val = parse_any(k0) return CIMInstanceName(classname, {None: val}) elif w == 'KEYBINDING': kbs = {} for kb in list_of_various(tt, ['KEYBINDING']): kbs.update(kb) return CIMInstanceName(classname, kbs) else: raise ParseError('unexpected node %s under %s' % (name(kids(tt)[0]), name(tt))) def parse_objectpath(tt): """ """ check_node(tt, 'OBJECTPATH') child = one_child(tt, ['INSTANCEPATH', 'CLASSPATH']) return (name(tt), attrs(tt), child) def parse_keybinding(tt): ## ## """Returns one-item dictionary from name to Python value.""" check_node(tt, 'KEYBINDING', ['NAME']) child = one_child(tt, ['KEYVALUE', 'VALUE.REFERENCE']) return {attrs(tt)['NAME']: child} def parse_keyvalue(tt): ## ## """Parse VALUETYPE into Python primitive value""" check_node(tt, 'KEYVALUE', ['VALUETYPE'], ['TYPE'], [], True) p = pcdata(tt) if not attrs(tt).has_key('VALUETYPE'): return p; vt = attrs(tt).get('VALUETYPE') if vt == 'string': return p elif vt == 'boolean': return unpack_boolean(p) elif vt == 'numeric': try: # XXX: Use TYPE attribute to create named CIM type. # if attrs(tt).has_key('TYPE'): # return cim_obj.tocimobj(attrs(tt)['TYPE'], p.strip()) # XXX: Would like to use long() here, but that tends to cause # trouble when it's written back out as '2L' return int(p.strip()) except ValueError, e: raise ParseError('invalid numeric %s under %s' % (`p`, name(tt))) else: raise ParseError('invalid VALUETYPE %s in %s', vt, name(tt)) # # Object definition elements # def parse_class(tt): ## ## # This doesn't check the ordering of elements, but it's not very important check_node(tt, 'CLASS', ['NAME'], ['SUPERCLASS'], ['QUALIFIER', 'PROPERTY', 'PROPERTY.REFERENCE', 'PROPERTY.ARRAY', 'METHOD']) superclass = attrs(tt).get('SUPERCLASS') # TODO: Return these as maps, not lists properties = byname(list_of_matching(tt, ['PROPERTY', 'PROPERTY.REFERENCE', 'PROPERTY.ARRAY'])) qualifiers = byname(list_of_matching(tt, ['QUALIFIER'])) methods = byname(list_of_matching(tt, ['METHOD'])) return cim_obj.CIMClass(attrs(tt)['NAME'], superclass=superclass, properties=properties, qualifiers=qualifiers, methods=methods) def parse_instance(tt): """Return a CIMInstance. The instance contains the properties, qualifiers and classname for the instance""" ## ## check_node(tt, 'INSTANCE', ['CLASSNAME'], ['QUALIFIER', 'PROPERTY', 'PROPERTY.ARRAY', 'PROPERTY.REFERENCE']) ## XXX: This does not enforce ordering constraint ## XXX: This does not enforce the constraint that there be only ## one PROPERTY or PROPERTY.ARRAY. ## TODO: Parse instance qualifiers qualifiers = {} props = list_of_matching(tt, ['PROPERTY.REFERENCE', 'PROPERTY', 'PROPERTY.ARRAY']) obj = cim_obj.CIMInstance(attrs(tt)['CLASSNAME'], qualifiers = qualifiers) [obj.__setitem__(p.name, p) for p in props] return obj def parse_scope(tt): # # ## check_node(tt, 'QUALIFIER.DECLARATION', ['NAME', 'TYPE'], ['ISARRAY', 'ARRAYSIZE', 'OVERRIDABLE', 'TOSUBCLASS', 'TOINSTANCE', 'TRANSLATABLE'], ['SCOPE', 'VALUE', 'VALUE.ARRAY']) a = attrs(tt) qname = a['NAME'] type = a['TYPE'] try: is_array = a['ISARRAY'].lower() == 'true' except KeyError: is_array = False try: array_size = int(a['ARRAYSIZE']) except KeyError: array_size = None flavors = {} for f in ['OVERRIDABLE', 'TOSUBCLASS', 'TOINSTANCE', 'TRANSLATABLE']: try: flavors[f.lower()] = a[f].lower() == 'true' except KeyError: pass scopes = None value = None for child in kids(tt): if name(child) == 'SCOPE': if scopes is not None: raise ParseError("Multiple SCOPE tags encountered") scopes = parse_any(child) else: if value is not None: raise ParseError("Multiple VALUE/VALUE.ARRAY tags encountered") value = cim_obj.tocimobj(type, parse_any(child)) return cim_obj.CIMQualifierDeclaration(qname, type, value, is_array, array_size, scopes, **flavors) def parse_qualifier(tt): ## ## check_node(tt, 'QUALIFIER', ['NAME', 'TYPE'], ['OVERRIDABLE', 'TOSUBCLASS', 'TOINSTANCE', 'TRANSLATABLE', 'PROPAGATED'], ['VALUE', 'VALUE.ARRAY']) a = attrs(tt) q = cim_obj.CIMQualifier(a['NAME'], unpack_value(tt), type=a['TYPE']) ## TODO: Lift this out? for i in ['OVERRIDABLE', 'TOSUBCLASS', 'TOINSTANCE', 'TRANSLATABLE', 'PROPAGATED']: rv = a.get(i) if rv not in ['true', 'false', None]: raise ParseError("invalid value %s for %s on %s" % (`rv`, i, name(tt))) if rv == 'true': rv = True elif rv == 'false': rv = False setattr(q, i.lower(), rv) return q def parse_property(tt): """Parse PROPERTY into a CIMProperty object. VAL is just the pcdata of the enclosed VALUE node.""" ## ## ## TODO: Parse this into NAME, VALUE, where the value contains ## magic fields for the qualifiers and the propagated flag. check_node(tt, 'PROPERTY', ['TYPE', 'NAME'], ['NAME', 'CLASSORIGIN', 'PROPAGATED', 'EmbeddedObject', 'EMBEDDEDOBJECT'], ['QUALIFIER', 'VALUE']) quals = {} for q in list_of_matching(tt, ['QUALIFIER']): quals[q.name] = q val = unpack_value(tt) a = attrs(tt) embedded_object=None if 'EmbeddedObject' in a or 'EMBEDDEDOBJECT' in a: try: embedded_object = a['EmbeddedObject'] except KeyError: embedded_object = a['EMBEDDEDOBJECT'] if embedded_object is not None: val = parse_embeddedObject(val) return CIMProperty(a['NAME'], val, a['TYPE'], class_origin=a.get('CLASSORIGIN'), propagated=unpack_boolean(a.get('PROPAGATED')), qualifiers=quals, embedded_object=embedded_object) def parse_property_array(tt): """ """ from cim_obj import tocimobj check_node(tt, 'PROPERTY.ARRAY', ['NAME', 'TYPE'], ['REFERENCECLASS', 'CLASSORIGIN', 'PROPAGATED', 'ARRAYSIZE', 'EmbeddedObject', 'EMBEDDEDOBJECT'], ['QUALIFIER', 'VALUE.ARRAY']) quals = {} for q in list_of_matching(tt, ['QUALIFIER']): quals[q.name] = q values = unpack_value(tt) a = attrs(tt) embedded_object = None if 'EmbeddedObject' in a or 'EMBEDDEDOBJECT' in a: try: embedded_object = a['EmbeddedObject'] except KeyError: embedded_object = a['EMBEDDEDOBJECT'] if embedded_object is not None: values = parse_embeddedObject(values) obj = CIMProperty(a['NAME'], values, a['TYPE'], class_origin=a.get('CLASSORIGIN'), qualifiers=quals, is_array=True, embedded_object=embedded_object) ## TODO: qualifiers, other attributes return obj def parse_property_reference(tt): """ """ check_node(tt, 'PROPERTY.REFERENCE', ['NAME'], ['REFERENCECLASS', 'CLASSORIGIN', 'PROPAGATED']) value = list_of_matching(tt, ['VALUE.REFERENCE']) if value is None or len(value) == 0: value = None elif len(value) == 1: value = value[0] else: raise ParseError('Too many VALUE.REFERENCE elements.') attributes = attrs(tt) pref = cim_obj.CIMProperty(attributes['NAME'], value, type = 'reference') for q in list_of_matching(tt, ['QUALIFIER']): pref.qualifiers[q.name] = q if attributes.has_key('REFERENCECLASS'): pref.reference_class = attributes['REFERENCECLASS'] if attributes.has_key('CLASSORIGIN'): pref.class_origin = attributes['CLASSORIGIN'] if attributes.has_key('PROPAGATED'): pref.propagated = attributes['PROPAGATED'] return pref def parse_method(tt): """ """ check_node(tt, 'METHOD', ['NAME'], ['TYPE', 'CLASSORIGIN', 'PROPAGATED'], ['QUALIFIER', 'PARAMETER', 'PARAMETER.REFERENCE', 'PARAMETER.ARRAY', 'PARAMETER.REFARRAY']) qualifiers = byname(list_of_matching(tt, ['QUALIFIER'])) parameters = byname(list_of_matching(tt, ['PARAMETER', 'PARAMETER.REFERENCE', 'PARAMETER.ARRAY', 'PARAMETER.REFARRAY',])) a = attrs(tt) return cim_obj.CIMMethod(a['NAME'], return_type=a.get('TYPE'), parameters=parameters, qualifiers=qualifiers, class_origin=a.get('CLASSORIGIN'), propagated=unpack_boolean(a.get('PROPAGATED'))) def parse_parameter(tt): """ """ check_node(tt, 'PARAMETER', ['NAME', 'TYPE'], []) quals = {} for q in list_of_matching(tt, ['QUALIFIER']): quals[q.name] = q a = attrs(tt) return cim_obj.CIMParameter(a['NAME'], type=a['TYPE'], qualifiers=quals) def parse_parameter_reference(tt): """ """ check_node(tt, 'PARAMETER.REFERENCE', ['NAME'], ['REFERENCECLASS']) quals = {} for q in list_of_matching(tt, ['QUALIFIER']): quals[q.name] = q a = attrs(tt) return cim_obj.CIMParameter(a['NAME'], type='reference', reference_class=a.get('REFERENCECLASS'), qualifiers=quals) def parse_parameter_array(tt): """ """ check_node(tt, 'PARAMETER.ARRAY', ['NAME', 'TYPE'], ['ARRAYSIZE']) quals = {} for q in list_of_matching(tt, ['QUALIFIER']): quals[q.name] = q a = attrs(tt) array_size = a.get('ARRAYSIZE') if array_size is not None: array_size = int(array_size) return cim_obj.CIMParameter(a['NAME'], type=a['TYPE'], is_array = True, array_size=array_size, qualifiers=quals) def parse_parameter_refarray(tt): """ """ check_node(tt, 'PARAMETER.REFARRAY', ['NAME'], ['REFERENCECLASS', 'ARRAYSIZE']) quals = {} for q in list_of_matching(tt, ['QUALIFIER']): quals[q.name] = q a = attrs(tt) array_size = a.get('ARRAYSIZE') if array_size is not None: array_size = int(array_size) return cim_obj.CIMParameter(a['NAME'], 'reference', is_array = True, reference_class=a.get('REFERENCECLASS'), array_size=array_size, qualifiers=quals) # # Message elements # def parse_message(tt): """ """ check_node(tt, 'MESSAGE', ['ID', 'PROTOCOLVERSION']) messages = one_child( tt, ['SIMPLEREQ', 'MULTIREQ', 'SIMPLERSP', 'MULTIRSP', 'SIMPLEEXPREQ']) if type(messages) is not list: # make single and multi forms consistent messages = [messages] return name(tt), attrs(tt), messages def parse_multireq(tt): raise ParseError('MULTIREQ parser not implemented') def parse_multiexpreq(tt): raise ParseError('MULTIEXPREQ parser not implemented') def parse_simpleexpreq(tt): """ """ child = one_child(tt, ['EXPMETHODCALL']) return name(tt), attrs(tt), child def parse_simplereq(tt): """ """ check_node(tt, 'SIMPLEREQ') child = one_child(tt, ['IMETHODCALL', 'METHODCALL']) return name(tt), attrs(tt), child def parse_imethodcall(tt): """ """ check_node(tt, 'IMETHODCALL', ['NAME']) if len(kids(tt)) < 1: raise ParseError('Expecting LOCALNAMESPACEPATH, got nothing') localnspath = parse_localnamespacepath(kids(tt)[0]) params = map(lambda x: parse_iparamvalue(x), kids(tt)[1:]) return (name(tt), attrs(tt), localnspath, params) def parse_methodcall(tt): """ """ check_node(tt, 'METHODCALL', ['NAME'], [], ['LOCALCLASSPATH', 'LOCALINSTANCEPATH', 'PARAMVALUE']) path = list_of_matching(tt, ['LOCALCLASSPATH','LOCALINSTANCEPATH']) if len(path) != 1: raise ParseError('Expecting one of LOCALCLASSPATH or LOCALINSTANCEPATH, got %s' % `path`) path = path[0] params = list_of_matching(tt, ['PARAMVALUE']) return (name(tt), attrs(tt), path, params) def parse_expmethodcall(tt): """ """ check_node(tt, 'EXPMETHODCALL', ['NAME'], [], ['EXPPARAMVALUE']) params = list_of_matching(tt, ['EXPPARAMVALUE']) return (name(tt), attrs(tt), params) def parse_paramvalue(tt): ## ## ## Version 2.1.1 of the DTD lacks the %ParamType attribute but it ## is present in version 2.2. Make it optional to be backwards ## compatible. check_node(tt, 'PARAMVALUE', ['NAME'], ['PARAMTYPE','EmbeddedObject', 'EMBEDDEDOBJECT']) child = optional_child(tt, ['VALUE', 'VALUE.REFERENCE', 'VALUE.ARRAY', 'VALUE.REFARRAY',]) if attrs(tt).has_key('PARAMTYPE'): paramtype = attrs(tt)['PARAMTYPE'] else: paramtype = None if 'EmbeddedObject' in attrs(tt) or 'EMBEDDEDOBJECT' in attrs(tt): child = parse_embeddedObject(child) return attrs(tt)['NAME'], paramtype, child def parse_iparamvalue(tt): ## ## """Returns NAME, VALUE pair.""" check_node(tt, 'IPARAMVALUE', ['NAME'], []) child = optional_child(tt, ['VALUE', 'VALUE.ARRAY', 'VALUE.REFERENCE', 'INSTANCENAME', 'CLASSNAME', 'QUALIFIER.DECLARATION', 'CLASS', 'INSTANCE', 'VALUE.NAMEDINSTANCE']) name = attrs(tt)['NAME'] if isinstance(child, basestring) and \ name.lower() in ['deepinheritance', 'localonly', 'includequalifiers', 'includeclassorigin']: if child.lower() in ['true', 'false']: child = child.lower() == 'true' return name, child def parse_expparamvalue(tt): """ """ check_node(tt, 'EXPPARAMVALUE', ['NAME'], [], ['INSTANCE']) child = optional_child(tt, ['INSTANCE']) name = attrs(tt)['NAME'] return name, child def parse_multirsp(tt): raise ParseError('MULTIRSP parser not implemented') def parse_multiexprsp(tt): raise ParseError('MULTIEXPRSP parser not implemented') def parse_simplersp(tt): ## check_node(tt, 'SIMPLERSP', [], []) child = one_child(tt, ['METHODRESPONSE', 'IMETHODRESPONSE']) return name(tt), attrs(tt), child def parse_simpleexprsp(tt): raise ParseError('SIMPLEEXPRSP parser not implemented') def parse_methodresponse(tt): ## ## check_node(tt, 'METHODRESPONSE', ['NAME'], []) return name(tt), attrs(tt), list_of_various(tt, ['ERROR', 'RETURNVALUE', 'PARAMVALUE']) def parse_expmethodresponse(tt): raise ParseError('EXPMETHODRESPONSE parser not implemented') def parse_imethodresponse(tt): ## ## check_node(tt, 'IMETHODRESPONSE', ['NAME'], []) return name(tt), attrs(tt), optional_child(tt, ['ERROR', 'IRETURNVALUE']) def parse_error(tt): """ """ ## TODO: Return a CIMError object, not a tuple check_node(tt, 'ERROR', ['CODE'], ['DESCRIPTION']) return (name(tt), attrs(tt), None) def parse_returnvalue(tt): ## ## ## Version 2.1.1 of the DTD lacks the %ParamType attribute but it ## is present in version 2.2. Make it optional to be backwards ## compatible. check_node(tt, 'RETURNVALUE', [], ['PARAMTYPE']) return name(tt), attrs(tt), one_child(tt, ['VALUE', 'VALUE.ARRAY', 'VALUE.REFERENCE', 'VALUE.REFARRAY']) def parse_ireturnvalue(tt): ## check_node(tt, 'IRETURNVALUE', [], []) # XXX: doesn't prohibit the case of only one VALUE.ARRAY or # VALUE.REFERENCE. But why is that required? Why can it return # multiple VALUEs but not multiple VALUE.REFERENCEs? values = list_of_same(tt, ['CLASSNAME', 'INSTANCENAME', 'VALUE', 'VALUE.OBJECTWITHPATH', 'VALUE.OBJECT', 'OBJECTPATH', 'QUALIFIER.DECLARATION', 'VALUE.ARRAY', 'VALUE.REFERENCE', 'CLASS', 'INSTANCE', 'VALUE.NAMEDINSTANCE',]) ## TODO: Call unpack_value if appropriate return name(tt), attrs(tt), values # # Object naming and locating elements # def parse_any(tt): """Parse any fragment of XML.""" nodename = name(tt).lower().replace('.', '_') fn_name = 'parse_' + nodename fn = globals().get(fn_name) if fn is None: raise ParseError('no parser for node type %s' % name(tt)) else: return fn(tt) def parse_embeddedObject(val): if isinstance(val, list): return [parse_embeddedObject(obj) for obj in val] if val is None: return None tt = xml_to_tupletree(val) if tt[0] == 'INSTANCE': return parse_instance(tt) elif tt[0] == 'CLASS': return parse_class(tt) else: raise ParseError('Error parsing embedded object') def unpack_value(tt): """Find VALUE or VALUE.ARRAY under TT and convert to a Python value. Looks at the TYPE of the node to work out how to decode it. Handles nodes with no value (e.g. in CLASS.) """ ## TODO: Handle VALUE.REFERENCE, VALUE.REFARRAY valtype = attrs(tt)['TYPE'] raw_val = list_of_matching(tt, ['VALUE', 'VALUE.ARRAY']) if len(raw_val) == 0: return None elif len(raw_val) > 1: raise ParseError('more than one VALUE or VALUE.ARRAY under %s' % name(tt)) raw_val = raw_val[0] if isinstance(raw_val, list): return [cim_obj.tocimobj(valtype, x) for x in raw_val] elif len(raw_val) == 0 and valtype != 'string': return None else: return cim_obj.tocimobj(valtype, raw_val) def unpack_boolean(p): """Unpack a boolean, represented as "TRUE" or "FALSE" in CIM.""" if p is None: return None ## CIM-XML says "These values MUST be treated as case-insensitive" ## (even though the XML definition requires them to be lowercase.) p = p.strip().lower() # ignore space if p == 'true': return True elif p == 'false': return False elif p == '': return None else: raise ParseError('invalid boolean %s' % `p`) pywbem-0.8.0~dev/pywbem/__init__.py0000644000175000017500000001062512413747174017243 0ustar bzedbzed00000000000000# # (C) Copyright 2004,2006 Hewlett-Packard Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter # Martin Pool """ PyWBEM provides a WBEM client library and some related utilities, written in pure Python. The WBEM client library allows issuing operations to a WBEM server, using the CIM operations over HTTP (CIM-XML) protocol defined in the DMTF standards DSP0200 and DSP0201. See http://www.dmtf.org/standards/wbem for information about WBEM. It is based on the idea that a good WBEM client should be easy to use and not necessarily require a large amount of programming knowledge. It is suitable for a large range of tasks from simply poking around to writing web and GUI applications. * `pywbem.cim_operations.WBEMConnection` : Main class of the WBEM client library and a good starting point to read about it. The WBEM-related utilities included in this package are: * `pywbem.mof_compiler` : Script for compiling MOF files, can also be used as a module. * `pywbem.cim_provider` : Module for writing CIM providers in Python. * `pywbem.cim_provider2` : Another module for writing CIM providers in Python. * `pywbem.twisted_client` : An experimental alternative WBEM client library that uses the Python `twisted` package. * [`wbemcli.py`](../wbemcli.m.html) : Script providing a WBEM client CLI as an interactive shell. Importing the `pywbem` package causes a subset of symbols from its sub-modules to be folded into the target namespace. The use of these folded symbols is shown for the example of class `pywbem.cim_operations.WBEMConnection`: import pywbem conn = pywbem.WBEMConnection(...) or: from pywbem import WBEMConnection conn = WBEMConnection(...) or (less preferred): from pywbem import * conn = WBEMConnection(...) The folded symbols' origin symbols in the sub-modules are also considered part of the public interface of the `pywbem` package. Programs using sub-modules that are not part of the WBEM client library, or specific symbols that are not folded into the target namespace of the `pywbem` package need to import the respective sub-modules explicitly. The use of such sub-modules is shown for the example of class `pywbem.cim_provider.CIMProvider`: from pywbem import cim_provider provider = cim_provider.CIMProvider(...) or: from pywbem.cim_provider import CIMProvider provider = CIMProvider(...) or: import pywbem.cim_provider provider = pywbem.cim_provider.CIMProvider(...) Version ------- This version of PyWBEM is 0.8.0~dev. The version number follows these conventions: * M.N.U~dev : During development of the future M.N.U version. * M.N.U~rc1 : For release candidate 1 (etc.) of the future M.N.U version. * M.N.U : For the final (=released) M.N.U version. The use of the tilde (~) causes RPM to correctly treat the preliminary versions to be younger than the final version. Changes ------- The change log is in the NEWS file of the PyWBEM distribution archive. Compatibility ------------- PyWBEM has been tested with Python 2.6 on Windows and Linux, and with Python 2.7 on Linux (due to a restriction of the `M2Crypto` package on Windows). Contributing ------------ PyWBEM [is on SourceForge](http://sourceforge.net/projects/pywbem/). Bug reports and discussion on the mailing list are welcome. License ------- PyWBEM is licensed with GNU LGPL v2. """ # Version of the pywbem package __version__ = '0.8.0~dev' # There are submodules, but clients shouldn't need to know about them. # Importing just this module is enough. # These are explicitly safe for 'import *' from pywbem.cim_types import * from pywbem.cim_constants import * from pywbem.cim_operations import * from pywbem.cim_obj import * from pywbem.tupleparse import ParseError pywbem-0.8.0~dev/pywbem/mofparsetab.py0000644000175000017500000022026212413747203020000 0ustar bzedbzed00000000000000 # pywbem/mofparsetab.py # This file is automatically generated. Do not edit. _tabversion = '3.0' _lr_method = 'LALR' _lr_signature = 2116372305 _lr_action_items = {'DT_UINT8':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[22,22,22,22,22,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,22,-201,22,22,22,22,-201,22,-201,22,-24,22,-46,-201,22,22,-173,22,22,-201,22,22,22,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,22,-67,22,22,22,22,22,-201,-201,22,22,-174,22,-101,22,22,22,22,-201,22,22,-175,-76,22,-68,-201,-201,22,22,-176,-77,22,22,22,-70,-69,-78,22,-72,-201,-201,-36,22,-201,-201,22,-80,22,22,22,-71,-79,-74,-73,-201,22,22,-45,-37,-201,22,22,-81,-82,-75,22,22,-83,]),'DISABLEOVERRIDE':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,81,90,94,96,98,99,100,101,103,122,123,124,125,126,127,128,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,169,174,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,266,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,342,348,351,353,354,358,365,],[23,23,23,23,23,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,23,-201,23,122,23,23,-201,23,-201,23,-24,122,-56,-58,-57,-55,122,-59,-51,23,-46,-201,23,23,-173,23,23,-201,23,23,23,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,23,-67,23,122,-52,23,23,23,23,-201,-201,23,23,-174,23,-101,23,23,23,23,-201,23,23,-175,-76,23,-68,-201,-201,122,23,23,-176,-77,23,23,23,-70,-69,-78,23,-72,-201,-201,-36,23,-201,-201,23,-80,23,23,23,-71,-79,-74,-73,-201,23,23,-45,-37,-201,23,23,122,-81,-82,-75,23,23,-83,]),'DT_STR':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[24,24,24,24,24,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,24,-201,24,24,24,24,-201,24,-201,24,-24,24,-46,-201,24,24,-173,24,24,-201,24,24,24,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,24,-67,24,24,24,24,24,-201,-201,24,24,-174,24,-101,24,24,24,24,-201,24,24,-175,-76,24,-68,-201,-201,24,24,-176,-77,24,24,24,-70,-69,-78,24,-72,-201,-201,-36,24,-201,-201,24,-80,24,24,24,-71,-79,-74,-73,-201,24,24,-45,-37,-201,24,24,-81,-82,-75,24,24,-83,]),'DT_SINT64':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[25,25,25,25,25,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,25,-201,25,25,25,25,-201,25,-201,25,-24,25,-46,-201,25,25,-173,25,25,-201,25,25,25,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,25,-67,25,25,25,25,25,-201,-201,25,25,-174,25,-101,25,25,25,25,-201,25,25,-175,-76,25,-68,-201,-201,25,25,-176,-77,25,25,25,-70,-69,-78,25,-72,-201,-201,-36,25,-201,-201,25,-80,25,25,25,-71,-79,-74,-73,-201,25,25,-45,-37,-201,25,25,-81,-82,-75,25,25,-83,]),'octalValue':([79,80,173,182,185,],[108,108,108,108,108,]),',':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,62,63,65,66,77,78,82,83,84,85,86,87,88,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,134,135,150,169,170,171,172,174,175,183,184,210,216,217,218,219,220,221,222,223,224,254,255,256,257,258,259,260,261,262,263,264,265,267,280,281,283,284,285,286,306,308,309,315,316,318,326,340,345,346,347,349,350,362,363,364,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,-188,-193,-181,-47,-145,-201,-146,-144,-145,-146,-54,-49,-34,129,129,129,-148,-147,133,-179,-177,-130,-136,-138,-135,-132,-137,-127,-133,-178,-129,-131,-134,173,-125,-124,-56,-58,-57,-55,-48,-59,-51,179,-151,-40,-50,-53,-128,-123,-52,-35,-152,-149,-126,-140,-139,-121,-122,-119,-120,-141,-150,-117,-160,-162,307,-163,-165,-159,-154,-161,-164,-157,-158,-156,-118,-106,-102,-107,-105,-104,319,-153,342,-167,-112,-116,-108,319,-155,-113,-109,-103,-114,-110,-168,-115,-111,]),'hexValue':([79,80,173,182,185,],[109,109,109,109,109,]),'stringValue':([79,80,92,111,113,171,173,182,],[113,113,141,171,-127,-128,113,113,]),'decimalValue':([79,80,173,182,185,],[112,112,112,112,112,]),'DT_DATETIME':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[28,28,28,28,28,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,28,-201,28,28,28,28,-201,28,-201,28,-24,28,-46,-201,28,28,-173,28,28,-201,28,28,28,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,28,-67,28,28,28,28,28,-201,-201,28,28,-174,28,-101,28,28,28,28,-201,28,28,-175,-76,28,-68,-201,-201,28,28,-176,-77,28,28,28,-70,-69,-78,28,-72,-201,-201,-36,28,-201,-201,28,-80,28,28,28,-71,-79,-74,-73,-201,28,28,-45,-37,-201,28,28,-81,-82,-75,28,28,-83,]),'PARAMETER':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,213,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,307,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[27,27,27,27,27,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,27,-201,27,27,27,-201,27,-201,27,-24,27,-46,-201,27,27,-173,27,27,-201,27,27,27,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,27,-67,27,27,27,27,27,-201,-201,27,27,-174,27,-101,27,27,262,27,27,-201,27,27,-175,-76,27,-68,-201,-201,27,27,-176,-77,27,27,27,-70,-69,-78,27,-72,-201,-201,-36,27,-201,-201,27,262,-80,27,27,27,-71,-79,-74,-73,-201,27,27,-45,-37,-201,27,27,-81,-82,-75,27,27,-83,]),'FLAVOR':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,179,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[46,46,46,46,46,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,46,-201,46,46,46,-201,46,-201,46,-24,46,-46,-201,46,46,-173,46,46,-201,46,46,46,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,46,-67,46,46,46,214,46,46,-201,-201,46,46,-174,46,-101,46,46,46,46,-201,46,46,-175,-76,46,-68,-201,-201,46,46,-176,-77,46,46,46,-70,-69,-78,46,-72,-201,-201,-36,46,-201,-201,46,-80,46,46,46,-71,-79,-74,-73,-201,46,46,-45,-37,-201,46,46,-81,-82,-75,46,46,-83,]),'charValue':([79,80,173,182,],[117,117,117,117,]),'#':([0,2,3,4,5,7,9,10,12,13,15,17,18,181,192,209,215,233,237,238,273,274,276,311,313,314,343,344,357,361,367,368,370,371,372,373,],[-201,-2,6,-12,-5,-7,-10,-4,-11,-8,-3,-6,-9,-142,-13,-16,-143,-169,-18,-17,-20,-170,-19,-171,-22,-21,-172,-23,-26,-30,-28,-27,-32,-31,-29,-33,]),'TOSUBCLASS':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,81,90,94,96,98,99,100,101,103,122,123,124,125,126,127,128,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,169,174,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,266,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,342,348,351,353,354,358,365,],[26,26,26,26,26,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,26,-201,26,123,26,26,-201,26,-201,26,-24,123,-56,-58,-57,-55,123,-59,-51,26,-46,-201,26,26,-173,26,26,-201,26,26,26,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,26,-67,26,123,-52,26,26,26,26,-201,-201,26,26,-174,26,-101,26,26,26,26,-201,26,26,-175,-76,26,-68,-201,-201,123,26,26,-176,-77,26,26,26,-70,-69,-78,26,-72,-201,-201,-36,26,-201,-201,26,-80,26,26,26,-71,-79,-74,-73,-201,26,26,-45,-37,-201,26,26,123,-81,-82,-75,26,26,-83,]),'$':([73,182,],[98,98,]),'REFERENCE':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,213,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,307,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[29,29,29,29,29,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,29,-201,29,29,29,-201,29,-201,29,-24,29,-46,-201,29,29,-173,29,29,-201,29,29,29,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,29,-67,29,29,29,29,29,-201,-201,29,29,-174,29,-101,29,29,255,29,29,-201,29,29,-175,-76,29,-68,-201,-201,29,29,-176,-77,29,29,29,-70,-69,-78,29,-72,-201,-201,-36,29,-201,-201,29,255,-80,29,29,29,-71,-79,-74,-73,-201,29,29,-45,-37,-201,29,29,-81,-82,-75,29,29,-83,]),')':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,122,123,124,125,127,140,141,171,224,241,254,255,256,257,258,259,260,261,262,263,264,265,267,280,281,283,284,285,286,293,308,309,315,316,318,326,340,345,346,347,349,350,362,363,364,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,-188,-193,-181,170,-179,-177,-130,-136,-138,-135,-132,-137,-127,-133,-178,-129,-131,-134,-56,-58,-57,-55,-59,192,-15,-128,-117,279,-160,-162,306,-163,-165,-159,-154,-161,-164,-157,-158,-156,-118,-106,-102,-107,-105,-104,320,325,341,-167,-112,-116,-108,352,-155,-113,-109,-103,-114,-110,-168,-115,-111,]),'RESTRICTED':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,81,90,94,96,98,99,100,101,103,122,123,124,125,126,127,128,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,169,174,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,266,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,342,348,351,353,354,358,365,],[30,30,30,30,30,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,30,-201,30,124,30,30,-201,30,-201,30,-24,124,-56,-58,-57,-55,124,-59,-51,30,-46,-201,30,30,-173,30,30,-201,30,30,30,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,30,-67,30,124,-52,30,30,30,30,-201,-201,30,30,-174,30,-101,30,30,30,30,-201,30,30,-175,-76,30,-68,-201,-201,124,30,30,-176,-77,30,30,30,-70,-69,-78,30,-72,-201,-201,-36,30,-201,-201,30,-80,30,30,30,-71,-79,-74,-73,-201,30,30,-45,-37,-201,30,30,124,-81,-82,-75,30,30,-83,]),'DT_REAL64':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[31,31,31,31,31,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,31,-201,31,31,31,31,-201,31,-201,31,-24,31,-46,-201,31,31,-173,31,31,-201,31,31,31,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,31,-67,31,31,31,31,31,-201,-201,31,31,-174,31,-101,31,31,31,31,-201,31,31,-175,-76,31,-68,-201,-201,31,31,-176,-77,31,31,31,-70,-69,-78,31,-72,-201,-201,-36,31,-201,-201,31,-80,31,31,31,-71,-79,-74,-73,-201,31,31,-45,-37,-201,31,31,-81,-82,-75,31,31,-83,]),'TRANSLATABLE':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,81,90,94,96,98,99,100,101,103,122,123,124,125,126,127,128,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,169,174,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,266,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,342,348,351,353,354,358,365,],[32,32,32,32,32,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,32,-201,32,127,32,32,-201,32,-201,32,-24,127,-56,-58,-57,-55,127,-59,-51,32,-46,-201,32,32,-173,32,32,-201,32,32,32,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,32,-67,32,127,-52,32,32,32,32,-201,-201,32,32,-174,32,-101,32,32,32,32,-201,32,32,-175,-76,32,-68,-201,-201,127,32,32,-176,-77,32,32,32,-70,-69,-78,32,-72,-201,-201,-36,32,-201,-201,32,-80,32,32,32,-71,-79,-74,-73,-201,32,32,-45,-37,-201,32,32,127,-81,-82,-75,32,32,-83,]),':':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,63,64,65,66,72,77,78,91,97,121,137,150,170,172,211,212,248,251,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-38,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,76,-188,-193,-181,81,-145,-146,-144,89,-145,-146,76,-54,103,76,-39,-124,76,-40,-53,-123,76,76,76,76,]),'DT_SINT8':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[34,34,34,34,34,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,34,-201,34,34,34,34,-201,34,-201,34,-24,34,-46,-201,34,34,-173,34,34,-201,34,34,34,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,34,-67,34,34,34,34,34,-201,-201,34,34,-174,34,-101,34,34,34,34,-201,34,34,-175,-76,34,-68,-201,-201,34,34,-176,-77,34,34,34,-70,-69,-78,34,-72,-201,-201,-36,34,-201,-201,34,-80,34,34,34,-71,-79,-74,-73,-201,34,34,-45,-37,-201,34,34,-81,-82,-75,34,34,-83,]),';':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,105,106,107,108,109,110,111,112,113,114,115,116,117,118,121,134,150,168,171,172,180,195,197,199,200,201,202,204,205,216,217,218,219,220,221,222,224,231,232,234,236,239,243,244,245,247,267,269,271,272,279,289,291,295,296,306,310,312,320,325,328,335,339,341,352,355,356,359,360,366,369,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,-188,-193,-181,-179,-177,-130,-136,-138,-135,-132,-137,-127,-133,-178,-129,-131,-134,-124,181,-40,209,-128,-123,215,233,235,237,238,240,-85,242,-84,-140,-139,-121,-122,-119,-120,-141,-117,273,274,275,276,277,288,290,292,294,-118,311,313,314,317,323,324,327,329,-153,343,344,348,351,353,357,361,-166,365,367,368,370,371,372,373,]),'IDENTIFIER':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[35,35,35,35,35,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,35,-201,35,35,35,-201,35,-201,35,-24,35,-46,-201,35,35,-173,35,35,-201,35,35,35,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,35,-67,35,35,35,35,35,-201,-201,35,35,-174,35,-101,35,35,35,35,-201,35,35,-175,-76,35,-68,-201,-201,35,35,-176,-77,35,35,35,-70,-69,-78,35,-72,-201,-201,-36,35,-201,-201,35,-80,35,35,35,-71,-79,-74,-73,-201,35,35,-45,-37,-201,35,35,-81,-82,-75,35,35,-83,]),'=':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,135,147,184,196,201,202,204,205,224,243,245,247,267,295,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,-188,-193,-181,182,182,182,182,182,-85,182,-84,-117,182,182,182,-118,182,]),'METHOD':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,213,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,307,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[36,36,36,36,36,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,36,-201,36,36,36,-201,36,-201,36,-24,36,-46,-201,36,36,-173,36,36,-201,36,36,36,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,36,-67,36,36,36,36,36,-201,-201,36,36,-174,36,-101,36,36,257,36,36,-201,36,36,-175,-76,36,-68,-201,-201,36,36,-176,-77,36,36,36,-70,-69,-78,36,-72,-201,-201,-36,36,-201,-201,36,257,-80,36,36,36,-71,-79,-74,-73,-201,36,36,-45,-37,-201,36,36,-81,-82,-75,36,36,-83,]),'ASSOCIATION':([14,16,129,143,213,307,],[60,65,65,65,264,264,]),'$end':([0,1,2,3,4,5,7,9,10,12,13,15,17,18,181,192,209,215,233,237,238,273,274,276,311,313,314,343,344,357,361,367,368,370,371,372,373,],[-201,0,-2,-1,-12,-5,-7,-10,-4,-11,-8,-3,-6,-9,-142,-13,-16,-143,-169,-18,-17,-20,-170,-19,-171,-22,-21,-172,-23,-26,-30,-28,-27,-32,-31,-29,-33,]),'DT_BOOL':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[49,49,49,49,49,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,49,-201,49,49,49,49,-201,49,-201,49,-24,49,-46,-201,49,49,-173,49,49,-201,49,49,49,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,49,-67,49,49,49,49,49,-201,-201,49,49,-174,49,-101,49,49,49,49,-201,49,49,-175,-76,49,-68,-201,-201,49,49,-176,-77,49,49,49,-70,-69,-78,49,-72,-201,-201,-36,49,-201,-201,49,-80,49,49,49,-71,-79,-74,-73,-201,49,49,-45,-37,-201,49,49,-81,-82,-75,49,49,-83,]),'CLASS':([0,2,3,4,5,7,9,10,11,12,13,14,15,16,17,18,19,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,130,131,132,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,181,182,187,189,190,191,192,193,194,198,206,207,208,209,213,215,226,227,228,229,230,233,235,237,238,240,241,242,250,253,268,270,273,274,275,276,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,307,311,313,314,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,343,344,348,351,353,354,357,358,361,365,367,368,370,371,372,373,],[-201,-2,11,-12,-5,-7,-10,-4,54,-11,-8,54,-3,54,-6,-9,68,54,54,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,54,-201,54,54,54,-201,54,-201,54,-24,54,176,-46,177,-201,54,54,-173,54,54,-201,54,54,54,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,54,-67,54,54,54,-142,54,54,-201,-201,54,-13,54,-174,54,-101,54,54,-16,263,-143,54,54,-201,54,54,-169,-175,-18,-17,-76,54,-68,-201,-201,54,54,-20,-170,-176,-19,-77,54,54,54,-70,-69,-78,54,-72,-201,-201,-36,54,-201,-201,54,263,-171,-22,-21,-80,54,54,54,-71,-79,-74,-73,-201,54,54,-45,-37,-201,54,54,-172,-23,-81,-82,-75,54,-26,54,-30,-83,-28,-27,-32,-31,-29,-33,]),'floatValue':([79,80,173,182,],[107,107,107,107,]),'DT_SINT16':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[41,41,41,41,41,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,41,-201,41,41,41,41,-201,41,-201,41,-24,41,-46,-201,41,41,-173,41,41,-201,41,41,41,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,41,-67,41,41,41,41,41,-201,-201,41,41,-174,41,-101,41,41,41,41,-201,41,41,-175,-76,41,-68,-201,-201,41,41,-176,-77,41,41,41,-70,-69,-78,41,-72,-201,-201,-36,41,-201,-201,41,-80,41,41,41,-71,-79,-74,-73,-201,41,41,-45,-37,-201,41,41,-81,-82,-75,41,41,-83,]),'AS':([11,14,16,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,68,71,75,76,90,91,94,96,98,99,100,101,129,131,136,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,211,212,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[42,42,42,42,42,-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-38,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,73,-188,-193,-181,42,73,-201,42,42,73,42,-201,42,-201,42,-24,42,-46,73,-201,42,42,-173,42,42,-201,42,42,42,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,42,-67,42,42,42,42,42,-201,-201,42,42,-174,42,-101,42,42,73,73,42,42,-201,42,42,-175,-76,42,-68,-201,-201,42,42,-176,-77,42,42,42,-70,-69,-78,42,-72,-201,-201,-36,42,-201,-201,42,-80,42,42,42,-71,-79,-74,-73,-201,42,42,-45,-37,-201,42,42,-81,-82,-75,42,42,-83,]),'DT_SINT32':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[43,43,43,43,43,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,43,-201,43,43,43,43,-201,43,-201,43,-24,43,-46,-201,43,43,-173,43,43,-201,43,43,43,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,43,-67,43,43,43,43,43,-201,-201,43,43,-174,43,-101,43,43,43,43,-201,43,43,-175,-76,43,-68,-201,-201,43,43,-176,-77,43,43,43,-70,-69,-78,43,-72,-201,-201,-36,43,-201,-201,43,-80,43,43,43,-71,-79,-74,-73,-201,43,43,-45,-37,-201,43,43,-81,-82,-75,43,43,-83,]),'NULL':([79,80,173,182,],[105,105,105,105,]),'PRAGMA':([6,11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[20,44,44,44,44,44,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,44,-201,44,44,44,-201,44,-201,44,-24,44,-46,-201,44,44,-173,44,44,-201,44,44,44,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,44,-67,44,44,44,44,44,-201,-201,44,44,-174,44,-101,44,44,44,44,-201,44,44,-175,-76,44,-68,-201,-201,44,44,-176,-77,44,44,44,-70,-69,-78,44,-72,-201,-201,-36,44,-201,-201,44,-80,44,44,44,-71,-79,-74,-73,-201,44,44,-45,-37,-201,44,44,-81,-82,-75,44,44,-83,]),'SCOPE':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,133,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[45,45,45,45,45,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,45,-201,45,45,45,-201,45,-201,45,-24,45,-46,178,-201,45,45,-173,45,45,-201,45,45,45,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,45,-67,45,45,45,45,45,-201,-201,45,45,-174,45,-101,45,45,45,45,-201,45,45,-175,-76,45,-68,-201,-201,45,45,-176,-77,45,45,45,-70,-69,-78,45,-72,-201,-201,-36,45,-201,-201,45,-80,45,45,45,-71,-79,-74,-73,-201,45,45,-45,-37,-201,45,45,-81,-82,-75,45,45,-83,]),'[':([0,2,3,4,5,7,9,10,12,13,15,17,18,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,75,94,96,99,100,101,135,139,142,144,145,148,149,151,153,154,155,156,157,158,159,160,161,162,163,165,181,187,189,190,191,192,193,194,198,204,205,209,215,226,227,228,229,230,233,235,237,238,240,241,242,247,250,253,268,270,273,274,275,276,277,288,290,292,293,294,298,299,300,301,303,304,305,311,313,314,315,316,317,318,319,323,324,327,329,330,331,332,333,334,336,337,338,343,344,348,349,350,351,353,354,357,358,361,365,367,368,370,371,372,373,],[-201,-2,14,-12,-5,-7,-10,-4,-11,-8,-3,-6,-9,-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,-188,-193,-181,-201,143,-201,-201,143,-24,185,-201,143,-173,143,-201,143,143,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,-67,-142,143,-201,-201,143,-13,143,-174,143,185,-84,-16,-143,143,143,-201,143,143,-169,-175,-18,-17,-76,143,-68,185,-201,-201,143,143,-20,-170,-176,-19,-77,-70,-69,-78,143,-72,-201,-201,-36,143,-201,-201,143,-171,-22,-21,185,-116,-80,185,143,-71,-79,-74,-73,-201,143,143,-45,-37,-201,143,143,-172,-23,-81,185,185,-82,-75,143,-26,143,-30,-83,-28,-27,-32,-31,-29,-33,]),'DT_CHAR16':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[47,47,47,47,47,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,47,-201,47,47,47,47,-201,47,-201,47,-24,47,-46,-201,47,47,-173,47,47,-201,47,47,47,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,47,-67,47,47,47,47,47,-201,-201,47,47,-174,47,-101,47,47,47,47,-201,47,47,-175,-76,47,-68,-201,-201,47,47,-176,-77,47,47,47,-70,-69,-78,47,-72,-201,-201,-36,47,-201,-201,47,-80,47,47,47,-71,-79,-74,-73,-201,47,47,-45,-37,-201,47,47,-81,-82,-75,47,47,-83,]),']':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,62,63,65,66,77,78,82,83,84,85,108,109,110,112,121,122,123,124,125,126,127,128,169,170,172,174,175,185,225,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,-188,-193,-181,-47,-145,-201,-146,-144,-145,-146,-54,-49,-34,130,131,132,-136,-138,-135,-137,-124,-56,-58,-57,-55,-48,-59,-51,-50,-53,-123,-52,-35,224,267,]),'DT_UINT16':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[40,40,40,40,40,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,40,-201,40,40,40,40,-201,40,-201,40,-24,40,-46,-201,40,40,-173,40,40,-201,40,40,40,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,40,-67,40,40,40,40,40,-201,-201,40,40,-174,40,-101,40,40,40,40,-201,40,40,-175,-76,40,-68,-201,-201,40,40,-176,-77,40,40,40,-70,-69,-78,40,-72,-201,-201,-36,40,-201,-201,40,-80,40,40,40,-71,-79,-74,-73,-201,40,40,-45,-37,-201,40,40,-81,-82,-75,40,40,-83,]),'TRUE':([79,80,173,182,],[115,115,115,115,]),'DT_REAL32':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[48,48,48,48,48,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,48,-201,48,48,48,48,-201,48,-201,48,-24,48,-46,-201,48,48,-173,48,48,-201,48,48,48,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,48,-67,48,48,48,48,48,-201,-201,48,48,-174,48,-101,48,48,48,48,-201,48,48,-175,-76,48,-68,-201,-201,48,48,-176,-77,48,48,48,-70,-69,-78,48,-72,-201,-201,-36,48,-201,-201,48,-80,48,48,48,-71,-79,-74,-73,-201,48,48,-45,-37,-201,48,48,-81,-82,-75,48,48,-83,]),'ENABLEOVERRIDE':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,81,90,94,96,98,99,100,101,103,122,123,124,125,126,127,128,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,169,174,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,266,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,342,348,351,353,354,358,365,],[50,50,50,50,50,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,50,-201,50,125,50,50,-201,50,-201,50,-24,125,-56,-58,-57,-55,125,-59,-51,50,-46,-201,50,50,-173,50,50,-201,50,50,50,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,50,-67,50,125,-52,50,50,50,50,-201,-201,50,50,-174,50,-101,50,50,50,50,-201,50,50,-175,-76,50,-68,-201,-201,125,50,50,-176,-77,50,50,50,-70,-69,-78,50,-72,-201,-201,-36,50,-201,-201,50,-80,50,50,50,-71,-79,-74,-73,-201,50,50,-45,-37,-201,50,50,125,-81,-82,-75,50,50,-83,]),'FALSE':([79,80,173,182,],[106,106,106,106,]),'QUALIFIER':([0,2,3,4,5,7,9,10,11,12,13,14,15,16,17,18,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,181,182,187,189,190,191,192,193,194,198,206,207,208,209,213,215,226,227,228,229,230,233,235,237,238,240,241,242,250,253,268,270,273,274,275,276,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,307,311,313,314,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,343,344,348,351,353,354,357,358,361,365,367,368,370,371,372,373,],[-201,-2,16,-12,-5,-7,-10,-4,51,-11,-8,51,-3,51,-6,-9,51,51,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,51,-201,51,51,51,-201,51,-201,51,-24,51,-46,-201,51,51,-173,51,51,-201,51,51,51,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,51,-67,51,51,51,-142,51,51,-201,-201,51,-13,51,-174,51,-101,51,51,-16,254,-143,51,51,-201,51,51,-169,-175,-18,-17,-76,51,-68,-201,-201,51,51,-20,-170,-176,-19,-77,51,51,51,-70,-69,-78,51,-72,-201,-201,-36,51,-201,-201,51,254,-171,-22,-21,-80,51,51,51,-71,-79,-74,-73,-201,51,51,-45,-37,-201,51,51,-172,-23,-81,-82,-75,51,-26,51,-30,-83,-28,-27,-32,-31,-29,-33,]),'DT_UINT64':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[52,52,52,52,52,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,52,-201,52,52,52,52,-201,52,-201,52,-24,52,-46,-201,52,52,-173,52,52,-201,52,52,52,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,52,-67,52,52,52,52,52,-201,-201,52,52,-174,52,-101,52,52,52,52,-201,52,52,-175,-76,52,-68,-201,-201,52,52,-176,-77,52,52,52,-70,-69,-78,52,-72,-201,-201,-36,52,-201,-201,52,-80,52,52,52,-71,-79,-74,-73,-201,52,52,-45,-37,-201,52,52,-81,-82,-75,52,52,-83,]),'OF':([8,11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,67,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[21,53,53,53,53,53,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,90,53,-201,53,53,53,-201,53,-201,53,-24,53,-46,-201,53,53,-173,53,53,-201,53,53,53,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,53,-67,53,53,53,53,53,-201,-201,53,53,-174,53,-101,53,53,53,53,-201,53,53,-175,-76,53,-68,-201,-201,53,53,-176,-77,53,53,53,-70,-69,-78,53,-72,-201,-201,-36,53,-201,-201,53,-80,53,53,53,-71,-79,-74,-73,-201,53,53,-45,-37,-201,53,53,-81,-82,-75,53,53,-83,]),'REF':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,164,166,208,282,322,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-38,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,-188,-193,-181,-185,206,-185,-185,-185,]),'DT_UINT32':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,89,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[33,33,33,33,33,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,33,-201,33,33,33,33,-201,33,-201,33,-24,33,-46,-201,33,33,-173,33,33,-201,33,33,33,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,33,-67,33,33,33,33,33,-201,-201,33,33,-174,33,-101,33,33,33,33,-201,33,33,-175,-76,33,-68,-201,-201,33,33,-176,-77,33,33,33,-70,-69,-78,33,-72,-201,-201,-36,33,-201,-201,33,-80,33,33,33,-71,-79,-74,-73,-201,33,33,-45,-37,-201,33,33,-81,-82,-75,33,33,-83,]),'INSTANCE':([0,2,3,4,5,7,9,10,11,12,13,14,15,16,17,18,19,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,181,182,187,189,190,191,192,193,194,198,206,207,208,209,215,226,227,228,229,230,233,235,237,238,240,241,242,250,253,268,270,273,274,275,276,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,311,313,314,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,343,344,348,351,353,354,357,358,361,365,367,368,370,371,372,373,],[-201,-2,8,-12,-5,-7,-10,-4,56,-11,-8,56,-3,56,-6,-9,67,56,56,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,56,-201,56,56,56,-201,56,-201,56,-24,56,-46,-201,56,56,-173,56,56,-201,56,56,56,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,56,-67,56,56,56,-142,56,56,-201,-201,56,-13,56,-174,56,-101,56,56,-16,-143,56,56,-201,56,56,-169,-175,-18,-17,-76,56,-68,-201,-201,56,56,-20,-170,-176,-19,-77,56,56,56,-70,-69,-78,56,-72,-201,-201,-36,56,-201,-201,56,-171,-22,-21,-80,56,56,56,-71,-79,-74,-73,-201,56,56,-45,-37,-201,56,56,-172,-23,-81,-82,-75,56,-26,56,-30,-83,-28,-27,-32,-31,-29,-33,]),'PROPERTY':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,213,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,307,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[57,57,57,57,57,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,57,-201,57,57,57,-201,57,-201,57,-24,57,-46,-201,57,57,-173,57,57,-201,57,57,57,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,57,-67,57,57,57,57,57,-201,-201,57,57,-174,57,-101,57,57,261,57,57,-201,57,57,-175,-76,57,-68,-201,-201,57,57,-176,-77,57,57,57,-70,-69,-78,57,-72,-201,-201,-36,57,-201,-201,57,261,-80,57,57,57,-71,-79,-74,-73,-201,57,57,-45,-37,-201,57,57,-81,-82,-75,57,57,-83,]),'INDICATION':([14,16,129,143,213,307,],[62,66,66,66,259,259,]),'(':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,62,63,65,66,69,70,178,203,205,214,246,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,-188,-193,-181,79,-145,-146,-144,-145,-146,92,-14,213,241,-86,266,293,]),'{':([22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,63,65,66,71,72,74,91,93,95,97,102,136,137,138,150,182,186,188,211,212,248,249,251,252,297,302,],[-87,-184,-98,-94,-199,-191,-100,-195,-196,-96,-200,-91,-88,-180,-189,-197,-38,-185,-89,-90,-182,-92,-192,-198,-187,-97,-95,-99,-186,-194,-93,-190,-183,75,-188,-193,-181,80,-145,-146,-144,-145,-146,94,96,99,139,142,148,-39,-41,187,189,190,-40,80,226,228,250,253,298,299,303,304,330,336,]),'SCHEMA':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,213,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,307,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[37,37,37,37,37,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,37,-201,37,37,37,-201,37,-201,37,-24,37,-46,-201,37,37,-173,37,37,-201,37,37,37,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,37,-67,37,37,37,37,37,-201,-201,37,37,-174,37,-101,37,37,265,37,37,-201,37,37,-175,-76,37,-68,-201,-201,37,37,-176,-77,37,37,37,-70,-69,-78,37,-72,-201,-201,-36,37,-201,-201,37,265,-80,37,37,37,-71,-79,-74,-73,-201,37,37,-45,-37,-201,37,37,-81,-82,-75,37,37,-83,]),'}':([75,80,96,99,100,101,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,139,144,145,148,149,151,153,154,155,156,157,158,159,160,161,162,163,165,171,189,190,191,193,194,198,210,227,228,229,230,235,240,242,250,253,268,270,275,277,288,290,292,294,298,299,300,301,303,304,305,317,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[-201,121,-201,-201,168,-24,-179,-177,-130,-136,-138,-135,-132,-137,-127,-133,-178,-129,-131,-134,172,-125,-201,-173,195,-201,199,200,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,-67,-128,-201,-201,231,232,-174,236,-126,269,-201,271,272,-175,-76,-68,-201,-201,310,312,-176,-77,-70,-69,-78,-72,-201,-201,-36,335,-201,-201,339,-80,-71,-79,-74,-73,-201,355,356,-45,-37,-201,359,360,-81,-82,-75,366,369,-83,]),'ANY':([11,14,16,20,21,22,24,25,28,31,33,34,40,41,43,47,48,49,52,68,75,76,90,94,96,98,99,100,101,129,131,139,142,143,144,145,146,148,149,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,176,177,182,187,189,190,191,193,194,198,206,207,208,213,226,227,228,229,230,235,240,241,242,250,253,268,270,275,277,278,282,287,288,290,292,293,294,298,299,300,301,303,304,305,307,317,319,321,322,323,324,327,329,330,331,332,333,334,336,337,338,348,351,353,354,358,365,],[58,58,58,58,58,-87,-98,-94,-100,-96,-91,-88,-89,-90,-92,-97,-95,-99,-93,58,-201,58,58,58,-201,58,-201,58,-24,58,-46,-201,58,58,-173,58,58,-201,58,58,58,-42,-43,-44,-25,-64,-63,-66,-65,-60,-62,-61,58,-67,58,58,58,58,58,-201,-201,58,58,-174,58,-101,58,58,258,58,58,-201,58,58,-175,-76,58,-68,-201,-201,58,58,-176,-77,58,58,58,-70,-69,-78,58,-72,-201,-201,-36,58,-201,-201,58,258,-80,58,58,58,-71,-79,-74,-73,-201,58,58,-45,-37,-201,58,58,-81,-82,-75,58,58,-83,]),'binaryValue':([79,80,173,182,185,],[110,110,110,110,110,]),} _lr_action = { } for _k, _v in _lr_action_items.items(): for _x,_y in zip(_v[0],_v[1]): if not _x in _lr_action: _lr_action[_x] = { } _lr_action[_x][_k] = _y del _lr_action_items _lr_goto_items = {'objectHandle':([182,],[217,]),'objectRef':([100,149,151,167,191,198,229,230,241,270,287,293,301,305,319,331,332,337,338,354,358,],[152,152,152,207,152,152,152,152,278,152,321,278,152,152,278,152,152,152,152,152,152,]),'qualifierDeclaration':([3,],[4,]),'classFeatureList':([75,96,99,139,148,189,190,228,253,303,304,336,],[100,149,151,191,198,229,230,270,305,337,338,358,]),'propertyDeclaration':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,]),'qualifierType_1':([64,],[87,]),'qualifierType':([64,],[88,]),'aliasIdentifier':([73,182,],[97,216,]),'propertyDeclaration_7':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,]),'flavorList':([81,103,],[126,169,]),'initializer':([182,],[220,]),'mofProductionList':([0,],[3,]),'qualifierType_2':([64,],[86,]),'flavor':([81,103,126,169,266,342,],[128,128,174,174,309,362,]),'qualifierParameter':([59,],[78,]),'methodDeclaration':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,]),'referenceDeclaration':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,]),'classFeature':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[156,156,156,156,156,156,156,156,333,156,333,333,156,156,333,156,]),'mp_createClass':([3,],[5,]),'arrayInitializer':([59,182,],[77,218,]),'booleanValue':([79,80,173,182,],[114,114,114,114,]),'mp_createInstance':([3,],[7,]),'defaultValue':([135,147,184,196,201,204,243,245,247,295,],[183,197,223,234,239,244,289,291,296,328,]),'indicDeclaration':([3,],[9,]),'flavorListWithComma':([266,],[308,]),'compilerDirective':([3,],[10,]),'mofSpecification':([0,],[1,]),'associationFeature':([301,331,332,354,],[334,334,334,334,]),'referenceInitializer':([182,],[219,]),'defaultFlavor':([134,],[180,]),'referenceName':([152,207,],[201,245,]),'qualifierName':([14,16,129,143,],[59,64,59,59,]),'scope':([88,],[134,]),'parameter_1':([241,293,319,],[285,285,285,]),'parameterList':([241,293,],[286,326,]),'parameter':([241,293,319,],[281,281,347,]),'metaElementList':([213,],[256,]),'empty':([0,60,61,62,75,96,99,139,148,189,190,228,250,253,298,299,303,304,330,336,],[2,82,82,82,101,101,101,101,101,101,101,101,300,101,300,300,101,101,300,101,]),'parameter_4':([241,293,319,],[283,283,283,]),'propertyDeclaration_5':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,]),'propertyDeclaration_4':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,]),'constantValueList':([80,],[119,]),'propertyDeclaration_6':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,]),'propertyDeclaration_1':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,]),'qualifier':([14,129,143,],[61,175,61,]),'propertyDeclaration_3':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,]),'propertyDeclaration_2':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,]),'dataType':([11,14,16,20,21,68,76,89,90,94,98,100,129,142,143,145,146,149,151,152,164,167,176,177,182,187,191,193,198,207,208,226,227,229,230,241,268,270,278,282,287,293,301,305,319,321,322,331,332,337,338,354,358,],[39,39,39,39,39,39,39,135,39,39,39,164,39,39,39,39,39,164,164,39,39,208,39,39,39,39,164,39,164,39,39,39,39,164,164,282,39,164,39,39,322,282,164,164,282,39,39,164,164,164,164,164,164,]),'stringValueList':([79,80,173,182,],[111,111,111,111,]),'pragmaParameter':([92,],[140,]),'instanceDeclaration':([3,],[12,]),'propertyDeclaration_8':([100,149,151,191,198,229,230,270,301,305,331,332,337,338,354,358,],[165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,]),'parameter_3':([241,293,319,],[280,280,280,]),'classDeclaration':([3,],[13,]),'valueInitializer':([94,142,145,187,193,226,227,268,],[144,144,194,144,194,144,194,194,]),'methodName':([164,208,],[203,246,]),'parameter_2':([241,293,319,],[284,284,284,]),'associationFeatureList':([250,298,299,330,],[301,331,332,354,]),'valueInitializerList':([94,142,187,226,],[145,193,227,268,]),'pragmaName':([20,],[69,]),'mofProduction':([3,],[15,]),'constantValue':([79,80,173,182,],[104,120,210,221,]),'parameterName':([278,282,321,322,],[315,318,349,350,]),'propertyName':([164,208,],[204,247,]),'array':([135,204,247,315,318,349,350,],[184,243,295,345,346,363,364,]),'mp_setQualifier':([3,],[17,]),'integerValue':([79,80,173,182,185,],[116,116,116,116,225,]),'className':([11,21,68,76,90,100,149,151,167,176,177,191,198,229,230,241,270,287,293,301,305,319,331,332,337,338,354,358,],[55,71,91,102,136,166,166,166,166,211,212,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,]),'alias':([55,71,91,136,211,212,],[72,93,137,186,248,251,]),'superClass':([55,72,91,137,211,212,248,251,],[74,95,138,188,249,252,297,302,]),'metaElement':([213,307,],[260,340,]),'assocDeclaration':([3,],[18,]),'qualifierList':([3,94,100,142,145,149,151,187,191,193,198,226,227,229,230,241,268,270,293,301,305,319,331,332,337,338,354,358,],[19,146,167,146,146,167,167,146,167,146,167,146,146,167,167,287,146,167,287,167,167,287,167,167,167,167,167,167,]),'identifier':([11,14,16,20,21,68,76,90,94,98,100,129,142,143,145,146,149,151,152,164,167,176,177,182,187,191,193,198,207,208,226,227,229,230,241,268,270,278,282,287,293,301,305,319,321,322,331,332,337,338,354,358,],[38,63,63,70,38,38,38,38,147,150,38,63,147,63,147,196,38,38,202,205,38,38,38,222,147,38,147,38,202,205,147,147,38,38,38,147,38,316,316,38,38,38,38,38,316,316,38,38,38,38,38,38,]),'qualifierListEmpty':([60,61,62,],[83,84,85,]),'nullValue':([79,80,173,182,],[118,118,118,118,]),} _lr_goto = { } for _k, _v in _lr_goto_items.items(): for _x,_y in zip(_v[0],_v[1]): if not _x in _lr_goto: _lr_goto[_x] = { } _lr_goto[_x][_k] = _y del _lr_goto_items _lr_productions = [ ("S' -> mofSpecification","S'",1,None,None,None), ('mofSpecification -> mofProductionList','mofSpecification',1,'p_mofSpecification','/tmp/pywbem/pywbem/mof_compiler.py',179), ('mofProductionList -> empty','mofProductionList',1,'p_mofProductionList','/tmp/pywbem/pywbem/mof_compiler.py',182), ('mofProductionList -> mofProductionList mofProduction','mofProductionList',2,'p_mofProductionList','/tmp/pywbem/pywbem/mof_compiler.py',183), ('mofProduction -> compilerDirective','mofProduction',1,'p_mofProduction','/tmp/pywbem/pywbem/mof_compiler.py',187), ('mofProduction -> mp_createClass','mofProduction',1,'p_mofProduction','/tmp/pywbem/pywbem/mof_compiler.py',188), ('mofProduction -> mp_setQualifier','mofProduction',1,'p_mofProduction','/tmp/pywbem/pywbem/mof_compiler.py',189), ('mofProduction -> mp_createInstance','mofProduction',1,'p_mofProduction','/tmp/pywbem/pywbem/mof_compiler.py',190), ('mp_createClass -> classDeclaration','mp_createClass',1,'p_mp_createClass','/tmp/pywbem/pywbem/mof_compiler.py',250), ('mp_createClass -> assocDeclaration','mp_createClass',1,'p_mp_createClass','/tmp/pywbem/pywbem/mof_compiler.py',251), ('mp_createClass -> indicDeclaration','mp_createClass',1,'p_mp_createClass','/tmp/pywbem/pywbem/mof_compiler.py',252), ('mp_createInstance -> instanceDeclaration','mp_createInstance',1,'p_mp_createInstance','/tmp/pywbem/pywbem/mof_compiler.py',357), ('mp_setQualifier -> qualifierDeclaration','mp_setQualifier',1,'p_mp_setQualifier','/tmp/pywbem/pywbem/mof_compiler.py',382), ('compilerDirective -> # PRAGMA pragmaName ( pragmaParameter )','compilerDirective',6,'p_compilerDirective','/tmp/pywbem/pywbem/mof_compiler.py',411), ('pragmaName -> identifier','pragmaName',1,'p_pragmaName','/tmp/pywbem/pywbem/mof_compiler.py',427), ('pragmaParameter -> stringValue','pragmaParameter',1,'p_pragmaParameter','/tmp/pywbem/pywbem/mof_compiler.py',431), ('classDeclaration -> CLASS className { classFeatureList } ;','classDeclaration',6,'p_classDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',435), ('classDeclaration -> CLASS className superClass { classFeatureList } ;','classDeclaration',7,'p_classDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',436), ('classDeclaration -> CLASS className alias { classFeatureList } ;','classDeclaration',7,'p_classDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',437), ('classDeclaration -> CLASS className alias superClass { classFeatureList } ;','classDeclaration',8,'p_classDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',438), ('classDeclaration -> qualifierList CLASS className { classFeatureList } ;','classDeclaration',7,'p_classDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',439), ('classDeclaration -> qualifierList CLASS className superClass { classFeatureList } ;','classDeclaration',8,'p_classDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',440), ('classDeclaration -> qualifierList CLASS className alias { classFeatureList } ;','classDeclaration',8,'p_classDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',441), ('classDeclaration -> qualifierList CLASS className alias superClass { classFeatureList } ;','classDeclaration',9,'p_classDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',442), ('classFeatureList -> empty','classFeatureList',1,'p_classFeatureList','/tmp/pywbem/pywbem/mof_compiler.py',493), ('classFeatureList -> classFeatureList classFeature','classFeatureList',2,'p_classFeatureList','/tmp/pywbem/pywbem/mof_compiler.py',494), ('assocDeclaration -> [ ASSOCIATION qualifierListEmpty ] CLASS className { associationFeatureList } ;','assocDeclaration',10,'p_assocDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',502), ('assocDeclaration -> [ ASSOCIATION qualifierListEmpty ] CLASS className superClass { associationFeatureList } ;','assocDeclaration',11,'p_assocDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',503), ('assocDeclaration -> [ ASSOCIATION qualifierListEmpty ] CLASS className alias { associationFeatureList } ;','assocDeclaration',11,'p_assocDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',504), ('assocDeclaration -> [ ASSOCIATION qualifierListEmpty ] CLASS className alias superClass { associationFeatureList } ;','assocDeclaration',12,'p_assocDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',505), ('indicDeclaration -> [ INDICATION qualifierListEmpty ] CLASS className { classFeatureList } ;','indicDeclaration',10,'p_indicDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',513), ('indicDeclaration -> [ INDICATION qualifierListEmpty ] CLASS className superClass { classFeatureList } ;','indicDeclaration',11,'p_indicDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',514), ('indicDeclaration -> [ INDICATION qualifierListEmpty ] CLASS className alias { classFeatureList } ;','indicDeclaration',11,'p_indicDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',515), ('indicDeclaration -> [ INDICATION qualifierListEmpty ] CLASS className alias superClass { classFeatureList } ;','indicDeclaration',12,'p_indicDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',516), ('qualifierListEmpty -> empty','qualifierListEmpty',1,'p_qualifierListEmpty','/tmp/pywbem/pywbem/mof_compiler.py',556), ('qualifierListEmpty -> qualifierListEmpty , qualifier','qualifierListEmpty',3,'p_qualifierListEmpty','/tmp/pywbem/pywbem/mof_compiler.py',557), ('associationFeatureList -> empty','associationFeatureList',1,'p_associationFeatureList','/tmp/pywbem/pywbem/mof_compiler.py',565), ('associationFeatureList -> associationFeatureList associationFeature','associationFeatureList',2,'p_associationFeatureList','/tmp/pywbem/pywbem/mof_compiler.py',566), ('className -> identifier','className',1,'p_className','/tmp/pywbem/pywbem/mof_compiler.py',574), ('alias -> AS aliasIdentifier','alias',2,'p_alias','/tmp/pywbem/pywbem/mof_compiler.py',578), ('aliasIdentifier -> $ identifier','aliasIdentifier',2,'p_aliasIdentifier','/tmp/pywbem/pywbem/mof_compiler.py',582), ('superClass -> : className','superClass',2,'p_superClass','/tmp/pywbem/pywbem/mof_compiler.py',586), ('classFeature -> propertyDeclaration','classFeature',1,'p_classFeature','/tmp/pywbem/pywbem/mof_compiler.py',590), ('classFeature -> methodDeclaration','classFeature',1,'p_classFeature','/tmp/pywbem/pywbem/mof_compiler.py',591), ('classFeature -> referenceDeclaration','classFeature',1,'p_classFeature','/tmp/pywbem/pywbem/mof_compiler.py',592), ('associationFeature -> classFeature','associationFeature',1,'p_associationFeature','/tmp/pywbem/pywbem/mof_compiler.py',597), ('qualifierList -> [ qualifier qualifierListEmpty ]','qualifierList',4,'p_qualifierList','/tmp/pywbem/pywbem/mof_compiler.py',601), ('qualifier -> qualifierName','qualifier',1,'p_qualifier','/tmp/pywbem/pywbem/mof_compiler.py',605), ('qualifier -> qualifierName : flavorList','qualifier',3,'p_qualifier','/tmp/pywbem/pywbem/mof_compiler.py',606), ('qualifier -> qualifierName qualifierParameter','qualifier',2,'p_qualifier','/tmp/pywbem/pywbem/mof_compiler.py',607), ('qualifier -> qualifierName qualifierParameter : flavorList','qualifier',4,'p_qualifier','/tmp/pywbem/pywbem/mof_compiler.py',608), ('flavorList -> flavor','flavorList',1,'p_flavorList','/tmp/pywbem/pywbem/mof_compiler.py',660), ('flavorList -> flavorList flavor','flavorList',2,'p_flavorList','/tmp/pywbem/pywbem/mof_compiler.py',661), ('qualifierParameter -> ( constantValue )','qualifierParameter',3,'p_qualifierParameter','/tmp/pywbem/pywbem/mof_compiler.py',669), ('qualifierParameter -> arrayInitializer','qualifierParameter',1,'p_qualifierParameter','/tmp/pywbem/pywbem/mof_compiler.py',670), ('flavor -> ENABLEOVERRIDE','flavor',1,'p_flavor','/tmp/pywbem/pywbem/mof_compiler.py',678), ('flavor -> DISABLEOVERRIDE','flavor',1,'p_flavor','/tmp/pywbem/pywbem/mof_compiler.py',679), ('flavor -> RESTRICTED','flavor',1,'p_flavor','/tmp/pywbem/pywbem/mof_compiler.py',680), ('flavor -> TOSUBCLASS','flavor',1,'p_flavor','/tmp/pywbem/pywbem/mof_compiler.py',681), ('flavor -> TRANSLATABLE','flavor',1,'p_flavor','/tmp/pywbem/pywbem/mof_compiler.py',682), ('propertyDeclaration -> propertyDeclaration_1','propertyDeclaration',1,'p_propertyDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',687), ('propertyDeclaration -> propertyDeclaration_2','propertyDeclaration',1,'p_propertyDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',688), ('propertyDeclaration -> propertyDeclaration_3','propertyDeclaration',1,'p_propertyDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',689), ('propertyDeclaration -> propertyDeclaration_4','propertyDeclaration',1,'p_propertyDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',690), ('propertyDeclaration -> propertyDeclaration_5','propertyDeclaration',1,'p_propertyDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',691), ('propertyDeclaration -> propertyDeclaration_6','propertyDeclaration',1,'p_propertyDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',692), ('propertyDeclaration -> propertyDeclaration_7','propertyDeclaration',1,'p_propertyDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',693), ('propertyDeclaration -> propertyDeclaration_8','propertyDeclaration',1,'p_propertyDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',694), ('propertyDeclaration_1 -> dataType propertyName ;','propertyDeclaration_1',3,'p_propertyDeclaration_1','/tmp/pywbem/pywbem/mof_compiler.py',699), ('propertyDeclaration_2 -> dataType propertyName defaultValue ;','propertyDeclaration_2',4,'p_propertyDeclaration_2','/tmp/pywbem/pywbem/mof_compiler.py',703), ('propertyDeclaration_3 -> dataType propertyName array ;','propertyDeclaration_3',4,'p_propertyDeclaration_3','/tmp/pywbem/pywbem/mof_compiler.py',707), ('propertyDeclaration_4 -> dataType propertyName array defaultValue ;','propertyDeclaration_4',5,'p_propertyDeclaration_4','/tmp/pywbem/pywbem/mof_compiler.py',712), ('propertyDeclaration_5 -> qualifierList dataType propertyName ;','propertyDeclaration_5',4,'p_propertyDeclaration_5','/tmp/pywbem/pywbem/mof_compiler.py',717), ('propertyDeclaration_6 -> qualifierList dataType propertyName defaultValue ;','propertyDeclaration_6',5,'p_propertyDeclaration_6','/tmp/pywbem/pywbem/mof_compiler.py',722), ('propertyDeclaration_7 -> qualifierList dataType propertyName array ;','propertyDeclaration_7',5,'p_propertyDeclaration_7','/tmp/pywbem/pywbem/mof_compiler.py',728), ('propertyDeclaration_8 -> qualifierList dataType propertyName array defaultValue ;','propertyDeclaration_8',6,'p_propertyDeclaration_8','/tmp/pywbem/pywbem/mof_compiler.py',734), ('referenceDeclaration -> objectRef referenceName ;','referenceDeclaration',3,'p_referenceDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',740), ('referenceDeclaration -> objectRef referenceName defaultValue ;','referenceDeclaration',4,'p_referenceDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',741), ('referenceDeclaration -> qualifierList objectRef referenceName ;','referenceDeclaration',4,'p_referenceDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',742), ('referenceDeclaration -> qualifierList objectRef referenceName defaultValue ;','referenceDeclaration',5,'p_referenceDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',743), ('methodDeclaration -> dataType methodName ( ) ;','methodDeclaration',5,'p_methodDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',763), ('methodDeclaration -> dataType methodName ( parameterList ) ;','methodDeclaration',6,'p_methodDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',764), ('methodDeclaration -> qualifierList dataType methodName ( ) ;','methodDeclaration',6,'p_methodDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',765), ('methodDeclaration -> qualifierList dataType methodName ( parameterList ) ;','methodDeclaration',7,'p_methodDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',766), ('propertyName -> identifier','propertyName',1,'p_propertyName','/tmp/pywbem/pywbem/mof_compiler.py',789), ('referenceName -> identifier','referenceName',1,'p_referenceName','/tmp/pywbem/pywbem/mof_compiler.py',793), ('methodName -> identifier','methodName',1,'p_methodName','/tmp/pywbem/pywbem/mof_compiler.py',797), ('dataType -> DT_UINT8','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',801), ('dataType -> DT_SINT8','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',802), ('dataType -> DT_UINT16','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',803), ('dataType -> DT_SINT16','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',804), ('dataType -> DT_UINT32','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',805), ('dataType -> DT_SINT32','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',806), ('dataType -> DT_UINT64','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',807), ('dataType -> DT_SINT64','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',808), ('dataType -> DT_REAL32','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',809), ('dataType -> DT_REAL64','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',810), ('dataType -> DT_CHAR16','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',811), ('dataType -> DT_STR','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',812), ('dataType -> DT_BOOL','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',813), ('dataType -> DT_DATETIME','dataType',1,'p_dataType','/tmp/pywbem/pywbem/mof_compiler.py',814), ('objectRef -> className REF','objectRef',2,'p_objectRef','/tmp/pywbem/pywbem/mof_compiler.py',819), ('parameterList -> parameter','parameterList',1,'p_parameterList','/tmp/pywbem/pywbem/mof_compiler.py',823), ('parameterList -> parameterList , parameter','parameterList',3,'p_parameterList','/tmp/pywbem/pywbem/mof_compiler.py',824), ('parameter -> parameter_1','parameter',1,'p_parameter','/tmp/pywbem/pywbem/mof_compiler.py',832), ('parameter -> parameter_2','parameter',1,'p_parameter','/tmp/pywbem/pywbem/mof_compiler.py',833), ('parameter -> parameter_3','parameter',1,'p_parameter','/tmp/pywbem/pywbem/mof_compiler.py',834), ('parameter -> parameter_4','parameter',1,'p_parameter','/tmp/pywbem/pywbem/mof_compiler.py',835), ('parameter_1 -> dataType parameterName','parameter_1',2,'p_parameter_1','/tmp/pywbem/pywbem/mof_compiler.py',840), ('parameter_1 -> dataType parameterName array','parameter_1',3,'p_parameter_1','/tmp/pywbem/pywbem/mof_compiler.py',841), ('parameter_2 -> qualifierList dataType parameterName','parameter_2',3,'p_parameter_2','/tmp/pywbem/pywbem/mof_compiler.py',850), ('parameter_2 -> qualifierList dataType parameterName array','parameter_2',4,'p_parameter_2','/tmp/pywbem/pywbem/mof_compiler.py',851), ('parameter_3 -> objectRef parameterName','parameter_3',2,'p_parameter_3','/tmp/pywbem/pywbem/mof_compiler.py',861), ('parameter_3 -> objectRef parameterName array','parameter_3',3,'p_parameter_3','/tmp/pywbem/pywbem/mof_compiler.py',862), ('parameter_4 -> qualifierList objectRef parameterName','parameter_4',3,'p_parameter_4','/tmp/pywbem/pywbem/mof_compiler.py',871), ('parameter_4 -> qualifierList objectRef parameterName array','parameter_4',4,'p_parameter_4','/tmp/pywbem/pywbem/mof_compiler.py',872), ('parameterName -> identifier','parameterName',1,'p_parameterName','/tmp/pywbem/pywbem/mof_compiler.py',883), ('array -> [ ]','array',2,'p_array','/tmp/pywbem/pywbem/mof_compiler.py',887), ('array -> [ integerValue ]','array',3,'p_array','/tmp/pywbem/pywbem/mof_compiler.py',888), ('defaultValue -> = initializer','defaultValue',2,'p_defaultValue','/tmp/pywbem/pywbem/mof_compiler.py',896), ('initializer -> constantValue','initializer',1,'p_initializer','/tmp/pywbem/pywbem/mof_compiler.py',900), ('initializer -> arrayInitializer','initializer',1,'p_initializer','/tmp/pywbem/pywbem/mof_compiler.py',901), ('initializer -> referenceInitializer','initializer',1,'p_initializer','/tmp/pywbem/pywbem/mof_compiler.py',902), ('arrayInitializer -> { constantValueList }','arrayInitializer',3,'p_arrayInitializer','/tmp/pywbem/pywbem/mof_compiler.py',907), ('arrayInitializer -> { }','arrayInitializer',2,'p_arrayInitializer','/tmp/pywbem/pywbem/mof_compiler.py',908), ('constantValueList -> constantValue','constantValueList',1,'p_constantValueList','/tmp/pywbem/pywbem/mof_compiler.py',916), ('constantValueList -> constantValueList , constantValue','constantValueList',3,'p_constantValueList','/tmp/pywbem/pywbem/mof_compiler.py',917), ('stringValueList -> stringValue','stringValueList',1,'p_stringValueList','/tmp/pywbem/pywbem/mof_compiler.py',971), ('stringValueList -> stringValueList stringValue','stringValueList',2,'p_stringValueList','/tmp/pywbem/pywbem/mof_compiler.py',972), ('constantValue -> integerValue','constantValue',1,'p_constantValue','/tmp/pywbem/pywbem/mof_compiler.py',981), ('constantValue -> floatValue','constantValue',1,'p_constantValue','/tmp/pywbem/pywbem/mof_compiler.py',982), ('constantValue -> charValue','constantValue',1,'p_constantValue','/tmp/pywbem/pywbem/mof_compiler.py',983), ('constantValue -> stringValueList','constantValue',1,'p_constantValue','/tmp/pywbem/pywbem/mof_compiler.py',984), ('constantValue -> booleanValue','constantValue',1,'p_constantValue','/tmp/pywbem/pywbem/mof_compiler.py',985), ('constantValue -> nullValue','constantValue',1,'p_constantValue','/tmp/pywbem/pywbem/mof_compiler.py',986), ('integerValue -> binaryValue','integerValue',1,'p_integerValue','/tmp/pywbem/pywbem/mof_compiler.py',991), ('integerValue -> octalValue','integerValue',1,'p_integerValue','/tmp/pywbem/pywbem/mof_compiler.py',992), ('integerValue -> decimalValue','integerValue',1,'p_integerValue','/tmp/pywbem/pywbem/mof_compiler.py',993), ('integerValue -> hexValue','integerValue',1,'p_integerValue','/tmp/pywbem/pywbem/mof_compiler.py',994), ('referenceInitializer -> objectHandle','referenceInitializer',1,'p_referenceInitializer','/tmp/pywbem/pywbem/mof_compiler.py',1000), ('referenceInitializer -> aliasIdentifier','referenceInitializer',1,'p_referenceInitializer','/tmp/pywbem/pywbem/mof_compiler.py',1001), ('objectHandle -> identifier','objectHandle',1,'p_objectHandle','/tmp/pywbem/pywbem/mof_compiler.py',1015), ('qualifierDeclaration -> QUALIFIER qualifierName qualifierType scope ;','qualifierDeclaration',5,'p_qualifierDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',1019), ('qualifierDeclaration -> QUALIFIER qualifierName qualifierType scope defaultFlavor ;','qualifierDeclaration',6,'p_qualifierDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',1020), ('qualifierName -> identifier','qualifierName',1,'p_qualifierName','/tmp/pywbem/pywbem/mof_compiler.py',1061), ('qualifierName -> ASSOCIATION','qualifierName',1,'p_qualifierName','/tmp/pywbem/pywbem/mof_compiler.py',1062), ('qualifierName -> INDICATION','qualifierName',1,'p_qualifierName','/tmp/pywbem/pywbem/mof_compiler.py',1063), ('qualifierType -> qualifierType_1','qualifierType',1,'p_qualifierType','/tmp/pywbem/pywbem/mof_compiler.py',1068), ('qualifierType -> qualifierType_2','qualifierType',1,'p_qualifierType','/tmp/pywbem/pywbem/mof_compiler.py',1069), ('qualifierType_1 -> : dataType array','qualifierType_1',3,'p_qualifierType_1','/tmp/pywbem/pywbem/mof_compiler.py',1074), ('qualifierType_1 -> : dataType array defaultValue','qualifierType_1',4,'p_qualifierType_1','/tmp/pywbem/pywbem/mof_compiler.py',1075), ('qualifierType_2 -> : dataType','qualifierType_2',2,'p_qualifierType_2','/tmp/pywbem/pywbem/mof_compiler.py',1083), ('qualifierType_2 -> : dataType defaultValue','qualifierType_2',3,'p_qualifierType_2','/tmp/pywbem/pywbem/mof_compiler.py',1084), ('scope -> , SCOPE ( metaElementList )','scope',5,'p_scope','/tmp/pywbem/pywbem/mof_compiler.py',1092), ('metaElementList -> metaElement','metaElementList',1,'p_metaElementList','/tmp/pywbem/pywbem/mof_compiler.py',1107), ('metaElementList -> metaElementList , metaElement','metaElementList',3,'p_metaElementList','/tmp/pywbem/pywbem/mof_compiler.py',1108), ('metaElement -> SCHEMA','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1116), ('metaElement -> CLASS','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1117), ('metaElement -> ASSOCIATION','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1118), ('metaElement -> INDICATION','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1119), ('metaElement -> QUALIFIER','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1120), ('metaElement -> PROPERTY','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1121), ('metaElement -> REFERENCE','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1122), ('metaElement -> METHOD','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1123), ('metaElement -> PARAMETER','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1124), ('metaElement -> ANY','metaElement',1,'p_metaElement','/tmp/pywbem/pywbem/mof_compiler.py',1125), ('defaultFlavor -> , FLAVOR ( flavorListWithComma )','defaultFlavor',5,'p_defaultFlavor','/tmp/pywbem/pywbem/mof_compiler.py',1130), ('flavorListWithComma -> flavor','flavorListWithComma',1,'p_flavorListWithComma','/tmp/pywbem/pywbem/mof_compiler.py',1143), ('flavorListWithComma -> flavorListWithComma , flavor','flavorListWithComma',3,'p_flavorListWithComma','/tmp/pywbem/pywbem/mof_compiler.py',1144), ('instanceDeclaration -> INSTANCE OF className { valueInitializerList } ;','instanceDeclaration',7,'p_instanceDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',1152), ('instanceDeclaration -> INSTANCE OF className alias { valueInitializerList } ;','instanceDeclaration',8,'p_instanceDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',1153), ('instanceDeclaration -> qualifierList INSTANCE OF className { valueInitializerList } ;','instanceDeclaration',8,'p_instanceDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',1154), ('instanceDeclaration -> qualifierList INSTANCE OF className alias { valueInitializerList } ;','instanceDeclaration',9,'p_instanceDeclaration','/tmp/pywbem/pywbem/mof_compiler.py',1155), ('valueInitializerList -> valueInitializer','valueInitializerList',1,'p_valueInitializerList','/tmp/pywbem/pywbem/mof_compiler.py',1233), ('valueInitializerList -> valueInitializerList valueInitializer','valueInitializerList',2,'p_valueInitializerList','/tmp/pywbem/pywbem/mof_compiler.py',1234), ('valueInitializer -> identifier defaultValue ;','valueInitializer',3,'p_valueInitializer','/tmp/pywbem/pywbem/mof_compiler.py',1243), ('valueInitializer -> qualifierList identifier defaultValue ;','valueInitializer',4,'p_valueInitializer','/tmp/pywbem/pywbem/mof_compiler.py',1244), ('booleanValue -> FALSE','booleanValue',1,'p_booleanValue','/tmp/pywbem/pywbem/mof_compiler.py',1257), ('booleanValue -> TRUE','booleanValue',1,'p_booleanValue','/tmp/pywbem/pywbem/mof_compiler.py',1258), ('nullValue -> NULL','nullValue',1,'p_nullValue','/tmp/pywbem/pywbem/mof_compiler.py',1263), ('identifier -> IDENTIFIER','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1267), ('identifier -> ANY','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1268), ('identifier -> AS','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1269), ('identifier -> CLASS','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1270), ('identifier -> DISABLEOVERRIDE','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1271), ('identifier -> dataType','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1272), ('identifier -> ENABLEOVERRIDE','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1273), ('identifier -> FLAVOR','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1274), ('identifier -> INSTANCE','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1275), ('identifier -> METHOD','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1276), ('identifier -> OF','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1277), ('identifier -> PARAMETER','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1278), ('identifier -> PRAGMA','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1279), ('identifier -> PROPERTY','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1280), ('identifier -> QUALIFIER','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1281), ('identifier -> REFERENCE','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1282), ('identifier -> RESTRICTED','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1283), ('identifier -> SCHEMA','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1284), ('identifier -> SCOPE','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1285), ('identifier -> TOSUBCLASS','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1286), ('identifier -> TRANSLATABLE','identifier',1,'p_identifier','/tmp/pywbem/pywbem/mof_compiler.py',1287), ('empty -> ','empty',0,'p_empty','/tmp/pywbem/pywbem/mof_compiler.py',1294), ] pywbem-0.8.0~dev/pywbem/moflextab.py0000644000175000017500000000474412413747203017463 0ustar bzedbzed00000000000000# moflextab.py. This file automatically created by PLY (version 3.0). Don't edit! _tabversion = '3.0' _lextokens = {'DT_UINT8': 1, 'DISABLEOVERRIDE': 1, 'DT_STR': 1, 'DT_SINT64': 1, 'octalValue': 1, 'stringValue': 1, 'decimalValue': 1, 'DT_DATETIME': 1, 'REF': 1, 'charValue': 1, 'NULL': 1, 'REFERENCE': 1, 'TRUE': 1, 'TOSUBCLASS': 1, 'DT_REAL64': 1, 'TRANSLATABLE': 1, 'DT_UINT32': 1, 'PARAMETER': 1, 'ENABLEOVERRIDE': 1, 'CLASS': 1, 'ASSOCIATION': 1, 'SCHEMA': 1, 'DT_BOOL': 1, 'DT_UINT16': 1, 'floatValue': 1, 'DT_SINT16': 1, 'AS': 1, 'DT_SINT32': 1, 'binaryValue': 1, 'PRAGMA': 1, 'SCOPE': 1, 'FLAVOR': 1, 'DT_CHAR16': 1, 'DT_REAL32': 1, 'DT_SINT8': 1, 'FALSE': 1, 'QUALIFIER': 1, 'DT_UINT64': 1, 'OF': 1, 'hexValue': 1, 'METHOD': 1, 'INSTANCE': 1, 'IDENTIFIER': 1, 'INDICATION': 1, 'RESTRICTED': 1, 'PROPERTY': 1, 'ANY': 1} _lexreflags = 0 _lexliterals = '#(){};[],$:=' _lexstateinfo = {'INITIAL': 'inclusive'} _lexstatere = {'INITIAL': [('(?P//.*)|(?P/\\*(.|\\n)*?\\*/)|(?P([a-zA-Z_]|(([\\xC2-\\xDF][\\x80-\\xBF])|(\\xE0[\\xA0-\\xBF][\\x80-\\xBF])|([\\xE1-\\xEC][\\x80-\\xBF][\\x80-\\xBF])|(\\xED[\\x80-\\x9F][\\x80-\\xBF])|([\\xEE-\\xEF][\\x80-\\xBF][\\x80-\\xBF])|(\\xF0[\\x90-\\xBF][\\x80-\\xBF][\\x80-\\xBF])|([\\xF1-\\xF3][\\x80-\\xBF][\\x80-\\xBF][\\x80-\\xBF])|(\\xF4[\\x80-\\x8F][\\x80-\\xBF][\\x80-\\xBF])))([0-9a-zA-Z_]|(([\\xC2-\\xDF][\\x80-\\xBF])|(\\xE0[\\xA0-\\xBF][\\x80-\\xBF])|([\\xE1-\\xEC][\\x80-\\xBF][\\x80-\\xBF])|(\\xED[\\x80-\\x9F][\\x80-\\xBF])|([\\xEE-\\xEF][\\x80-\\xBF][\\x80-\\xBF])|(\\xF0[\\x90-\\xBF][\\x80-\\xBF][\\x80-\\xBF])|([\\xF1-\\xF3][\\x80-\\xBF][\\x80-\\xBF][\\x80-\\xBF])|(\\xF4[\\x80-\\x8F][\\x80-\\xBF][\\x80-\\xBF])))*)|(?P\\n+)|(?P"([^"\\\\\\n\\r]|([\\\\](([bfnrt\'"\\\\])|(x[0-9a-fA-F]{1,4}))))*")|(?P[+-]?[0-9]*\\.[0-9]+([eE][+-]?[0-9]+)?)|(?P[+-]?0[xX][0-9a-fA-F]+)|(?P[+-]?([1-9][0-9]*|0))|(?P[+-]?[01]+[bB])|(?P[+-]?0[0-7]+)', [None, ('t_COMMENT', 'COMMENT'), ('t_MCOMMENT', 'MCOMMENT'), None, ('t_IDENTIFIER', 'IDENTIFIER'), None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ('t_newline', 'newline'), (None, 'stringValue'), None, None, None, None, None, (None, 'floatValue'), None, (None, 'hexValue'), (None, 'decimalValue'), None, (None, 'binaryValue'), (None, 'octalValue')])]} _lexstateignore = {'INITIAL': ' \r\t'} _lexstateerrorf = {'INITIAL': 't_error'} pywbem-0.8.0~dev/pywbem/mof_compiler.py0000644000175000017500000016170612413747174020166 0ustar bzedbzed00000000000000#!/usr/bin/env python # # (C) Copyright 2006-2007 Novell, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Bart Whiteley import sys import os from getpass import getpass from pywbem import lex from pywbem import yacc from pywbem.lex import TOKEN from pywbem.cim_operations import CIMError, WBEMConnection from pywbem.cim_obj import * from pywbem.cim_constants import * _optimize = 1 _tabmodule='mofparsetab' _lextab='moflextab' _outputdir='pywbem' reserved = { 'any':'ANY', 'as':'AS', 'association':'ASSOCIATION', 'class':'CLASS', 'disableoverride':'DISABLEOVERRIDE', 'boolean':'DT_BOOL', 'char16':'DT_CHAR16', 'datetime':'DT_DATETIME', 'pragma':'PRAGMA', 'real32':'DT_REAL32', 'real64':'DT_REAL64', 'sint16':'DT_SINT16', 'sint32':'DT_SINT32', 'sint64':'DT_SINT64', 'sint8':'DT_SINT8', 'string':'DT_STR', 'uint16':'DT_UINT16', 'uint32':'DT_UINT32', 'uint64':'DT_UINT64', 'uint8':'DT_UINT8', 'enableoverride':'ENABLEOVERRIDE', 'false':'FALSE', 'flavor':'FLAVOR', 'indication':'INDICATION', 'instance':'INSTANCE', 'method':'METHOD', 'null':'NULL', 'of':'OF', 'parameter':'PARAMETER', 'property':'PROPERTY', 'qualifier':'QUALIFIER', 'ref':'REF', 'reference':'REFERENCE', 'restricted':'RESTRICTED', 'schema':'SCHEMA', 'scope':'SCOPE', 'tosubclass':'TOSUBCLASS', 'translatable':'TRANSLATABLE', 'true':'TRUE', } tokens = reserved.values() + [ 'IDENTIFIER', 'stringValue', 'floatValue', 'charValue', 'binaryValue', 'octalValue', 'decimalValue', 'hexValue', ] literals = '#(){};[],$:=' # UTF-8 (from Unicode 4.0.0 standard): # Table 3-6. Well-Formed UTF-8 Byte Sequences Code Points # 1st Byte 2nd Byte 3rd Byte 4th Byte # U+0000..U+007F 00..7F # U+0080..U+07FF C2..DF 80..BF # U+0800..U+0FFF E0 A0..BF 80..BF # U+1000..U+CFFF E1..EC 80..BF 80..BF # U+D000..U+D7FF ED 80..9F 80..BF # U+E000..U+FFFF EE..EF 80..BF 80..BF # U+10000..U+3FFFF F0 90..BF 80..BF 80..BF # U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF # U+100000..U+10FFFF F4 80..8F 80..BF 80..BF utf8_2 = r'[\xC2-\xDF][\x80-\xBF]' utf8_3_1 = r'\xE0[\xA0-\xBF][\x80-\xBF]' utf8_3_2 = r'[\xE1-\xEC][\x80-\xBF][\x80-\xBF]' utf8_3_3 = r'\xED[\x80-\x9F][\x80-\xBF]' utf8_3_4 = r'[\xEE-\xEF][\x80-\xBF][\x80-\xBF]' utf8_4_1 = r'\xF0[\x90-\xBF][\x80-\xBF][\x80-\xBF]' utf8_4_2 = r'[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]' utf8_4_3 = r'\xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]' utf8Char = r'(%s)|(%s)|(%s)|(%s)|(%s)|(%s)|(%s)|(%s)' % (utf8_2, utf8_3_1, utf8_3_2, utf8_3_3, utf8_3_4, utf8_4_1, utf8_4_2, utf8_4_3) def t_COMMENT(t): r'//.*' pass def t_MCOMMENT(t): r'/\*(.|\n)*?\*/' t.lineno += t.value.count('\n') t_binaryValue = r'[+-]?[01]+[bB]' t_octalValue = r'[+-]?0[0-7]+' t_decimalValue = r'[+-]?([1-9][0-9]*|0)' t_hexValue = r'[+-]?0[xX][0-9a-fA-F]+' t_floatValue = r'[+-]?[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?' simpleEscape = r"""[bfnrt'"\\]""" hexEscape = r'x[0-9a-fA-F]{1,4}' escapeSequence = r'[\\]((%s)|(%s))' % (simpleEscape, hexEscape) cChar = r"[^'\\\n\r]|(%s)" % escapeSequence sChar = r'[^"\\\n\r]|(%s)' % escapeSequence charValue = r"'%s'" % cChar t_stringValue = r'"(%s)*"' % sChar identifier_re = r'([a-zA-Z_]|(%s))([0-9a-zA-Z_]|(%s))*' % (utf8Char, utf8Char) @TOKEN(identifier_re) def t_IDENTIFIER(t): t.type = reserved.get(t.value.lower(),'IDENTIFIER') # check for reserved word return t # Define a rule so we can track line numbers def t_newline(t): r'\n+' t.lexer.lineno += len(t.value) t.lexer.linestart = t.lexpos t_ignore = ' \r\t' # Error handling rule def t_error(t): msg = "Illegal character '%s' " % t.value[0] msg+= "Line %d, col %d" % (t.lineno, _find_column(t.lexer.parser.mof, t)) t.lexer.parser.log(msg) t.lexer.skip(1) class MOFParseError(ValueError): pass def p_error(p): ex = MOFParseError() if p is None: ex.args = ('Unexpected end of file',) raise ex ex.file = p.lexer.parser.file ex.lineno = p.lineno ex.column = _find_column(p.lexer.parser.mof, p) ex.context = _get_error_context(p.lexer.parser.mof, p) raise ex def p_mofSpecification(p): """mofSpecification : mofProductionList""" def p_mofProductionList(p): """mofProductionList : empty | mofProductionList mofProduction """ def p_mofProduction(p): """mofProduction : compilerDirective | mp_createClass | mp_setQualifier | mp_createInstance """ def _create_ns(p, handle, ns): # Figure out the flavor of cim server cimom_type = None ns = ns.strip('/') try: inames = handle.EnumerateInstanceNames('__Namespace', namespace='root') inames = [x['name'] for x in inames] if 'PG_InterOp' in inames: cimom_type = 'pegasus' except CIMError, ce: if ce.args[0] != CIM_ERR_NOT_FOUND: ce.file_line = (p.parser.file, p.lexer.lineno) raise if not cimom_type: try: inames = handle.EnumerateInstanceNames('CIM_Namespace', namespace='Interop') inames = [x['name'] for x in inames] cimom_type = 'proper' except CIMError, ce: ce.file_line = (p.parser.file, p.lexer.lineno) raise if not cimom_type: ce = CIMError(CIM_ERR_FAILED, 'Unable to determine CIMOM type') ce.file_line = (p.parser.file, p.lexer.lineno) raise ce if cimom_type == 'pegasus': # To create a namespace in Pegasus, create an instance of # __Namespace with __Namespace.Name = '', and create it in # the target namespace to be created. inst = CIMInstance('__Namespace', properties={'Name':''}, path=CIMInstanceName('__Namespace', keybindings={'Name':''}, namespace=ns)) try: handle.CreateInstance(inst) except CIMError, ce: if ce.args[0] != CIM_ERR_ALREADY_EXISTS: ce.file_line = (p.parser.file, p.lexer.lineno) raise elif cimom_type == 'proper': inst = CIMInstance('CIM_Namespace', properties={'Name': ns}, path=CIMInstanceName('CIM_Namespace', namespace='root', keybindings={'Name':ns})) handle.CreateInstance(inst) def p_mp_createClass(p): """mp_createClass : classDeclaration | assocDeclaration | indicDeclaration """ ns = p.parser.handle.default_namespace cc = p[1] try: fixedNS = fixedRefs = fixedSuper = False while not fixedNS or not fixedRefs or not fixedSuper: try: if p.parser.verbose: p.parser.log('Creating class %s:%s' % (ns, cc.classname)) p.parser.handle.CreateClass(cc) if p.parser.verbose: p.parser.log('Created class %s:%s' % (ns,cc.classname)) p.parser.classnames[ns].append(cc.classname.lower()) break except CIMError, ce: ce.file_line = (p.parser.file, p.lexer.lineno) errcode = ce.args[0] if errcode == CIM_ERR_INVALID_NAMESPACE: if fixedNS: raise if p.parser.verbose: p.parser.log('Creating namespace ' + ns) _create_ns(p, p.parser.handle, ns) fixedNS = True continue if not p.parser.search_paths: raise if errcode == CIM_ERR_INVALID_SUPERCLASS: if fixedSuper: raise moffile = p.parser.mofcomp.find_mof(cc.superclass) if not moffile: raise p.parser.mofcomp.compile_file(moffile, ns) fixedSuper = True elif errcode in [CIM_ERR_INVALID_PARAMETER, CIM_ERR_NOT_FOUND, CIM_ERR_FAILED]: if fixedRefs: raise if not p.parser.qualcache[ns]: for fname in ['qualifiers', 'qualifiers_optional']: qualfile = p.parser.mofcomp.find_mof(fname) if qualfile: p.parser.mofcomp.compile_file(qualfile,ns) if not p.parser.qualcache[ns]: # can't find qualifiers raise objects = cc.properties.values() for meth in cc.methods.values(): objects+= meth.parameters.values() dep_classes = [] for obj in objects: if obj.type not in ['reference','string']: continue if obj.type == 'reference': if obj.reference_class.lower() not in dep_classes: dep_classes.append(obj.reference_class.lower()) continue # else obj.type is 'string' try: embedded_inst= obj.qualifiers['embeddedinstance'] except KeyError: continue embedded_inst = embedded_inst.value.lower() if embedded_inst not in dep_classes: dep_classes.append(embedded_inst) continue for klass in dep_classes: if klass in p.parser.classnames[ns]: continue try: # don't limit it with LocalOnly=True, # PropertyList, IncludeQualifiers=False, ... # because of caching in case we're using the # special WBEMConnection subclass used for # removing schema elements p.parser.handle.GetClass(klass, LocalOnly=False, IncludeQualifiers=True) p.parser.classnames[ns].append(klass) except CIMError: moffile = p.parser.mofcomp.find_mof(klass) if not moffile: raise p.parser.mofcomp.compile_file(moffile, ns) p.parser.classnames[ns].append(klass) fixedRefs = True else: raise except CIMError, ce: ce.file_line = (p.parser.file, p.lexer.lineno) if ce.args[0] != CIM_ERR_ALREADY_EXISTS: raise if p.parser.verbose: p.parser.log('Class %s already exist. Modifying...' % cc.classname) try: p.parser.handle.ModifyClass(cc, ns) except CIMError, ce: p.parser.log('Error Modifying class %s: %s, %s' % (cc.classname, ce.args[0], ce.args[1])) def p_mp_createInstance(p): """mp_createInstance : instanceDeclaration""" inst = p[1] if p.parser.verbose: p.parser.log('Creating instance of %s.' % inst.classname) try: p.parser.handle.CreateInstance(inst) except CIMError, ce: if ce.args[0] == CIM_ERR_ALREADY_EXISTS: if p.parser.verbose: p.parser.log('Instance of class %s already exist. Modifying...' % inst.classname) try: p.parser.handle.ModifyInstance(inst) except CIMError, ce: if ce.args[0] == CIM_ERR_NOT_SUPPORTED: if p.parser.verbose: p.parser.log('ModifyInstance not supported. Deleting instance of %s: %s' % (inst.classname, inst.path)) p.parser.handle.DeleteInstance(inst.path) if p.parser.verbose: p.parser.log('Creating instance of %s.' % inst.classname) p.parser.handle.CreateInstance(inst) else: ce.file_line = (p.parser.file, p.lexer.lineno) raise def p_mp_setQualifier(p): """mp_setQualifier : qualifierDeclaration""" qualdecl = p[1] ns = p.parser.handle.default_namespace if p.parser.verbose: p.parser.log('Setting qualifier %s' % qualdecl.name) try: p.parser.handle.SetQualifier(qualdecl) except CIMError, ce: if ce.args[0] == CIM_ERR_INVALID_NAMESPACE: if p.parser.verbose: p.parser.log('Creating namespace ' + ns) _create_ns(p, p.parser.handle, ns) if p.parser.verbose: p.parser.log('Setting qualifier %s' % qualdecl.name) p.parser.handle.SetQualifier(qualdecl) elif ce.args[0] == CIM_ERR_NOT_SUPPORTED: if p.parser.verbose: p.parser.log('Qualifier %s already exists. Deleting...' % qualdecl.name) p.parser.handle.DeleteQualifier(qualdecl.name) if p.parser.verbose: p.parser.log('Setting qualifier %s' % qualdecl.name) p.parser.handle.SetQualifier(qualdecl) else: ce.file_line = (p.parser.file, p.lexer.lineno) raise p.parser.qualcache[ns][qualdecl.name] = qualdecl def p_compilerDirective(p): """compilerDirective : '#' PRAGMA pragmaName '(' pragmaParameter ')'""" directive = p[3].lower() param = p[5] if directive == 'include': fname = param #if p.parser.file: fname = os.path.dirname(p.parser.file) + '/' + fname p.parser.mofcomp.compile_file(fname, p.parser.handle.default_namespace) elif directive == 'namespace': p.parser.handle.default_namespace = param if param not in p.parser.qualcache: p.parser.qualcache[param] = NocaseDict() p[0] = None def p_pragmaName(p): """pragmaName : identifier""" p[0] = p[1] def p_pragmaParameter(p): """pragmaParameter : stringValue""" p[0] = _fixStringValue(p[1]) def p_classDeclaration(p): """classDeclaration : CLASS className '{' classFeatureList '}' ';' | CLASS className superClass '{' classFeatureList '}' ';' | CLASS className alias '{' classFeatureList '}' ';' | CLASS className alias superClass '{' classFeatureList '}' ';' | qualifierList CLASS className '{' classFeatureList '}' ';' | qualifierList CLASS className superClass '{' classFeatureList '}' ';' | qualifierList CLASS className alias '{' classFeatureList '}' ';' | qualifierList CLASS className alias superClass '{' classFeatureList '}' ';' """ superclass = None alias = None quals = [] if isinstance(p[1], basestring): # no class qualifiers cname = p[2] if p[3][0] == '$': # alias present alias = p[3] if p[4] == '{': # no superclass cfl = p[5] else: # superclass superclass = p[4] cfl = p[6] else: # no alias if p[3] == '{': # no superclass cfl = p[4] else: # superclass superclass = p[3] cfl = p[5] else: # class qualifiers quals = p[1] cname = p[3] if p[4][0] == '$': # alias present alias = p[4] if p[5] == '{': # no superclass cfl = p[6] else: # superclass superclass = p[5] cfl = p[7] else: # no alias if p[4] == '{': # no superclass cfl = p[5] else: # superclass superclass = p[4] cfl = p[6] quals = dict([(x.name, x) for x in quals]) methods = {} props = {} for item in cfl: item.class_origin = cname if isinstance(item, CIMMethod): methods[item.name] = item else: props[item.name] = item p[0] = CIMClass(cname, properties=props, methods=methods, superclass=superclass, qualifiers=quals) if alias: p.parser.aliases[alias] = p[0] def p_classFeatureList(p): """classFeatureList : empty | classFeatureList classFeature """ if len(p) == 2: p[0] = [] else: p[0] = p[1] + [p[2]] def p_assocDeclaration(p): """assocDeclaration : '[' ASSOCIATION qualifierListEmpty ']' CLASS className '{' associationFeatureList '}' ';' | '[' ASSOCIATION qualifierListEmpty ']' CLASS className superClass '{' associationFeatureList '}' ';' | '[' ASSOCIATION qualifierListEmpty ']' CLASS className alias '{' associationFeatureList '}' ';' | '[' ASSOCIATION qualifierListEmpty ']' CLASS className alias superClass '{' associationFeatureList '}' ';' """ aqual = CIMQualifier('ASSOCIATION', True, type='boolean') # TODO flavor trash. quals = [aqual] + p[3] p[0] = _assoc_or_indic_decl(quals, p) def p_indicDeclaration(p): """indicDeclaration : '[' INDICATION qualifierListEmpty ']' CLASS className '{' classFeatureList '}' ';' | '[' INDICATION qualifierListEmpty ']' CLASS className superClass '{' classFeatureList '}' ';' | '[' INDICATION qualifierListEmpty ']' CLASS className alias '{' classFeatureList '}' ';' | '[' INDICATION qualifierListEmpty ']' CLASS className alias superClass '{' classFeatureList '}' ';' """ iqual = CIMQualifier('INDICATION', True, type='boolean') # TODO flavor trash. quals = [iqual] + p[3] p[0] = _assoc_or_indic_decl(quals, p) def _assoc_or_indic_decl(quals, p): """(refer to grammer rules on p_assocDeclaration and p_indicDeclaration)""" superclass = None alias = None cname = p[6] if p[7] == '{': cfl = p[8] elif p[7][0] == '$': # alias alias = p[7] if p[8] == '{': cfl = p[9] else: superclass = p[8] cfl = p[10] else: superclass = p[7] cfl = p[9] props = {} methods = {} for item in cfl: item.class_origin = cname if isinstance(item, CIMMethod): methods[item.name] = item else: props[item.name] = item quals = dict([(x.name, x) for x in quals]) cc = CIMClass(cname, properties=props, methods=methods, superclass=superclass, qualifiers=quals) if alias: p.parser.aliases[alias] = cc return cc def p_qualifierListEmpty(p): """qualifierListEmpty : empty | qualifierListEmpty ',' qualifier """ if len(p) == 2: p[0] = [] else: p[0] = p[1] + [p[3]] def p_associationFeatureList(p): """associationFeatureList : empty | associationFeatureList associationFeature """ if len(p) == 2: p[0] = [] else: p[0] = p[1] + [p[2]] def p_className(p): """className : identifier""" p[0] = p[1] def p_alias(p): """alias : AS aliasIdentifier""" p[0] = p[2] def p_aliasIdentifier(p): """aliasIdentifier : '$' identifier""" p[0] = '$%s' % p[2] def p_superClass(p): """superClass : ':' className""" p[0] = p[2] def p_classFeature(p): """classFeature : propertyDeclaration | methodDeclaration | referenceDeclaration """ p[0] = p[1] def p_associationFeature(p): """associationFeature : classFeature""" p[0] = p[1] def p_qualifierList(p): """qualifierList : '[' qualifier qualifierListEmpty ']'""" p[0] = [p[2]] + p[3] def p_qualifier(p): """qualifier : qualifierName | qualifierName ':' flavorList | qualifierName qualifierParameter | qualifierName qualifierParameter ':' flavorList """ qname = p[1] ns = p.parser.handle.default_namespace qval = None flavorlist = [] if len(p) == 3: qval = p[2] elif len(p) == 4: flavorlist = p[3] elif len(p) == 5: qval = p[2] flavorlist = p[4] try: qualdecl = p.parser.qualcache[ns][qname] except KeyError: try: quals = p.parser.handle.EnumerateQualifiers() except CIMError, ce: if ce.args[0] != CIM_ERR_INVALID_NAMESPACE: ce.file_line = (p.parser.file, p.lexer.lineno) raise _create_ns(p, p.parser.handle, ns) quals = None if quals: for qual in quals: p.parser.qualcache[ns][qual.name] = qual else: for fname in ['qualifiers', 'qualifiers_optional']: qualfile = p.parser.mofcomp.find_mof(fname) if qualfile: p.parser.mofcomp.compile_file(qualfile, ns) try: qualdecl = p.parser.qualcache[ns][qname] except KeyError: ce = CIMError(CIM_ERR_FAILED, 'Unknown Qualifier: %s' % qname) ce.file_line = (p.parser.file, p.lexer.lineno) raise ce flavors = _build_flavors(flavorlist, qualdecl) if qval is None: if qualdecl.type == 'boolean': qval = True else: qval = qualdecl.value # default value else: qval = tocimobj(qualdecl.type, qval) p[0] = CIMQualifier(qname, qval, type=qualdecl.type, **flavors) # TODO propagated? def p_flavorList(p): """flavorList : flavor | flavorList flavor """ if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[2]] def p_qualifierParameter(p): """qualifierParameter : '(' constantValue ')' | arrayInitializer """ if len(p) == 2: p[0] = p[1] else: p[0] = p[2] def p_flavor(p): """flavor : ENABLEOVERRIDE | DISABLEOVERRIDE | RESTRICTED | TOSUBCLASS | TRANSLATABLE """ p[0] = p[1].lower() def p_propertyDeclaration(p): """propertyDeclaration : propertyDeclaration_1 | propertyDeclaration_2 | propertyDeclaration_3 | propertyDeclaration_4 | propertyDeclaration_5 | propertyDeclaration_6 | propertyDeclaration_7 | propertyDeclaration_8 """ p[0] = p[1] def p_propertyDeclaration_1(p): """propertyDeclaration_1 : dataType propertyName ';'""" p[0] = CIMProperty(p[2], None, type=p[1]) def p_propertyDeclaration_2(p): """propertyDeclaration_2 : dataType propertyName defaultValue ';'""" p[0] = CIMProperty(p[2], p[3], type=p[1]) def p_propertyDeclaration_3(p): """propertyDeclaration_3 : dataType propertyName array ';'""" p[0] = CIMProperty(p[2], None, type=p[1], is_array=True, array_size=p[3]) def p_propertyDeclaration_4(p): """propertyDeclaration_4 : dataType propertyName array defaultValue ';'""" p[0] = CIMProperty(p[2], p[4], type=p[1], is_array=True, array_size=p[3]) def p_propertyDeclaration_5(p): """propertyDeclaration_5 : qualifierList dataType propertyName ';'""" quals = dict([(x.name, x) for x in p[1]]) p[0] = CIMProperty(p[3], None, type=p[2], qualifiers=quals) def p_propertyDeclaration_6(p): """propertyDeclaration_6 : qualifierList dataType propertyName defaultValue ';'""" quals = dict([(x.name, x) for x in p[1]]) p[0] = CIMProperty(p[3], tocimobj(p[2], p[4]), type=p[2], qualifiers=quals) def p_propertyDeclaration_7(p): """propertyDeclaration_7 : qualifierList dataType propertyName array ';'""" quals = dict([(x.name, x) for x in p[1]]) p[0] = CIMProperty(p[3], None, type=p[2], qualifiers=quals, is_array=True, array_size=p[4]) def p_propertyDeclaration_8(p): """propertyDeclaration_8 : qualifierList dataType propertyName array defaultValue ';'""" quals = dict([(x.name, x) for x in p[1]]) p[0] = CIMProperty(p[3], tocimobj(p[2], p[5]), type=p[2], qualifiers=quals, is_array=True, array_size=p[4]) def p_referenceDeclaration(p): """referenceDeclaration : objectRef referenceName ';' | objectRef referenceName defaultValue ';' | qualifierList objectRef referenceName ';' | qualifierList objectRef referenceName defaultValue ';' """ quals = [] dv = None if isinstance(p[1], list): # qualifiers quals = p[1] cname = p[2] pname = p[3] if len(p) == 6: dv = p[4] else: cname = p[1] pname = p[2] if len(p) == 5: dv = p[3] quals = dict([(x.name, x) for x in quals]) p[0] = CIMProperty(pname, dv, type='reference', reference_class=cname, qualifiers=quals) def p_methodDeclaration(p): """methodDeclaration : dataType methodName '(' ')' ';' | dataType methodName '(' parameterList ')' ';' | qualifierList dataType methodName '(' ')' ';' | qualifierList dataType methodName '(' parameterList ')' ';' """ paramlist = [] quals = [] if isinstance(p[1], basestring): # no quals dt = p[1] mname = p[2] if p[4] != ')': paramlist = p[4] else: # quals present quals = p[1] dt = p[2] mname = p[3] if p[5] != ')': paramlist = p[5] params = dict([(param.name, param) for param in paramlist]) quals = dict([(q.name, q) for q in quals]) p[0] = CIMMethod(mname, return_type=dt, parameters=params, qualifiers=quals) # note: class_origin is set when adding method to class. # TODO what to do with propagated? def p_propertyName(p): """propertyName : identifier""" p[0] = p[1] def p_referenceName(p): """referenceName : identifier""" p[0] = p[1] def p_methodName(p): """methodName : identifier""" p[0] = p[1] def p_dataType(p): """dataType : DT_UINT8 | DT_SINT8 | DT_UINT16 | DT_SINT16 | DT_UINT32 | DT_SINT32 | DT_UINT64 | DT_SINT64 | DT_REAL32 | DT_REAL64 | DT_CHAR16 | DT_STR | DT_BOOL | DT_DATETIME """ p[0] = p[1].lower() def p_objectRef(p): """objectRef : className REF""" p[0] = p[1] def p_parameterList(p): """parameterList : parameter | parameterList ',' parameter """ if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[3]] def p_parameter(p): """parameter : parameter_1 | parameter_2 | parameter_3 | parameter_4 """ p[0] = p[1] def p_parameter_1(p): """parameter_1 : dataType parameterName | dataType parameterName array """ args = {} if len(p) == 4: args['is_array'] = True args['array_size'] = p[3] p[0] = CIMParameter(p[2], p[1], **args) def p_parameter_2(p): """parameter_2 : qualifierList dataType parameterName | qualifierList dataType parameterName array """ args = {} if len(p) == 5: args['is_array'] = True args['array_size'] = p[4] quals = dict([(x.name, x) for x in p[1]]) p[0] = CIMParameter(p[3], p[2], qualifiers=quals, **args) def p_parameter_3(p): """parameter_3 : objectRef parameterName | objectRef parameterName array """ args = {} if len(p) == 4: args['is_array'] = True args['array_size'] = p[3] p[0] = CIMParameter(p[2], 'reference', reference_class=p[1], **args) def p_parameter_4(p): """parameter_4 : qualifierList objectRef parameterName | qualifierList objectRef parameterName array """ args = {} if len(p) == 5: args['is_array'] = True args['array_size'] = p[4] quals = dict([(x.name, x) for x in p[1]]) p[0] = CIMParameter(p[3], 'reference', qualifiers=quals, reference_class=p[2], **args) def p_parameterName(p): """parameterName : identifier""" p[0] = p[1] def p_array(p): """array : '[' ']' | '[' integerValue ']' """ if len(p) == 3: p[0] = None else: p[0] = p[2] def p_defaultValue(p): """defaultValue : '=' initializer""" p[0] = p[2] def p_initializer(p): """initializer : constantValue | arrayInitializer | referenceInitializer """ p[0] = p[1] def p_arrayInitializer(p): """arrayInitializer : '{' constantValueList '}' | '{' '}' """ if len(p) == 3: p[0] = [] else: p[0] = p[2] def p_constantValueList(p): """constantValueList : constantValue | constantValueList ',' constantValue """ if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[3]] def _fixStringValue(s): s = s[1:-1] rv = '' esc = False i = -1 while i < len(s) -1: i+= 1 ch = s[i] if ch == '\\' and not esc: esc = True continue if not esc: rv+= ch continue if ch == '"' : rv+= '"' elif ch == 'n' : rv+= '\n' elif ch == 't' : rv+= '\t' elif ch == 'b' : rv+= '\b' elif ch == 'f' : rv+= '\f' elif ch == 'r' : rv+= '\r' elif ch == '\\': rv+= '\\' elif ch in ['x','X']: hexc = 0 j = 0 i+= 1 while j < 4: c = s[i+j]; c = c.upper() if not c.isdigit() and not c in 'ABCDEF': break; hexc <<= 4 if c.isdigit(): hexc |= ord(c) - ord('0') else: hexc |= ord(c) - ord('A') + 0XA j+= 1 rv+= chr(hexc) i+= j-1 esc = False return rv def p_stringValueList(p): """stringValueList : stringValue | stringValueList stringValue """ if len(p) == 2: p[0] = _fixStringValue(p[1]) else: p[0] = p[1] + _fixStringValue(p[2]) def p_constantValue(p): """constantValue : integerValue | floatValue | charValue | stringValueList | booleanValue | nullValue """ p[0] = p[1] def p_integerValue(p): """integerValue : binaryValue | octalValue | decimalValue | hexValue """ p[0] = int(p[1]) # TODO deal with non-decimal values. def p_referenceInitializer(p): """referenceInitializer : objectHandle | aliasIdentifier """ if p[1][0] == '$': try: p[0] = p.parser.aliases[p[1]] except KeyError: ce = CIMError(CIM_ERR_FAILED, 'Unknown alias: ' + p[0]) ce.file_line = (p.parser.file, p.lexer.lineno) raise ce else: p[0] = p[1] def p_objectHandle(p): """objectHandle : identifier""" p[0] = p[1] def p_qualifierDeclaration(p): """qualifierDeclaration : QUALIFIER qualifierName qualifierType scope ';' | QUALIFIER qualifierName qualifierType scope defaultFlavor ';' """ qualtype = p[3] dt, is_array, array_size, value = qualtype qualname = p[2] scopes = p[4] if len(p) == 5: flist = [] else: flist = p[5] flavors = _build_flavors(flist) p[0] = CIMQualifierDeclaration(qualname, dt, value=value, is_array=is_array, array_size=array_size, scopes=scopes, **flavors) def _build_flavors(flist, qualdecl=None): flavors = {} if qualdecl is not None: flavors = {'overridable':qualdecl.overridable, 'translatable':qualdecl.translatable, 'toinstance':qualdecl.toinstance, 'tosubclass':qualdecl.tosubclass} if 'disableoverride' in flist: flavors['overridable'] = False if 'enableoverride' in flist: flavors['overridable'] = True if 'translatable' in flist: flavors['translatable'] = True if 'restricted' in flist: flavors['tosubclass'] = False if 'tosubclass' in flist: flavors['tosubclass'] = True try: if flavors['tosubclass']: flavors['toinstance'] = True except KeyError: pass return flavors def p_qualifierName(p): """qualifierName : identifier | ASSOCIATION | INDICATION """ p[0] = p[1] def p_qualifierType(p): """qualifierType : qualifierType_1 | qualifierType_2 """ p[0] = p[1] def p_qualifierType_1(p): """qualifierType_1 : ':' dataType array | ':' dataType array defaultValue """ dv = None if len(p) == 5: dv = p[4] p[0] = (p[2], True, p[3], dv) def p_qualifierType_2(p): """qualifierType_2 : ':' dataType | ':' dataType defaultValue """ dv = None if len(p) == 4: dv = p[3] p[0] = (p[2], False, None, dv) def p_scope(p): """scope : ',' SCOPE '(' metaElementList ')'""" slist = p[4] scopes = {} for i in ('CLASS', 'ASSOCIATION', 'INDICATION', 'PROPERTY', 'REFERENCE', 'METHOD', 'PARAMETER', 'ANY'): scopes[i] = i in slist p[0] = scopes def p_metaElementList(p): """metaElementList : metaElement | metaElementList ',' metaElement """ if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[3]] def p_metaElement(p): """metaElement : SCHEMA | CLASS | ASSOCIATION | INDICATION | QUALIFIER | PROPERTY | REFERENCE | METHOD | PARAMETER | ANY """ p[0] = p[1].upper() def p_defaultFlavor(p): """defaultFlavor : ',' FLAVOR '(' flavorListWithComma ')'""" flist = p[4] flavors = {'ENABLEOVERRIDE':True, 'TOSUBCLASS':True, 'DISABLEOVERRIDE':False, 'RESTRICTED':False, 'TRANSLATABLE':False} for i in flist: flavors[i] = True p[0] = flavors def p_flavorListWithComma(p): """flavorListWithComma : flavor | flavorListWithComma ',' flavor """ if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[3]] def p_instanceDeclaration(p): """instanceDeclaration : INSTANCE OF className '{' valueInitializerList '}' ';' | INSTANCE OF className alias '{' valueInitializerList '}' ';' | qualifierList INSTANCE OF className '{' valueInitializerList '}' ';' | qualifierList INSTANCE OF className alias '{' valueInitializerList '}' ';' """ alias = None quals = {} ns = p.parser.handle.default_namespace if isinstance(p[1], basestring): # no qualifiers cname = p[3] if p[4] == '{': props = p[5] else: props = p[6] alias = p[4] else: cname = p[4] #quals = p[1] # qualifiers on instances are deprecated -- rightly so. if p[5] == '{': props = p[6] else: props = p[7] alias = p[5] try: cc = p.parser.handle.GetClass(cname, LocalOnly=False, IncludeQualifiers=True) p.parser.classnames[ns].append(cc.classname.lower()) except CIMError, ce: ce.file_line = (p.parser.file, p.lexer.lineno) if ce.args[0] == CIM_ERR_NOT_FOUND: file_ = p.parser.mofcomp.find_mof(cname) if p.parser.verbose: p.parser.log('Class %s does not exist' % cname) if file_: p.parser.mofcomp.compile_file(file_, ns) cc = p.parser.handle.GetClass(cname, LocalOnly=False, IncludeQualifiers=True) else: if p.parser.verbose: p.parser.log("Can't find file to satisfy class") ce = CIMError(CIM_ERR_INVALID_CLASS, cname) ce.file_line = (p.parser.file, p.lexer.lineno) raise ce else: raise path = CIMInstanceName(cname, namespace=ns) inst = CIMInstance(cname, properties=cc.properties, qualifiers=quals, path=path) for prop in props: pname = prop[1] pval = prop[2] try: cprop = inst.properties[pname] cprop.value = tocimobj(cprop.type, pval) except KeyError: ce = CIMError(CIM_ERR_INVALID_PARAMETER, 'Invalid property: %s' % pname) ce.file_line = (p.parser.file, p.lexer.lineno) raise ce except ValueError, ve: ce = CIMError(CIM_ERR_INVALID_PARAMETER, 'Invalid value for property: %s: %s' % (pname,ve.message)) ce.file_line = (p.parser.file, p.lexer.lineno) raise ce for prop in inst.properties.values(): if 'key' not in prop.qualifiers or not prop.qualifiers['key']: continue if prop.value is None: ce = CIMError(CIM_ERR_FAILED, 'Key property %s.%s is not set' % (cname, prop.name)) ce.file_line = (p.parser.file, p.lexer.lineno) raise ce inst.path.keybindings[prop.name] = prop.value if alias: p.parser.aliases[alias] = inst.path p[0] = inst def p_valueInitializerList(p): """valueInitializerList : valueInitializer | valueInitializerList valueInitializer """ if len(p) == 2: p[0] = [p[1]] else: p[0] = p[1] + [p[2]] def p_valueInitializer(p): """valueInitializer : identifier defaultValue ';' | qualifierList identifier defaultValue ';' """ if len(p) == 4: id_ = p[1] val = p[2] quals = [] else: quals = p[1] id_ = p[2] val = p[3] p[0] = (quals, id_, val) def p_booleanValue(p): """booleanValue : FALSE | TRUE """ p[0] = p[1].lower() == 'true' def p_nullValue(p): """nullValue : NULL""" p[0] = None def p_identifier(p): """identifier : IDENTIFIER | ANY | AS | CLASS | DISABLEOVERRIDE | dataType | ENABLEOVERRIDE | FLAVOR | INSTANCE | METHOD | OF | PARAMETER | PRAGMA | PROPERTY | QUALIFIER | REFERENCE | RESTRICTED | SCHEMA | SCOPE | TOSUBCLASS | TRANSLATABLE """ #| ASSOCIATION #| INDICATION p[0] = p[1] def p_empty(p): 'empty :' pass def _find_column(input, token): i = token.lexpos while i > 0: if input[i] == '\n': break i-= 1 column = (token.lexpos - i)+1 return column def _get_error_context(input, token): try: line = input[token.lexpos : input.index('\n', token.lexpos)] except ValueError: line = input[token.lexpos:] i = input.rfind('\n', 0, token.lexpos) if i < 0: i = 0 line = input[i:token.lexpos] + line lines = [line.strip('\r\n')] col = token.lexpos - i while len(lines) < 5 and i > 0: end = i i = input.rfind('\n', 0, i) if i < 0: i = 0 lines.insert(0, input[i:end].strip('\r\n')) pointer = '' for ch in token.value: pointer+= '^' pointline = '' i = 0 while i < col -1: if lines[-1][i].isspace(): pointline+= lines[-1][i] # otherwise, tabs complicate the alignment else: pointline+= ' ' i+= 1 lines.append(pointline + pointer) return lines def _print_logger(str): print str class MOFWBEMConnection(object): def __init__(self, conn=None): self.conn = conn self.class_names = {} self.qualifiers = {} self.instances = {} self.classes = {} if conn is None: self.__default_namespace = 'root/cimv2' def setns(self, value): if self.conn is not None: self.conn.default_namespace = value else: self.__default_namespace = value def getns(self): if self.conn is not None: return self.conn.default_namespace else: return self.__default_namespace default_namespace = property(getns, setns, None, "default_namespace property") def GetClass(self, *args, **kwargs): cname = len(args) > 0 and args[0] or kwargs['ClassName'] try: cc = self.classes[self.default_namespace][cname] except KeyError: if self.conn is None: ce = CIMError(CIM_ERR_NOT_FOUND, cname) raise ce cc = self.conn.GetClass(*args, **kwargs) try: self.classes[self.default_namespace][cc.classname] = cc except KeyError: self.classes[self.default_namespace] = \ NocaseDict({cc.classname:cc}) if 'LocalOnly' in kwargs and not kwargs['LocalOnly']: if cc.superclass: try: del kwargs['ClassName'] except KeyError: pass if len(args) > 0: args = args[1:] super_ = self.GetClass(cc.superclass, *args, **kwargs) for prop in super_.properties.values(): if prop.name not in cc.properties: cc.properties[prop.name] = prop for meth in super_.methods.values(): if meth.name not in cc.methods: cc.methods[meth.name] = meth return cc def CreateClass(self, *args, **kwargs): cc = len(args) > 0 and args[0] or kwargs['NewClass'] if cc.superclass: try: super_ = self.GetClass(cc.superclass, LocalOnly=True, IncludeQualifiers=False) except CIMError, ce: if ce.args[0] == CIM_ERR_NOT_FOUND: ce.args = (CIM_ERR_INVALID_SUPERCLASS, cc.superclass) raise else: raise try: self.classes[self.default_namespace][cc.classname] = cc except KeyError: self.classes[self.default_namespace] = \ NocaseDict({cc.classname:cc}) # TODO: should we see if it exists first with # self.conn.GetClass()? Do we want to create a class # that already existed? try: self.class_names[self.default_namespace].append(cc.classname) except KeyError: self.class_names[self.default_namespace] = [cc.classname] def ModifyClass(self, *args, **kwargs): raise CIMError(CIM_ERR_FAILED, 'This should not happen!') def ModifyInstance(self, *args, **kwargs): raise CIMError(CIM_ERR_FAILED, 'This should not happen!') def GetQualifier(self, *args, **kwargs): qualname = len(args) > 0 and args[0] or kwargs['QualifierName'] try: qual = self.qualifiers[self.default_namespace][qualname] except KeyError: if self.conn is None: raise CIMError(CIM_ERR_NOT_FOUND, qualname) qual = self.conn.GetQualifier(*args, **kwargs) return qual def SetQualifier(self, *args, **kwargs): qual = len(args) > 0 and args[0] or kwargs['QualifierDeclaration'] try: self.qualifiers[self.default_namespace][qual.name] = qual except KeyError: self.qualifiers[self.default_namespace] = \ NocaseDict({qual.name:qual}) def EnumerateQualifiers(self, *args, **kwargs): if self.conn is not None: rv = self.conn.EnumerateQualifiers(*args, **kwargs) else: rv = [] try: rv+= self.qualifiers[self.default_namespace].values() except KeyError: pass return rv def CreateInstance(self, *args, **kwargs): inst = len(args) > 0 and args[0] or kwargs['NewInstance'] try: self.instances[self.default_namespace].append(inst) except KeyError: self.instances[self.default_namespace] = [inst] return inst.path def rollback(self, verbose=False): for ns, insts in self.instances.items(): insts.reverse() for inst in insts: try: if verbose: print 'Deleting instance', inst.path self.conn.DeleteInstance(inst.path) except CIMError, ce: print 'Error deleting instance', inst.path print ' ', '%s %s' % (ce.args[0], ce.args[1]) for ns, cnames in self.class_names.items(): self.default_namespace = ns cnames.reverse() for cname in cnames: try: if verbose: print 'Deleting class %s:%s' % (ns, cname) self.conn.DeleteClass(cname) except CIMError, ce: print 'Error deleting class %s:%s' % (ns, cname) print ' ', '%s %s' % (ce.args[0], ce.args[1]) # TODO: do we want to do anything with qualifiers? def _errcode2string(code): d = { CIM_ERR_FAILED : 'A general error occurred', CIM_ERR_ACCESS_DENIED : 'Resource not available', CIM_ERR_INVALID_NAMESPACE : 'The target namespace does not exist', CIM_ERR_INVALID_PARAMETER : 'Parameter value(s) invalid', CIM_ERR_INVALID_CLASS : 'The specified Class does not exist', CIM_ERR_NOT_FOUND : 'Requested object could not be found', CIM_ERR_NOT_SUPPORTED : 'Operation not supported', CIM_ERR_CLASS_HAS_CHILDREN : 'Class has subclasses', CIM_ERR_CLASS_HAS_INSTANCES : 'Class has instances', CIM_ERR_INVALID_SUPERCLASS : 'Superclass does not exist', CIM_ERR_ALREADY_EXISTS : 'Object already exists', CIM_ERR_NO_SUCH_PROPERTY : 'Property does not exist', CIM_ERR_TYPE_MISMATCH : 'Value incompatible with type', CIM_ERR_QUERY_LANGUAGE_NOT_SUPPORTED : 'Query language not supported', CIM_ERR_INVALID_QUERY : 'Query not valid', CIM_ERR_METHOD_NOT_AVAILABLE : 'Extrinsic method not executed', CIM_ERR_METHOD_NOT_FOUND : 'Extrinsic method does not exist', } try: s = d[code] except KeyError: s = 'Unknown Error' return s class MOFCompiler(object): def __init__(self, handle, search_paths=[], verbose=False, log_func=_print_logger): """Initialize the compiler. Keyword arguments: handle -- A WBEMConnection or similar object. The following attributes and methods need to be present, corresponding to the the attributes and methods on pywbem.WBEMConnection having the same names: - default_namespace - EnumerateInstanceNames() - CreateClass() - GetClass() - ModifyClass() - DeleteInstance() - CreateInstance() - ModifyInstance() - DeleteQualifier() - EnumerateQualifiers() - SetQualifier() search_paths -- A list of file system paths specifying where missing schema elements should be looked for. verbose -- True if extra messages should be printed. log_func -- A callable that takes a single string argument. The default logger prints to stdout. """ self.parser = yacc.yacc(tabmodule=_tabmodule, optimize=_optimize) self.parser.search_paths = search_paths self.handle = handle self.parser.handle = handle self.lexer = lex.lex(lextab=_lextab, optimize=_optimize) self.lexer.parser = self.parser self.parser.qualcache = {handle.default_namespace:NocaseDict()} self.parser.classnames = {handle.default_namespace:[]} self.parser.mofcomp = self self.parser.verbose = verbose self.parser.log = log_func self.parser.aliases = {} def compile_string(self, mof, ns, filename=None): """Compile a string of MOF. Arguments: mof -- The string of MOF ns -- The CIM namespace Keyword arguments: filename -- The name of the file that the MOF was read from. This is used in status and error messages. """ lexer = self.lexer.clone() lexer.parser = self.parser try: oldfile = self.parser.file except AttributeError: oldfile = None self.parser.file = filename try: oldmof = self.parser.mof except AttributeError: oldmof = None self.parser.mof = mof self.parser.handle.default_namespace = ns if ns not in self.parser.qualcache: self.parser.qualcache[ns] = NocaseDict() if ns not in self.parser.classnames: self.parser.classnames[ns] = [] try: rv = self.parser.parse(mof, lexer=lexer) self.parser.file = oldfile self.parser.mof = oldmof return rv except MOFParseError, pe: self.parser.log('Syntax error:') if hasattr(pe, 'file') and hasattr(pe, 'lineno'): self.parser.log('%s:%s:' % (pe.file, pe.lineno)) if hasattr(pe, 'context'): self.parser.log('\n'.join(pe.context)) if str(pe): self.parser.log(str(pe)) raise except CIMError, ce: if hasattr(ce, 'file_line'): self.parser.log('Fatal Error: %s:%s' % (ce.file_line[0], ce.file_line[1])) else: self.parser.log('Fatal Error:') self.parser.log('%s%s' % (_errcode2string(ce.args[0]), ce.args[1] and ': '+ce.args[1] or '')) raise def compile_file(self, filename, ns): """Compile MOF from a file. Arguments: filename -- The file to read MOF from ns -- The CIM namespace """ if self.parser.verbose: self.parser.log('Compiling file ' + filename) f = open(filename, 'r') mof = f.read() f.close() return self.compile_string(mof, ns, filename=filename) def find_mof(self, classname): """Find a MOF file corresponding to a CIM class name. The search_paths provided to __init__() are searched recursively. Arguments: classname -- The name of the class to look for """ classname = classname.lower() for search in self.parser.search_paths: for root, dirs, files in os.walk(search): for file_ in files: if file_.endswith('.mof') and \ file_[:-4].lower() == classname: return root + '/' + file_ return None def rollback(self, verbose=False): self.handle.rollback(verbose=verbose) def _build(): yacc.yacc(optimize=_optimize, tabmodule=_tabmodule, outputdir=_outputdir) lex.lex(optimize=_optimize, lextab=_lextab, outputdir=_outputdir) if __name__ == '__main__': from optparse import OptionParser usage = 'usage: %prog -n [options] ...' oparser = OptionParser(usage=usage) oparser.add_option('-s', '--search', dest='search', help='Search path to find missing schema elements. This option can be present multiple times.', metavar='Path', action='append') oparser.add_option('-n', '--namespace', dest='ns', help='Specify the namespace', metavar='Namespace') oparser.add_option('-u', '--url', dest='url', help='URL to the CIM Server', metavar='URL', default='/var/run/tog-pegasus/cimxml.socket') oparser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False, help='Print more messages to stdout') oparser.add_option('-r', '--remove', action='store_true', dest='remove', default=False, help='Remove elements found in MOF, instead of create them') oparser.add_option('-l', '--username', dest='username', metavar='Username', help='Specify the username') oparser.add_option('-p', '--password', dest='password', metavar='Password', help='Specify the password') oparser.add_option('-d', '--dry-run', dest='dry_run', default=False, action='store_true', help="Don't actually modify the repository, just check mof file syntax. Connection to CIMOM is still required to check qualifiers.") (options, args) = oparser.parse_args() search = options.search if not args: oparser.error('No input files given for parsing') if options.ns is None: oparser.error('No namespace given') passwd = options.password if options.username and not passwd: passwd = getpass('Enter password for %s: ' % options.username) if options.username: conn = WBEMConnection(options.url, (options.username, passwd)) else: conn = WBEMConnection(options.url) if options.remove or options.dry_run: conn = MOFWBEMConnection(conn=conn) #conn.debug = True conn.default_namespace = options.ns if search is None: search = [] search = [os.path.abspath(x) for x in search] for fname in args: path = os.path.abspath(os.path.dirname(fname)) for spath in search: if path.startswith(spath): break else: search.append(path) # if removing, we'll be verbose later when we actually remove stuff. # We don't want MOFCompiler to be verbose, as that would be confusing. verbose = options.verbose and not options.remove mofcomp = MOFCompiler(handle=conn, search_paths=search, verbose=verbose) try: for fname in args: if fname[0] != '/': fname = os.path.curdir + '/' + fname mofcomp.compile_file(fname, options.ns) except MOFParseError, pe: sys.exit(1) except CIMError, ce: sys.exit(1) if options.remove and not options.dry_run: conn.rollback(verbose=options.verbose) pywbem-0.8.0~dev/pywbem/cim_obj.py0000644000175000017500000013773012413747174017115 0ustar bzedbzed00000000000000# # (C) Copyright 2003-2007 Hewlett-Packard Development Company, L.P. # (C) Copyright 2006-2007 Novell, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter # Martin Pool # Bart Whiteley import string, re from types import StringTypes from datetime import datetime, timedelta from pywbem import cim_xml, cim_types from pywbem.cim_types import atomic_to_cim_xml, CIMDateTime """ Representations of CIM Objects. In general we try to map CIM objects directly into Python primitives, except when that is not possible or would be ambiguous. For example, CIM Class names are simply Python strings, but a ClassPath is represented as a special Python object. These objects can also be mapped back into XML, by the toxml() method which returns a string. """ class NocaseDict(object): """Yet another implementation of a case-insensitive dictionary.""" def __init__(self, *args, **kwargs): self.data = {} # Initialise from sequence object if len(args) == 1 and type(args[0]) == list: for item in args[0]: self[item[0]] = item[1] # Initialise from mapping object if len(args) == 1 and type(args[0]) == dict: self.update(args[0]) # Initialise from NocaseDict if len(args) == 1 and isinstance(args[0], NocaseDict): self.data = args[0].data.copy() # Initialise from keyword args self.update(kwargs) # Basic accessor and settor methods def __getitem__(self, key): k = key if isinstance(key, (str, unicode)): k = key.lower() try: return self.data[k][1] except KeyError, arg: raise KeyError('Key %s not found in %s' % (key, repr(self))) def __setitem__(self, key, value): if not isinstance(key, (str, unicode)): raise KeyError('NocaseDict key %s must be string type, but is %s'%\ (key, type(key))) k = key.lower() self.data[k] = (key, value) def __delitem__(self, key): k = key if isinstance(key, (str, unicode)): k = key.lower() try: del self.data[k] except KeyError, arg: raise KeyError('Key %s not found in %s' % (key, repr(self))) def __len__(self): return len(self.data) def has_key(self, key): k = key if isinstance(key, (str, unicode)): k = key.lower() return self.data.has_key(k) def __contains__(self, key): k = key if isinstance(key, (str, unicode)): k = key.lower() return k in self.data def get(self, key, default = None): try: return self[key] except KeyError: return default def setdefault(self, key, default): if not self.has_key(key): self[key] = default return self[key] # Other accessor expressed in terms of iterators def keys(self): return list(self.iterkeys()) def values(self): return list(self.itervalues()) def items(self): return list(self.iteritems()) # Iterators def iterkeys(self): for item in self.data.iteritems(): yield item[1][0] def itervalues(self): for item in self.data.iteritems(): yield item[1][1] def iteritems(self): for item in self.data.iteritems(): yield item[1] # Support 'for' and 'in' directly def __iter__(self): return self.iterkeys() # Other stuff def __repr__(self): items = ', '.join([('%r: %r' % (key, value)) for key, value in self.items()]) return 'NocaseDict({%s})' % items def update(self, *args, **kwargs): for mapping in args: if hasattr(mapping, 'items'): for k, v in mapping.items(): self[k] = v else: for (k, v) in mapping: self[k] = v for k, v in kwargs.items(): self[k] = v def clear(self): self.data.clear() def popitem(self): pass def copy(self): result = NocaseDict() result.data = self.data.copy() return result def __eq__(self, other): for key, value in self.iteritems(): if not (key in other) or not (other[key] == value): return 0 return len(self) == len(other) def __cmp__(self, other): for key, value in self.iteritems(): if not (key in other): return -1 rv = cmp(value, other[key]) if rv != 0: return rv return len(self) - len(other) def cmpname(name1, name2): """Compare to CIM names. The comparison is done case-insensitvely, and one or both of the names may be None.""" if name1 is None and name2 is None: return 0 if name1 is None: return -1 if name2 is None: return 1 lower_name1 = name1.lower() lower_name2 = name2.lower() return cmp(lower_name1, lower_name2) class CIMClassName(object): def __init__(self, classname, host = None, namespace = None): if not isinstance(classname, StringTypes): raise TypeError('classname argument has an invalid type: %s '\ '(expected string)' % type(classname)) # TODO: There are some odd restrictions on what a CIM # classname can look like (i.e must start with a # non-underscore and only one underscore per classname). self.classname = classname self.host = host self.namespace = namespace def copy(self): return CIMClassName(self.classname, host = self.host, namespace = self.namespace) def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, CIMClassName): return 1 return (cmpname(self.classname, other.classname) or cmpname(self.host, other.host) or cmpname(self.namespace, other.namespace)) def __str__(self): s = '' if self.host is not None: s += '//%s/' % self.host if self.namespace is not None: s += '%s:' % self.namespace s += self.classname return s def __repr__(self): r = '%s(classname=%s' % (self.__class__.__name__, `self.classname`) if self.host is not None: r += ', host=%s' % `self.host` if self.namespace is not None: r += ', namespace=%s' % `self.namespace` r += ')' return r def tocimxml(self): classname = cim_xml.CLASSNAME(self.classname) if self.namespace is not None: localnsp = cim_xml.LOCALNAMESPACEPATH( [cim_xml.NAMESPACE(ns) for ns in string.split(self.namespace, '/')]) if self.host is not None: # Classname + namespace + host = CLASSPATH return cim_xml.CLASSPATH( cim_xml.NAMESPACEPATH(cim_xml.HOST(self.host), localnsp), classname) # Classname + namespace = LOCALCLASSPATH return cim_xml.LOCALCLASSPATH(localnsp, classname) # Just classname = CLASSNAME return cim_xml.CLASSNAME(self.classname) class CIMProperty(object): """A property of a CIMInstance. Property objects represent both properties on particular instances, and the property defined in a class. In the first case, the property will have a Value and in the second it will not. The property may hold an array value, in which case it is encoded in XML to PROPERTY.ARRAY containing VALUE.ARRAY.""" def __init__(self, name, value, type = None, class_origin = None, array_size = None, propagated = None, is_array = False, reference_class = None, qualifiers = {}, embedded_object = None): # Initialise members self.name = name self.value = value self.type = type self.class_origin = class_origin self.array_size = array_size self.propagated = propagated self.qualifiers = NocaseDict(qualifiers) self.is_array = is_array self.reference_class = reference_class self.embedded_object = embedded_object if isinstance(value, (datetime, timedelta)): value = CIMDateTime(value) import __builtin__ if __builtin__.type(value) == list: self.is_array = True # Determine type of value if not specified if type is None: # Can't work out what is going on if type and value are # both not set. if value is None: raise TypeError('Null property "%s" must have a type' % name) if self.is_array: # Determine type for list value if len(value) == 0: raise TypeError( 'Empty property array "%s" must have a type' % name) elif isinstance(value[0], CIMInstance): self.type = 'string' self.embedded_object = 'instance' elif isinstance(value[0], CIMClass): self.type = 'string' self.embedded_object = 'object' else: self.type = cim_types.cimtype(value[0]) elif isinstance(value, CIMInstanceName): self.type = 'reference' elif isinstance(value, CIMInstance): self.type = 'string' self.embedded_object = 'instance' elif isinstance(value, CIMClass): self.type = 'string' self.embedded_object = 'object' else: # Determine type for regular value self.type = cim_types.cimtype(value) def copy(self): return CIMProperty(self.name, self.value, type = self.type, class_origin = self.class_origin, array_size = self.array_size, propagated = self.propagated, is_array = self.is_array, reference_class = self.reference_class, qualifiers = self.qualifiers.copy()) def __repr__(self): return '%s(name=%s, type=%s, value=%s, is_array=%s)' % \ (self.__class__.__name__, `self.name`, `self.type`, `self.value`, `self.is_array`) def tocimxml(self): if self.is_array: value = self.value if value is not None: if value: if self.embedded_object is not None: value = [v.tocimxml().toxml() for v in value] value = cim_xml.VALUE_ARRAY([cim_xml.VALUE(atomic_to_cim_xml(v)) for v in value]) return cim_xml.PROPERTY_ARRAY( self.name, self.type, value, self.array_size, self.class_origin, self.propagated, qualifiers = [q.tocimxml() for q in self.qualifiers.values()], embedded_object = self.embedded_object) elif self.type == 'reference': value_reference = None if self.value is not None: value_reference = cim_xml.VALUE_REFERENCE(self.value.tocimxml()) return cim_xml.PROPERTY_REFERENCE( self.name, value_reference, reference_class = self.reference_class, class_origin = self.class_origin, propagated = self.propagated, qualifiers = [q.tocimxml() for q in self.qualifiers.values()]) else: value = self.value if value is not None: if self.embedded_object is not None: value = value.tocimxml().toxml() else: value = atomic_to_cim_xml(value) value = cim_xml.VALUE(value) return cim_xml.PROPERTY( self.name, self.type, value, class_origin = self.class_origin, propagated = self.propagated, qualifiers = [q.tocimxml() for q in self.qualifiers.values()], embedded_object = self.embedded_object) def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, self.__class__): return 1 return (cmpname(self.name, other.name) or cmp(self.value, other.value) or cmp(self.type, other.type) or cmp(self.class_origin, other.class_origin) or cmp(self.array_size, other.array_size) or cmp(self.propagated, other.propagated) or cmp(self.qualifiers, other.qualifiers) or cmp(self.is_array, other.is_array) or cmpname(self.reference_class, other.reference_class)) class CIMInstanceName(object): """Name (keys) identifying an instance. This may be treated as a dictionary to retrieve the keys.""" def __init__(self, classname, keybindings = {}, host = None, namespace = None): self.classname = classname self.keybindings = NocaseDict(keybindings) self.host = host self.namespace = namespace def copy(self): result = CIMInstanceName(self.classname) result.keybindings = self.keybindings.copy() result.host = self.host result.namespace = self.namespace return result def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, CIMInstanceName): return 1 return (cmpname(self.classname, other.classname) or cmp(self.keybindings, other.keybindings) or cmpname(self.host, other.host) or cmpname(self.namespace, other.namespace)) def __str__(self): s = '' if self.host is not None: s += '//%s/' % self.host if self.namespace is not None: s += '%s:' % self.namespace s += '%s.' % self.classname for key, value in self.keybindings.items(): s +='%s=' % key if isinstance(value, (int, long, bool, float)): s += str(value) elif isinstance(value, CIMInstanceName): s += '"%s"' % str(value).replace( '\\','\\\\').replace('"','\\"') else: s += '"%s"' % value s += ',' return s[:-1] def __repr__(self): r = '%s(classname=%s, keybindings=%s' % \ (self.__class__.__name__, `self.classname`, `self.keybindings`) if self.host is not None: r += ', host=%s' % `self.host` if self.namespace is not None: r += ', namespace=%s' % `self.namespace` r += ')' return r # A whole bunch of dictionary methods that map to the equivalent # operation on self.keybindings. def __getitem__(self, key): return self.keybindings[key] def __contains__(self, key): return key in self.keybindings def __delitem__(self, key): del self.keybindings[key] def __setitem__(self, key, value): self.keybindings[key] = value def __len__(self): return len(self.keybindings) def has_key(self, key): return self.keybindings.has_key(key) def keys(self): return self.keybindings.keys() def values(self): return self.keybindings.values() def items(self): return self.keybindings.items() def iterkeys(self): return self.keybindings.iterkeys() def itervalues(self): return self.keybindings.itervalues() def iteritems(self): return self.keybindings.iteritems() def update(self, *args, **kwargs): self.keybindings.update(*args, **kwargs) def tocimxml(self): # Generate an XML representation of the instance classname and # keybindings. if type(self.keybindings) == str: # Class with single key string property instancename_xml = cim_xml.INSTANCENAME( self.classname, cim_xml.KEYVALUE(self.keybindings, 'string')) elif isinstance(self.keybindings, (long, float, int)): # Class with single key numeric property instancename_xml = cim_xml.INSTANCENAME( self.classname, cim_xml.KEYVALUE(str(self.keybindings), 'numeric')) elif isinstance(self.keybindings, (dict, NocaseDict)): # Dictionary of keybindings # NOCASE_TODO should remove dict below. kbs = [] for kb in self.keybindings.items(): # Keybindings can be integers, booleans, strings or # value references. if hasattr(kb[1], 'tocimxml'): kbs.append(cim_xml.KEYBINDING( kb[0], cim_xml.VALUE_REFERENCE(kb[1].tocimxml()))) continue if type(kb[1]) == bool: _type = 'boolean' if kb[1]: value = 'TRUE' else: value = 'FALSE' elif isinstance(kb[1], (long, float, int)): # pywbem.cim_type.{Sint32, Real64, ... } derive from # long or float _type = 'numeric' value = str(kb[1]) elif isinstance(kb[1], basestring): _type = 'string' value = kb[1].decode('utf-8') if isinstance(kb[1], str) else kb[1] else: raise TypeError('Invalid keybinding type for keybinding '\ '%s: %s' % (kb[0], type(kb[1]))) kbs.append(cim_xml.KEYBINDING( kb[0], cim_xml.KEYVALUE(value, _type))) instancename_xml = cim_xml.INSTANCENAME(self.classname, kbs) else: # Value reference instancename_xml = cim_xml.INSTANCENAME( self.classname, cim_xml.VALUE_REFERENCE(self.keybindings.tocimxml())) # Instance name plus namespace = LOCALINSTANCEPATH if self.host is None and self.namespace is not None: return cim_xml.LOCALINSTANCEPATH( cim_xml.LOCALNAMESPACEPATH( [cim_xml.NAMESPACE(ns) for ns in string.split(self.namespace, '/')]), instancename_xml) # Instance name plus host and namespace = INSTANCEPATH if self.host is not None and self.namespace is not None: return cim_xml.INSTANCEPATH( cim_xml.NAMESPACEPATH( cim_xml.HOST(self.host), cim_xml.LOCALNAMESPACEPATH([ cim_xml.NAMESPACE(ns) for ns in string.split(self.namespace, '/')])), instancename_xml) # Just a regular INSTANCENAME return instancename_xml class CIMInstance(object): """Instance of a CIM Object. Has a classname (string), and named arrays of properties and qualifiers. The properties is indexed by name and points to CIMProperty instances.""" def __init__(self, classname, properties = {}, qualifiers = {}, path = None, property_list = None): """Create CIMInstance. bindings is a concise way to initialize property values; it is a dictionary from property name to value. This is merely a convenience and gets the same result as the properties parameter. properties is a list of full CIMProperty objects. """ self.classname = classname self.qualifiers = NocaseDict(qualifiers) self.path = path if property_list is not None: self.property_list = [x.lower() for x in property_list] else: self.property_list = None # Assign initialised property values and run through # __setitem__ to enforce CIM types for each property. self.properties = NocaseDict() [self.__setitem__(k, v) for k, v in properties.items()] def update(self, *args, **kwargs): """D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] = E[k] (if E has keys else: for (k, v) in E: D[k] = v) then: for k in F: D[k] = F[k] """ for mapping in args: if hasattr(mapping, 'items'): for k, v in mapping.items(): self[k] = v else: for (k, v) in mapping: self[k] = v for k, v in kwargs.items(): self[k] = v def update_existing(self, *args, **kwargs): """Update property values iff the property previously exists. Update D from E and F: for k in E: D[k] = E[k] (if E has keys else: for (k, v) in E: D[k] = v) then: for k in F: D[k] = F[k] Like update, but properties that are not already present in the instance are skipped. """ for mapping in args: if hasattr(mapping, 'items'): for k, v in mapping.items(): try: prop = self.properties[k] except KeyError: continue prop.value = tocimobj(prop.type, v) else: for (k, v) in mapping: try: prop = self.properties[k] except KeyError: continue prop.value = tocimobj(prop.type, v) for k, v in kwargs.items(): try: prop = self.properties[k] except KeyError: continue prop.value = tocimobj(prop.type, v) def copy(self): result = CIMInstance(self.classname) result.properties = self.properties.copy() result.qualifiers = self.qualifiers.copy() result.path = (self.path is not None and [self.path.copy()] or [None])[0] return result def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, CIMInstance): return 1 return (cmpname(self.classname, other.classname) or cmp(self.path, other.path) or cmp(self.properties, other.properties) or cmp(self.qualifiers, other.qualifiers)) def __repr__(self): # Don't show all the properties and qualifiers because they're # just too big return '%s(classname=%s, ...)' % (self.__class__.__name__, `self.classname`) # A whole bunch of dictionary methods that map to the equivalent # operation on self.properties. def __contains__(self, key): return key in self.properties def __getitem__(self, key): return self.properties[key].value def __delitem__(self, key): del self.properties[key] def __len__(self): return len(self.properties) def has_key(self, key): return self.properties.has_key(key) def keys(self): return self.properties.keys() def values(self): return [v.value for v in self.properties.values()] def items(self): return [(k, v.value) for k, v in self.properties.items()] def iterkeys(self): return self.properties.iterkeys() def itervalues(self): for k, v in self.properties.iteritems(): yield v.value def iteritems(self): for k, v in self.properties.iteritems(): yield (k, v.value) def __setitem__(self, key, value): # Don't let anyone set integer or float values. You must use # a subclass from the cim_type module. if type(value) == int or type(value) == float or type(value) == long: raise TypeError('Type of numeric value must be a CIM type but is '\ '%s' % type(value)) if self.property_list is not None and key.lower() not in \ self.property_list: if self.path is not None and key not in self.path.keybindings: return # Convert value to appropriate PyWBEM type if isinstance(value, CIMProperty): v = value else: v = CIMProperty(key, value) self.properties[key] = v if self.path is not None and key in self.path.keybindings: self.path[key] = v.value def tocimxml(self): props = [] for key, value in self.properties.items(): # Value has already been converted into a CIM object # property type (e.g for creating null property values). if isinstance(value, CIMProperty): props.append(value) continue props.append(CIMProperty(key, value)) instance_xml = cim_xml.INSTANCE( self.classname, properties = [p.tocimxml() for p in props], qualifiers = [q.tocimxml() for q in self.qualifiers.values()]) if self.path is None: return instance_xml return cim_xml.VALUE_NAMEDINSTANCE(self.path.tocimxml(), instance_xml) def tomof(self): def _prop2mof(_type, value): if value is None: val = 'NULL' elif isinstance(value, list): val = '{' for i,x in enumerate(value): if i > 0: val += ', ' val += _prop2mof(_type, x) val += '}' elif _type == 'string': val = '"' + value + '"' else: val = str(value) return val s = 'instance of %s {\n' % self.classname for p in self.properties.values(): s+= '\t%s = %s;\n' % (p.name, _prop2mof(p.type, p.value)) s+= '};\n' return s class CIMClass(object): def __init__(self, classname, properties = {}, methods = {}, superclass = None, qualifiers = {}): self.classname = classname self.properties = NocaseDict(properties) self.qualifiers = NocaseDict(qualifiers) self.methods = NocaseDict(methods) self.superclass = superclass def copy(self): result = CIMClass(self.classname) result.properties = self.properties.copy() result.methods = self.methods.copy() result.superclass = self.superclass result.qualifiers = self.qualifiers.copy() return result def __repr__(self): return "%s(%s, ...)" % (self.__class__.__name__, `self.classname`) def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, CIMClass): return 1 return (cmpname(self.classname, other.classname) or cmpname(self.superclass, other.superclass) or cmp(self.properties, other.properties) or cmp(self.qualifiers, other.qualifiers) or cmp(self.methods, other.methods)) def tocimxml(self): return cim_xml.CLASS( self.classname, properties = [p.tocimxml() for p in self.properties.values()], methods = [m.tocimxml() for m in self.methods.values()], qualifiers = [q.tocimxml() for q in self.qualifiers.values()], superclass = self.superclass) def tomof(self): def _makequalifiers(qualifiers, indent): """Return a mof fragment for a NocaseDict of qualifiers.""" if len(qualifiers) == 0: return '' return '[%s]' % ',\n '.ljust(indent+2).join([q.tomof() for q in qualifiers.values()]) # Class definition s = ' %s\n' % _makequalifiers(self.qualifiers, 4) s += 'class %s ' % self.classname # Superclass if self.superclass is not None: s += ': %s ' % self.superclass s += '{\n' # Properties for p in self.properties.values(): s += ' %s\n' % (_makequalifiers(p.qualifiers, 7)) s += ' %s %s;\n' % (p.type, p.name) # Methods for m in self.methods.values(): s += ' %s\n' % (_makequalifiers(m.qualifiers, 7)) s += ' %s\n' % m.tomof() s += '};\n' return s class CIMMethod(object): def __init__(self, methodname, return_type = None, parameters = {}, class_origin = None, propagated = False, qualifiers = {}): self.name = methodname self.return_type = return_type self.parameters = NocaseDict(parameters) self.class_origin = class_origin self.propagated = propagated self.qualifiers = NocaseDict(qualifiers) def copy(self): result = CIMMethod(self.name, return_type = self.return_type, class_origin = self.class_origin, propagated = self.propagated) result.parameters = self.parameters.copy() result.qualifiers = self.qualifiers.copy() return result def tocimxml(self): return cim_xml.METHOD( self.name, parameters = [p.tocimxml() for p in self.parameters.values()], return_type = self.return_type, class_origin = self.class_origin, propagated = self.propagated, qualifiers = [q.tocimxml() for q in self.qualifiers.values()]) def __repr__(self): return '%s(name=%s, return_type=%s...)' % \ (self.__class__.__name__, `self.name`, `self.return_type`) def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, CIMMethod): return 1 return (cmpname(self.name, other.name) or cmp(self.parameters, other.parameters) or cmp(self.qualifiers, other.qualifiers) or cmp(self.class_origin, other.class_origin) or cmp(self.propagated, other.propagated) or cmp(self.return_type, other.return_type)) def tomof(self): s = '' if self.return_type is not None: s += '%s ' % self.return_type s += '%s(%s);' % \ (self.name, string.join([p.tomof() for p in self.parameters.values()], ', ')) return s class CIMParameter(object): def __init__(self, name, type, reference_class = None, is_array = None, array_size = None, qualifiers = {}, value = None): self.name = name self.type = type self.reference_class = reference_class self.is_array = is_array self.array_size = array_size self.qualifiers = NocaseDict(qualifiers) self.value = value def copy(self): result = CIMParameter(self.name, self.type, reference_class = self.reference_class, is_array = self.is_array, array_size = self.array_size, value = self.value) result.qualifiers = self.qualifiers.copy() return result def __repr__(self): return '%s(name=%s, type=%s, is_array=%s)' % \ (self.__class__.__name__, `self.name`, `self.type`, `self.is_array`) def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, self.__class__): return 1 return (cmpname(self.name, other.name) or cmp(self.type, other.type) or cmpname(self.reference_class, other.reference_class) or cmp(self.is_array, other.is_array) or cmp(self.array_size, other.array_size) or cmp(self.qualifiers, other.qualifiers) or cmp(self.value, other.value)) def tocimxml(self): if self.type == 'reference': if self.is_array: array_size = None if self.array_size is not None: array_size = str(self.array_size) return cim_xml.PARAMETER_REFARRAY( self.name, self.reference_class, array_size, qualifiers = [q.tocimxml() for q in self.qualifiers.values()]) else: return cim_xml.PARAMETER_REFERENCE( self.name, self.reference_class, qualifiers = [q.tocimxml() for q in self.qualifiers.values()]) elif self.is_array: array_size = None if self.array_size is not None: array_size = str(self.array_size) return cim_xml.PARAMETER_ARRAY( self.name, self.type, array_size, qualifiers = [q.tocimxml() for q in self.qualifiers.values()]) else: return cim_xml.PARAMETER( self.name, self.type, qualifiers = [q.tocimxml() for q in self.qualifiers.values()]) def tomof(self): return '%s %s' % (self.type, self.name) class CIMQualifier(object): """Represents static annotations of a class, method, property, etc. Includes information such as a documentation string and whether a property is a key.""" def __init__(self, name, value, type = None, propagated = None, overridable = None, tosubclass = None, toinstance = None, translatable = None): self.name = name self.type = type self.propagated = propagated self.overridable = overridable self.tosubclass = tosubclass self.toinstance = toinstance self.translatable = translatable # Determine type of value if not specified import __builtin__ if type is None: # Can't work out what is going on if type and value are # both not set. if value is None: raise TypeError('Null qualifier "%s" must have a type' % name) if __builtin__.type(value) == list: # Determine type for list value if len(value) == 0: raise TypeError('Empty qualifier array "%s" must have a '\ 'type' % name) self.type = cim_types.cimtype(value[0]) else: # Determine type for regular value self.type = cim_types.cimtype(value) # Don't let anyone set integer or float values. You must use # a subclass from the cim_type module. if __builtin__.type(value) in (int, float, long): raise TypeError('Must use a CIM type for numeric qualifiers.') self.value = value def copy(self): return CIMQualifier(self.name, self.value, type = self.type, propagated = self.propagated, overridable = self.overridable, tosubclass = self.tosubclass, toinstance = self.toinstance, translatable = self.translatable) def __repr__(self): return "%s(%s, %s)" % \ (self.__class__.__name__, `self.name`, `self.value`) def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, CIMQualifier): return 1 return (cmpname(self.name, other.name) or cmp(self.value, other.value) or cmp(self.type, other.type) or cmp(self.propagated, other.propagated) or cmp(self.overridable, other.overridable) or cmp(self.tosubclass, other.tosubclass) or cmp(self.toinstance, other.toinstance) or cmp(self.translatable, other.translatable)) def tocimxml(self): value = None if type(self.value) == list: value = cim_xml.VALUE_ARRAY([cim_xml.VALUE(v) for v in self.value]) elif self.value is not None: value = cim_xml.VALUE(self.value) return cim_xml.QUALIFIER(self.name, self.type, value, propagated = self.propagated, overridable = self.overridable, tosubclass = self.tosubclass, toinstance = self.toinstance, translatable = self.translatable) def tomof(self): def valstr(v): if isinstance(v, basestring): return '"%s"' % v return str(v) if type(self.value) == list: return '%s {' % self.name + \ ', '.join([valstr(v) for v in self.value]) + '}' return '%s (%s)' % (self.name, valstr(self.value)) class CIMQualifierDeclaration(object): """Represents the declaration of a qualifier.""" # TODO: Scope and qualifier flavors def __init__(self, name, type, value = None, is_array = False, array_size = None, scopes = {}, overridable = None, tosubclass = None, toinstance = None, translatable = None): self.name = name self.type = type self.value = value self.is_array = is_array self.array_size = array_size self.scopes = NocaseDict(scopes) self.overridable = overridable self.tosubclass = tosubclass self.toinstance = toinstance self.translatable = translatable def copy(self): return CIMQualifierDeclaration(self.name, self.type, value=self.value, is_array=self.is_array, array_size=self.array_size, scopes=self.scopes, overridable=self.overridable, tosubclass=self.tosubclass, toinstance=self.toinstance, translatable=self.translatable) def __repr__(self): return "%s(%s)" % (self.__class__.__name__, `self.name`) def __cmp__(self, other): if self is other: return 0 elif not isinstance(other, CIMQualifierDeclaration): return 1 return (cmpname(self.name, other.name) or cmp(self.type, other.type) or cmp(self.value, other.value) or cmp(self.is_array, other.is_array) or cmp(self.array_size, other.array_size) or cmp(self.scopes, other.scopes) or cmp(self.overridable, other.overridable) or cmp(self.tosubclass, other.tosubclass) or cmp(self.toinstance, other.toinstance) or cmp(self.translatable, other.translatable)) def tocimxml(self): return cim_xml.QUALIFIER_DECLARATION(self.name, self.type, self.value, is_array = self.is_array, array_size = self.array_size, qualifier_scopes = self.scopes, overridable=self.overridable, tosubclass=self.tosubclass, toinstance=self.toinstance, translatable=self.translatable) def tomof(self): mof = 'Qualifier %s : %s' % (self.name, self.type) if self.is_array: mof+= '[' if self.array_size is not None: mof+= str(self.array_size) mof+= ']' if self.value is not None: if isinstance(self.value, list): mof+= '{' mof+= ', '.join([atomic_to_cim_xml(tocimobj(self.type, x)) \ for x in self.value]) mof+= '}' else: mof+= ' = %s' % atomic_to_cim_xml(tocimobj(self.type,self.value)) mof+= ',\n ' mof+= 'Scope(' mof+= ', '.join([x.lower() for x, y in self.scopes.items() if y]) + ')' if not self.overridable and not self.tosubclass \ and not self.toinstance and not self.translatable: mof+= ';' return mof mof+= ',\n Flavor(' mof+= self.overridable and 'EnableOverride' or 'DisableOverride' mof+= ', ' mof+= self.tosubclass and 'ToSubclass' or 'Restricted' if self.toinstance: mof+= ', ToInstance' if self.translatable: mof+= ', Translatable' mof+= ');' return mof def tocimxml(value): """Convert an arbitrary object to CIM xml. Works with cim_obj objects and builtin types.""" # Python cim_obj object if hasattr(value, 'tocimxml'): return value.tocimxml() # CIMType or builtin type if isinstance(value, (cim_types.CIMType, unicode, int)): return cim_xml.VALUE(unicode(value)) if isinstance(value, str): return cim_xml.VALUE(value.decode('utf-8')) if isinstance(value, bool): if value: return cim_xml.VALUE('TRUE') else: return cim_xml.VALUE('FALSE') # List of values if type(value) == list: return cim_xml.VALUE_ARRAY(map(tocimxml, value)) raise ValueError("Can't convert %s (%s) to CIM XML" % (value, type(value))) def tocimobj(_type, value): """Convert a CIM type and a string value into an appropriate builtin type.""" if value is None or _type is None: return None if _type != 'string' and isinstance(value, basestring) and not value: return None # Lists of values if type(value) == list: return map(lambda x: tocimobj(_type, x), value) # Boolean type if _type == 'boolean': if isinstance(value, bool): return value elif isinstance(value, basestring): if value.lower() == 'true': return True elif value.lower() == 'false': return False raise ValueError('Invalid boolean value: "%s"' % value) # String type if _type == 'string': return value # Integer types if _type == 'uint8': return cim_types.Uint8(value) if _type == 'sint8': return cim_types.Sint8(value) if _type == 'uint16': return cim_types.Uint16(value) if _type == 'sint16': return cim_types.Sint16(value) if _type == 'uint32': return cim_types.Uint32(value) if _type == 'sint32': return cim_types.Sint32(value) if _type == 'uint64': return cim_types.Uint64(value) if _type == 'sint64': return cim_types.Sint64(value) # Real types if _type == 'real32': return cim_types.Real32(value) if _type == 'real64': return cim_types.Real64(value) # Char16 if _type == 'char16': raise ValueError('CIMType char16 not handled') # Datetime if _type == 'datetime': return CIMDateTime(value) # REF def partition(s, seq): """ S.partition(sep) -> (head, sep, tail) Searches for the separator sep in S, and returns the part before it, the separator itself, and the part after it. If the separator is not found, returns S and two empty strings. """ try: return s.partition(seq) except AttributeError: try: idx = s.index(seq) except ValueError: return (s, '', '') return (s[:idx], seq, s[idx+len(seq):]) if _type == 'reference': # TODO doesn't handle double-quoting, as in refs to refs. Example: # r'ex_composedof.composer="ex_sampleClass.label1=9921,label2=\"SampleLabel\"",component="ex_sampleClass.label1=0121,label2=\"Component\""') if isinstance(value, (CIMInstanceName, CIMClassName)): return value elif isinstance(value, basestring): ns = host = None head, sep, tail = partition(value, '//') if sep and head.find('"') == -1: # we have a namespace type head, sep, tail = partition(tail, '/') host = head else: tail = head head, sep, tail = partition(tail, ':') if sep: ns = head else: tail = head head, sep, tail = partition(tail, '.') if not sep: return CIMClassName(head, host=host, namespace=ns) classname = head kb = {} while tail: head, sep, tail = partition(tail, ',') if head.count('"') == 1: # quoted string contains comma tmp, sep, tail = partition(tail,'"') head = '%s,%s' % (head, tmp) tail = partition(tail,',')[2] head = head.strip() key, sep, val = partition(head,'=') if sep: cn, s, k = partition(key, '.') if s: if cn != classname: raise ValueError('Invalid object path: "%s"' % \ value) key = k val = val.strip() if val[0] == '"' and val[-1] == '"': val = val.strip('"') else: if val.lower() in ('true','false'): val = val.lower() == 'true' elif val.isdigit(): val = int(val) else: try: val = float(val) except ValueError: try: val = CIMDateTime(val) except ValueError: raise ValueError('Invalid key binding: %s'\ % val) kb[key] = val return CIMInstanceName(classname, host=host, namespace=ns, keybindings=kb) else: raise ValueError('Invalid reference value: "%s"' % value) raise ValueError('Invalid CIM type: "%s"' % _type) def byname(nlist): """Convert a list of named objects into a map indexed by name""" return dict([(x.name, x) for x in nlist]) pywbem-0.8.0~dev/pywbem/cim_xml.py0000644000175000017500000012647612413747174017150 0ustar bzedbzed00000000000000# # (C) Copyright 2003-2006 Hewlett-Packard Development Company, L.P. # (C) Copyright 2006-2007 Novell, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter # Bart Whiteley """ Functions to create XML documens and elements conforming to the DMTF standard DSP0201, Representation of CIM in XML, v2.2. http://www.dmtf.org/standards/wbem/DSP201.html http://www.dmtf.org/standards/published_documents/DSP201.pdf Elements generated by this module should conform to version 2.2 of the DTD: http://www.dmtf.org/standards/wbem/CIM_DTD_V22.dtd There should be one class for each element described in the DTD. The constructors take builtin Python types, or other cim_xml classes where child elements are required. Every class is a subclass of the Element class and so shares the same attributes and methods, and can be used with the built-in Python XML handling routines. In particular you can call the toxml() and toprettyxml() methods to generate XML. Note that converting using toprettyxml() inserts whitespace which may corrupt the data in the XML (!!) so you should only do this when displaying to humans who can ignore it, and never for computers. XML always passes through all non-markup whitespace. """ import sys, xml.dom.minidom from xml.dom.minidom import Document, Element def Text(data): """Grr. The API for the minidom text node function has changed in Python 2.3. This function allows the code to run under older versions of the intepreter.""" if sys.version_info[0] == 2 and sys.version_info[1] >= 3: t = xml.dom.minidom.Text() t.data = data return t return xml.dom.minidom.Text(data) class CIMElement(Element): """A base class that has a few bonus helper methods.""" def setName(self, name): """Set the NAME attribute of the element.""" self.setAttribute('NAME', name) def setOptionalAttribute(self, name, value): """Set an attribute if the value parameter is not None.""" if value is not None: self.setAttribute(name, value) def appendOptionalChild(self, child): """Append a child element which can be None.""" if child is not None: self.appendChild(child) def appendChildren(self, children): """Append a list or tuple of children.""" [self.appendChild(child) for child in children] # Root element class CIM(CIMElement): """ The CIM element is the root element of every XML Document that is valid with respect to this schema. Each document takes one of two forms; it either contains a single MESSAGE element defining a CIM message (to be used in the HTTP mapping), or it contains a DECLARATION element used to declare a set of CIM objects. """ def __init__(self, data, cim_version, dtd_version): Element.__init__(self, 'CIM') self.setAttribute('CIMVERSION', cim_version) self.setAttribute('DTDVERSION', dtd_version) self.appendChild(data) # Object declaration elements class DECLARATION(CIMElement): """ The DECLARATION element defines a set of one or more declarations of CIM objects. These are partitioned into logical declaration subsets. """ def __init__(self, data): Element.__init__(self, 'DECLARATION') self.appendChildren(data) class DECLGROUP(CIMElement): """ The DECLGROUP element defines a logical set of CIM Class, Instance and Qualifier declarations. It MAY optionally include a NAMESPACEPATH or LOCALNAMESPACEPATH element which, if present, defines the common namespace in which all objects within the group are declared. """ def __init__(self, data): Element.__init__(self, 'DECLGROUP') self.appendChildren(data) class DECLGROUP_WITHNAME(CIMElement): """ The DECLGROUP.WITHNAME element defines a logical set of CIM Class, Instance and Qualifier declarations. It MAY optionally include a NAMESPACEPATH or LOCALNAMESPACEPATH element which, if present, defines the common namespace in which all objects within the group are declared. """ def __init__(self, data): Element.__init__(self, 'DECLGROUP.WITHNAME') self.appendChildren(data) class DECLGROUP_WITHPATH(CIMElement): """ The DECLGROUP.WITHPATH element defines a logical set of CIM Class and Instance declarations. Each object is declared with its own independent naming and location information. """ def __init__(self, data): Element.__init__(self, 'DECLGROUP.WITHPATH') self.appendChildren(data) class QUALIFIER_DECLARATION(CIMElement): """ The QUALIFIER.DECLARATION element defines a single CIM Qualifier declaration. """ def __init__(self, name, type, value, is_array = None, array_size = None, qualifier_scopes = {}, overridable = None, tosubclass = None, toinstance = None, translatable = None): Element.__init__(self, 'QUALIFIER.DECLARATION') self.setName(name) self.setAttribute('TYPE', type) if is_array is not None: self.setOptionalAttribute('ISARRAY', str(is_array).lower()) if array_size is not None: self.setAttribute('ARRAYSIZE', str(array_size)) if overridable is not None: self.setAttribute('OVERRIDABLE', str(overridable).lower()) if tosubclass is not None: self.setAttribute('TOSUBCLASS', str(tosubclass).lower()) if toinstance is not None: self.setAttribute('TOINSTANCE', str(toinstance).lower()) if translatable is not None: self.setAttribute('TRANSLATABLE', str(translatable).lower()) if qualifier_scopes: scope = SCOPE(qualifier_scopes) self.appendOptionalChild(scope) if value is not None: if is_array: xval = VALUE_ARRAY(value) else: xval = VALUE(value) self.appendOptionalChild(xval) class SCOPE(CIMElement): """ The SCOPE element defines the scope of a QUALIFIER.DECLARATION in the case that there are restrictions on the scope of the Qualifier declaration. """ def __init__(self, scopes={}): Element.__init__(self, 'SCOPE') if 'any' in scopes and scopes['any']: scopes = {'CLASS': True, 'ASSOCIATION': True, 'REFERENCE': True, 'PROPERTY': True, 'METHOD': True, 'PARAMETER': True, 'INDICATION': True} for k, v in scopes.items(): self.setOptionalAttribute(k, str(v).lower()) # Object value elements class VALUE(CIMElement): """ The VALUE element is used to define a single (non-array and non-reference) CIM Property value, CIM Qualifier value, or a CIM Method Parameter value. """ def __init__(self, pcdata): Element.__init__(self, 'VALUE') if pcdata is not None: self.appendChild(Text(pcdata)) class VALUE_ARRAY(CIMElement): """ The VALUE.ARRAY element is used to represent the value of a CIM Property or Qualifier that has an array type. """ def __init__(self, values): Element.__init__(self, 'VALUE.ARRAY') self.appendChildren(values) class VALUE_REFERENCE(CIMElement): """ The VALUE.REFERENCE element is used to define a single CIM reference Property value. """ def __init__(self, data): Element.__init__(self, 'VALUE.REFERENCE') self.appendChild(data) class VALUE_REFARRAY(CIMElement): """ The VALUE.REFARRAY element is used to represent the value of an array of CIM references. """ def __init__(self, data): Element.__init__(self, 'VALUE.REFARRAY') self.appendChildren(data) class VALUE_OBJECT(CIMElement): """ The VALUE.OBJECT element is used to define a value which is comprised of a single CIM Class or Instance definition. """ def __init__(self, data): Element.__init__(self, 'VALUE.OBJECT') self.appendChild(data) class VALUE_NAMEDINSTANCE(CIMElement): """ The VALUE.NAMEDINSTANCE element is used to define a value which is comprised of a single named CIM Instance definition. """ def __init__(self, instancename, instance): Element.__init__(self, 'VALUE.NAMEDINSTANCE') self.appendChild(instancename) self.appendChild(instance) class VALUE_NAMEDOBJECT(CIMElement): """ The VALUE.NAMEDOBJECT element is used to define a value which is comprised of a single named CIM Class or Instance definition. """ def __init__(self, data): Element.__init__(self, 'VALUE.NAMEDOBJECT') if type(data) == tuple or type(data) == list: self.appendChildren(data) else: self.appendChild(data) class VALUE_OBJECTWITHLOCALPATH(CIMElement): """ The VALUE.OBJECTWITHLOCALPATH element is used to define a value which is comprised of a single CIM Object (Class or Instance) definition with additional information that defines the local path to that Object. """ def __init__(self, data1, data2): Element.__init__(self, 'VALUE.OBJECTWITHLOCALPATH') self.appendChild(data1) self.appendChild(data2) class VALUE_OBJECTWITHPATH(CIMElement): """ The VALUE.OBJECTWITHPATH element is used to define a value which is comprised of a single CIM Object (Class or Instance) definition with additional information that defines the absolute path to that Object. """ def __init__(self, data1, data2): Element.__init__(self, 'VALUE.OBJECTWITHPATH') self.appendChild(data1) self.appendChild(data2) class VALUE_NULL(CIMElement): """ The VALUE.NULL element is used to represent a TABLECELL that has no assigned value. """ def __init__(self): Element.__init__(self, 'VALUE.NULL') # Object naming and location elements class NAMESPACEPATH(CIMElement): """ The NAMESPACEPATH element is used to define a Namespace Path. It consists of a HOST element and a LOCALNAMESPACE element. """ def __init__(self, host, localnamespacepath): Element.__init__(self, 'NAMESPACEPATH') self.appendChild(host) self.appendChild(localnamespacepath) class LOCALNAMESPACEPATH(CIMElement): """ The LOCALNAMESPACEPATH element is used to define a local Namespace path (one without a Host component). It consists of one or more NAMESPACE elements (one for each namespace in the path). """ def __init__(self, namespaces): Element.__init__(self, 'LOCALNAMESPACEPATH') self.appendChildren(namespaces) class HOST(CIMElement): """ The HOST element is used to define a single Host. The element content MUST specify a legal value for a hostname in accordance with the CIM specification. """ def __init__(self, pcdata): Element.__init__(self, 'HOST') self.appendChild(Text(pcdata)) class NAMESPACE(CIMElement): """ The NAMESPACE element is used to define a single Namespace component of a Namespace path. """ def __init__(self, name): Element.__init__(self, 'NAMESPACE') self.setName(name) class CLASSPATH(CIMElement): """ The CLASSPATH element defines the absolute path to a CIM Class. It is formed from a namespace path and Class name. """ def __init__(self, namespacepath, classname): Element.__init__(self, 'CLASSPATH') self.appendChild(namespacepath) self.appendChild(classname) class LOCALCLASSPATH(CIMElement): """ The LOCALCLASSPATH element defines the a local path to a CIM Class. It is formed from a local namespace path and Class name. """ def __init__(self, localnamespacepath, classname): Element.__init__(self, 'LOCALCLASSPATH') self.appendChild(localnamespacepath) self.appendChild(classname) class CLASSNAME(CIMElement): """ The CLASSNAME element defines the qualifying name of a CIM Class. """ def __init__(self, classname): Element.__init__(self, 'CLASSNAME') self.setName(classname) class INSTANCEPATH(CIMElement): """ The INSTANCEPATH element defines the absolute path to a CIM Instance. It is comprised of a Namespace path and an Instance Name (model path). """ def __init__(self, namespacepath, instancename): Element.__init__(self, 'INSTANCEPATH') self.appendChild(namespacepath) self.appendChild(instancename) class LOCALINSTANCEPATH(CIMElement): """ The LOCALINSTANCEPATH element defines the local path to a CIM Instance. It is comprised of a local Namespace path and an Instance Name (model path). """ def __init__(self, localpath, instancename): Element.__init__(self, 'LOCALINSTANCEPATH') self.appendChild(localpath) self.appendChild(instancename) class INSTANCENAME(CIMElement): """ The INSTANCENAME element defines the location of a CIM Instance within a Namespace (it is referred to in the CIM Specification as a Model Path). It is comprised of a class name and a key binding information. If the Class has a single key property, then a single KEYVALUE or VALUE.REFERENCE subelement may be used to describe the (necessarily) unique key value without a key name. Alternatively a single KEYBINDING subelement may be used instead. If the Class has more than one key property, then a KEYBINDING subelement MUST appear for each key. If there are no key-bindings specified, the instance is assumed to be a singleton instance of a keyless Class. """ def __init__(self, classname, data): Element.__init__(self, 'INSTANCENAME') self.setAttribute('CLASSNAME', classname) if data is not None: if type(data) == list: self.appendChildren(data) else: self.appendChild(data) class OBJECTPATH(CIMElement): """ The OBJECTPATH element is used to define a full path to a single CIM Object (Class or Instance). """ def __init__(self, data): Element.__init__(self, 'OBJECTPATH') self.appendChild(data) class KEYBINDING(CIMElement): """ The KEYBINDING element defines a single key property value binding. """ def __init__(self, name, data): Element.__init__(self, 'KEYBINDING') self.setName(name) self.appendChild(data) class KEYVALUE(CIMElement): """ The KEYVALUE element defines a single property key value when the key property is a non-reference type. """ def __init__(self, data, value_type = None, cim_type = None): Element.__init__(self, 'KEYVALUE') if value_type is None: self.setAttribute('VALUETYPE', 'string') else: self.setAttribute('VALUETYPE', value_type) self.setOptionalAttribute('TYPE', cim_type) if data != None: self.appendChild(Text(data)) # Object definition elements class CLASS(CIMElement): """ The CLASS element defines a single CIM Class. """ def __init__(self, classname, properties = [], methods = [], qualifiers = [], superclass = None): Element.__init__(self, 'CLASS') self.setName(classname) self.setOptionalAttribute('SUPERCLASS', superclass) self.appendChildren(qualifiers + properties + methods) class INSTANCE(CIMElement): """ The INSTANCE element defines a single CIM Instance of a CIM Class. """ def __init__(self, classname, properties = [], qualifiers = [], xml_lang = None): Element.__init__(self, 'INSTANCE') self.setAttribute('CLASSNAME', classname) self.setOptionalAttribute('xml:lang', xml_lang) self.appendChildren(qualifiers + properties) class QUALIFIER(CIMElement): """ The QUALIFIER element defines a single CIM Qualifier. If the Qualifier has a non-array type, it contains a single VALUE element representing the value of the Qualifier. If the Qualifier has an array type, it contains a single VALUE.ARRAY element to represent the value. If the Qualifier has no assigned value then the VALUE element MUST be absent. """ def __init__(self, name, type, value = None, propagated = None, overridable = None, tosubclass = None, toinstance = None, translatable = None, xml_lang = None): Element.__init__(self, 'QUALIFIER') self.setName(name) self.setAttribute('TYPE', type) if propagated is not None: self.setAttribute('PROPAGATED', str(propagated).lower()) if overridable is not None: self.setAttribute('OVERRIDABLE', str(overridable).lower()) if tosubclass is not None: self.setAttribute('TOSUBCLASS', str(tosubclass).lower()) if toinstance is not None: self.setAttribute('TOINSTANCE', str(toinstance).lower()) if translatable is not None: self.setAttribute('TRANSLATABLE', str(translatable).lower()) self.setOptionalAttribute('xml:lang', xml_lang) self.appendOptionalChild(value) class PROPERTY(CIMElement): """ The PROPERTY element defines a single (non-array) CIM Property that is not a reference. It contains a single VALUE element representing the value of the Property. If the Property has no assigned value then the VALUE element MUST be absent. CIM Reference Properties are described using the PROPERTY.REFERENCE element. """ def __init__(self, name, type, value = None, class_origin = None, propagated = None, qualifiers = [], xml_lang = None, embedded_object = None): Element.__init__(self, 'PROPERTY') self.setName(name) self.setAttribute('TYPE', type) self.setOptionalAttribute('CLASSORIGIN', class_origin) if propagated is not None: self.setAttribute('PROPAGATED', str(propagated).lower()) self.setOptionalAttribute('xml:lang', xml_lang) self.setOptionalAttribute('EmbeddedObject', embedded_object) self.appendChildren(qualifiers) self.appendOptionalChild(value) class PROPERTY_ARRAY(CIMElement): """ The PROPERTY.ARRAY element defines a single CIM Property with an array type. It contains a single VALUE.ARRAY element representing the value of the Property. If the Property has no assigned value then the VALUE.ARRAY element MUST be absent. There is no element to model a Property that contains an array of references as this is not a valid Property type according to CIM. """ def __init__(self, name, type, value_array = None, array_size = None, class_origin = None, propagated = None, qualifiers = [], xml_lang = None, embedded_object = None): Element.__init__(self, 'PROPERTY.ARRAY') self.setName(name) self.setAttribute('TYPE', type) if array_size is not None: self.setAttribute('ARRAYSIZE', str(array_size)) self.setOptionalAttribute('CLASSORIGIN', class_origin) self.setOptionalAttribute('EmbeddedObject', embedded_object) if propagated is not None: self.setAttribute('PROPAGATED', str(propagated).lower()) self.setOptionalAttribute('xml:lang', xml_lang) self.appendChildren(qualifiers) self.appendOptionalChild(value_array) class PROPERTY_REFERENCE(CIMElement): """ The PROPERTY.REFERENCE element models a single CIM Property with reference semantics. In future the features of XML Linking may be used to identify linking elements within the XML Document; as XML Linking is currently only at Working Draft status no explicit dependencies have been made at this point. """ def __init__(self, name, value_reference = None, reference_class = None, class_origin = None, propagated = None, qualifiers = []): Element.__init__(self, 'PROPERTY.REFERENCE') self.setName(name) self.setOptionalAttribute('REFERENCECLASS', reference_class) self.setOptionalAttribute('CLASSORIGIN', class_origin) if propagated is not None: self.setAttribute('PROPAGATED', str(propagated).lower()); self.appendChildren(qualifiers) self.appendOptionalChild(value_reference) class METHOD(CIMElement): """ The METHOD element defines a single CIM Method. It may have Qualifiers, and zero or more parameters. The order of the PARAMETER, PARAMETER.REFERENCE, PARAMETER.ARRAY and PARAMETER.REFARRAY subelements is not significant. """ def __init__(self, name, parameters = [], return_type = None, class_origin = None, propagated = None, qualifiers = []): Element.__init__(self, 'METHOD') self.setName(name) self.setOptionalAttribute('TYPE', return_type) self.setOptionalAttribute('CLASSORIGIN', class_origin) if propagated is not None: self.setAttribute('PROPAGATED', str(propagated).lower()) self.appendChildren(qualifiers + parameters) class PARAMETER(CIMElement): """ The PARAMETER element defines a single (non-array, non-reference) Parameter to a CIM Method. The parameter MAY have zero or more Qualifiers. """ def __init__(self, name, type, qualifiers = []): Element.__init__(self, 'PARAMETER') self.setName(name) self.setAttribute('TYPE', type) self.appendChildren(qualifiers) class PARAMETER_REFERENCE(CIMElement): """ The PARAMETER.REFERENCE element defines a single reference Parameter to a CIM Method. The parameter MAY have zero or more Qualifiers. """ def __init__(self, name, reference_class = None, qualifiers = []): Element.__init__(self, 'PARAMETER.REFERENCE') self.setName(name) self.setOptionalAttribute('REFERENCECLASS', reference_class) self.appendChildren(qualifiers) class PARAMETER_ARRAY(CIMElement): """ The PARAMETER.ARRAY element defines a single Parameter to a CIM Method that has an array type. The parameter MAY have zero or more Qualifiers. """ def __init__(self, name, type, array_size = None, qualifiers = []): Element.__init__(self, 'PARAMETER.ARRAY') self.setName(name) self.setAttribute('TYPE', type) if array_size is not None: self.setAttribute('ARRAYSIZE', str(array_size)) self.appendChildren(qualifiers) class PARAMETER_REFARRAY(CIMElement): """ The PARAMETER.REFARRAY element defines a single Parameter to a CIM Method that has an array of references type. The parameter MAY have zero or more Qualifiers. """ def __init__(self, name, reference_class = None, array_size = None, qualifiers = []): Element.__init__(self, 'PARAMETER.REFARRAY') self.setName(name) self.setOptionalAttribute('REFERENCECLASS', reference_class) if array_size is not None: self.setAttribute('ARRAYSIZE', str(array_size)) self.appendChildren(qualifiers) class TABLECELL_DECLARATION(CIMElement): """ The TABLECELL.DECLARATION element describes a TABLECELL that is not a reference or an array of references. """ class TABLECELL_REFERENCE(CIMElement): """ The TABLECELL.REFERENCE element defines a TABLECELL that contains reference or reference array values. """ class TABLEROW_DECLARATION(CIMElement): """ The TABLEROW.DECLARATION element contains a definition for each TABLECELL in the TABLEROW. """ class TABLE(CIMElement): """ The TABLE element defines the result of a CIM Query. A TABLE element consists of a TABLEROW.DECLARATION followed by 0 or more rows. """ class TABLEROW(CIMElement): """ The TABLEROW element defines the values for a single row of a table. A value for each cell of the row MUST be specified. If a value has no assigned value, the VALUE.NULL element MUST be used. """ # Message elements class MESSAGE(CIMElement): """ The MESSAGE element models a single CIM message. This element is used as the basis for CIM Operation Messages and CIM Export Messages. """ def __init__(self, data, message_id, protocol_version): Element.__init__(self, 'MESSAGE') self.setAttribute('ID', message_id) self.setAttribute('PROTOCOLVERSION', protocol_version) self.appendChild(data) class MULTIREQ(CIMElement): """ The MULTIREQ element defines a Multiple CIM Operation request. It contains two or more subelements defining the SIMPLEREQ elements that make up this multiple request. """ def __init__(self, data): Element.__init__(self, 'MULTIREQ') self.appendChildren(data) class MULTIEXPREQ(CIMElement): """ The MULTIEXPREQ element defines a Multiple CIM Export request. It contains two or more subelements defining the SIMPLEEXPREQ elements that make up this multiple request. """ def __init__(self, data): Element.__init__(self, 'MULTIEXPREQ') self.appendChildren(data) class SIMPLEREQ(CIMElement): """ The SIMPLEREQ element defines a Simple CIM Operation request. It contains either a METHODCALL (extrinsic method) element or an IMETHODCALL (intrinsic method) element. """ def __init__(self, data): Element.__init__(self, 'SIMPLEREQ') self.appendChild(data) class SIMPLEEXPREQ(CIMElement): """ The SIMPLEEXPREQ element defines a Simple CIM Export request. It contains an EXPMETHODCALL (export method). """ def __init__(self, data): Element.__init__(self, 'SIMPLEEXPREQ') self.appendChild(data) class IMETHODCALL(CIMElement): """ The IMETHODCALL element defines a single intrinsic method invocation. It specifies the target local namespace, followed by zero or more IPARAMVALUE subelements as the parameter values to be passed to the method. If the RESPONSEDESTINATION element is specified, the intrinsic method call MUST be interpreted as an asynchronous method call. """ def __init__(self, name, localnamespacepath, iparamvalues = [], responsedestination = None): Element.__init__(self, 'IMETHODCALL') self.setName(name) self.appendChild(localnamespacepath) self.appendChildren(iparamvalues) self.appendOptionalChild(responsedestination) class METHODCALL(CIMElement): """ The METHODCALL element defines a single method invocation on a Class or Instance. It specifies the local path of the target Class or Instance, followed by zero or more PARAMVALUE subelements as the parameter values to be passed to the method. If the RESPONSEDESTINATION element is specified, the method call MUST be interpreted as an asynchronous method call. """ def __init__(self, name, localpath, paramvalues = [], responsedestination = None): Element.__init__(self, 'METHODCALL') self.setName(name) self.appendChild(localpath) self.appendChildren(paramvalues) self.appendOptionalChild(responsedestination) class EXPMETHODCALL(CIMElement): """ The EXPMETHODCALL element defines a single export method invocation. It specifies zero or more subelements as the parameter values to be passed to the method. """ def __init__(self, name, params = []): Element.__init__(self, 'EXPMETHODCALL') self.setName(name) self.appendChildren(params) class PARAMVALUE(CIMElement): """ The PARAMVALUE element defines a single extrinsic method named parameter value. If no subelement is present this indicates that no value has been supplied for this parameter. """ def __init__(self, name, data = None, paramtype = None, embedded_object = None): Element.__init__(self, 'PARAMVALUE') self.setName(name) self.setOptionalAttribute('PARAMTYPE', paramtype) self.setOptionalAttribute('EmbeddedObject', embedded_object) self.appendOptionalChild(data) class IPARAMVALUE(CIMElement): """ The IPARAMVALUE element defines a single intrinsic method named parameter value. If no subelement is present this indicates that no value has been supplied for this parameter. """ def __init__(self, name, data = None): Element.__init__(self, 'IPARAMVALUE') self.setName(name) self.appendOptionalChild(data) class EXPPARAMVALUE(CIMElement): """ The EXPPARAMVALUE element defines a single export method named parameter value. If no subelement is present this indicates that no value has been supplied for this parameter. """ def __init__(self, name, data = None, param_type = None): Element.__init__(self, 'EXPPARAMVALUE') self.setName(name) self.setOptionalAttribute('PARAMTYPE', param_type) self.appendOptionalChild(data) class MULTIRSP(CIMElement): """ The MULTIRSP element defines a Multiple CIM Operation response. It contains two or more subelements defining the SIMPLERSP elements that make up this multiple response. """ def __init__(self, data): Element.__init__(self, 'MULTIRSP') self.appendChildren(data) class MULTIEXPRSP(CIMElement): """ The MULTIEXPRSP element defines a Multiple CIM Export response. It contains two or more subelements defining the SIMPLEEXPRSP elements that make up this multiple response. """ def __init__(self, data): Element.__init__(self, 'MULTIEXPRSP') self.appendChildren(data) class SIMPLERSP(CIMElement): """ The SIMPLERSP element defines a Simple CIM Operation response. It contains either a METHODRESPONSE (for extrinsic methods), IMETHODRESPONSE (for intrinsic methods) or a SIMPLEREQACK subelement. """ def __init__(self, data): Element.__init__(self, 'SIMPLERSP') self.appendChild(data) class SIMPLEEXPRSP(CIMElement): """ The SIMPLEEXPRSP element defines a Simple CIM Export response. It contains either a EXPMETHODRESPONSE (for export methods) subelement. """ def __init__(self, data): Element.__init__(self, 'SIMPLEEXPRSP') self.appendChild(data) class METHODRESPONSE(CIMElement): """ The METHODRESPONSE defines the response to a single CIM extrinsic method invocation. It contains either an ERROR subelement (to report a fundamental error which prevented the method from executing), or a combination of an optional return value and zero or more out parameter values. """ def __init__(self, name, data = None): Element.__init__(self, 'METHODRESPONSE') self.setName(name) if data is not None: if type(data) == tuple or type(data) == list: self.appendChildren(data) else: self.appendChild(data) class EXPMETHODRESPONSE(CIMElement): """ The EXPMETHODRESPONSE defines the response to a single export method invocation. It contains either an ERROR subelement (to report a fundamental error which prevented the method from executing), or an optional return value. """ def __init__(self, name, data = None): Element.__init__(self, 'EXPMETHODRESPONSE') self.setName(name) self.appendOptionalChild(data) class IMETHODRESPONSE(CIMElement): """ The IMETHODRESPONSE defines the response to a single intrinsic CIM method invocation. It contains either an ERROR subelement (to report a fundamental error which prevented the method from executing), or an optional return value. """ def __init__(self, name, data = None): Element.__init__(self, 'IMETHODRESPONSE') self.setName(name) self.appendOptionalChild(data) class ERROR(CIMElement): """ The ERROR element is used to define a fundamental error which prevented a method from executing normally. It consists of a status code, an optional description and zero or more instances containing detailed information about the error. """ def __init__(self, code, description = None, instances = []): Element.__init__(self, 'ERROR') self.setAttribute('CODE', code) self.setOptionalAttribute('DESCRIPTION', description) self.appendChildren(instances) class RETURNVALUE(CIMElement): """ The RETURNVALUE element specifies the value returned from an extrinsic method call. """ def __init__(self, data, param_type = None): Element.__init__(self, 'RETURNVALUE') self.setOptionalAttribute('PARAMTYPE', param_type) self.appendChild(data) class IRETURNVALUE(CIMElement): """ The IRETURNVALUE element specifies the value returned from an intrinsic method call. """ def __init__(self, data): Element.__init__(self, 'IRETURNVALUE') self.appendOptionalChild(data) class RESPONSEDESTINATION(CIMElement): """ The RESPONSEDESTINATION element contains an instance that describes the desired destination for the response. """ def __init__(self, data): Element.__init__(self, 'RESPONSEDESTINATON') self.appendChild(data); class SIMPLEREQACK(CIMElement): """ The SIMPLEREQACK defines the acknowledgement response to a Simple CIM Operation asynchronous request. The ERROR subelement is used to report a fundamental error which prevented the asynchronous request from being initiated. """ def __init__(self, instanceid, data): Element.__init__(self, 'SIMPLEREQACK') self.setOptionalAttribute('INSTANCEID', instanceid) self.appendOptionalChild(data) pywbem-0.8.0~dev/pywbem/cimxml_parse.py0000644000175000017500000006652112413747174020175 0ustar bzedbzed00000000000000# # (C) Copyright 2006, 2007 Hewlett-Packard Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter from xml.dom.pulldom import * from pywbem import * class ParseError(Exception): """This exception is raised when there is a validation error detected by the parser.""" pass # # Helper functions # def get_required_attribute(node, attr): """Return an attribute by name. Throw an exception if not present.""" if not node.hasAttribute(attr): raise ParseError( 'Expecting %s attribute in element %s' % (attr, node.tagName)) return node.getAttribute(attr) def get_attribute(node, attr): """Return an attribute by name, or None if not present.""" if node.hasAttribute(attr): return node.getAttribute(attr) return None def get_end_event(parser, tagName): """Check that the next event is the end of a particular tag.""" (event, node) = parser.next() if event != END_ELEMENT or node.tagName != tagName: raise ParseError( 'Expecting %s end tag, got %s %s' % (tagName, event, node.tagName)) def is_start(event, node, tagName): """Return true if (event, node) is a start event for tagname.""" return event == START_ELEMENT and node.tagName == tagName def is_end(event, node, tagName): """Return true if (event, node) is an end event for tagname.""" return event == END_ELEMENT and node.tagName == tagName # # # # # # # # # # # # # # # # # # # # def parse_value(parser, event, node): value = '' (next_event, next_node) = parser.next() if next_event == CHARACTERS: value = next_node.nodeValue (next_event, next_node) = parser.next() if not is_end(next_event, next_node, 'VALUE'): raise ParseError('Expecting end VALUE') return value # def parse_value_array(parser, event, node): value_array = [] (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'VALUE'): value_array.append(parse_value(parser, next_event, next_node)) while 1: (next_event, next_node) = parser.next() if is_end(next_event, next_node, 'VALUE.ARRAY'): break if is_start(next_event, next_node, 'VALUE'): value_array.append(parse_value(parser, next_event, next_node)) else: raise ParseError('Expecting VALUE element') return value_array # def parse_value_reference(parser, event, node): (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'CLASSPATH'): result = parse_classpath(parser, next_event, next_node) elif is_start(next_event, next_node, 'LOCALCLASSPATH'): result = parse_localclasspath(parser, next_event, next_node) elif is_start(next_event, next_node, 'CLASSNAME'): result = parse_classname(parser, next_event, next_node) elif is_start(next_event, next_node, 'INSTANCEPATH'): result = parse_instancepath(parser, next_event, next_node) elif is_start(next_event, next_node, 'LOCALINSTANCEPATH'): result = parse_localinstancepath(parser, next_event, next_node) elif is_start(next_event, next_node, 'INSTANCENAME'): result = parse_instancename(parser, next_event, next_node) else: raise ParseError('Expecting (CLASSPATH | LOCALCLASSPATH | CLASSNAME ' '| INSTANCEPATH | LOCALINSTANCEPATH | INSTANCENAME)') get_end_event(parser, 'VALUE.REFERENCE') return result # # # # # # # # # # # def parse_namespacepath(parser, event, node): (next_event, next_node) = parser.next() if not is_start(next_event, next_node, 'HOST'): raise ParseError('Expecting HOST') host = parse_host(parser, next_event, next_node) (next_event, next_node) = parser.next() if not is_start(next_event, next_node, 'LOCALNAMESPACEPATH'): raise ParseError('Expecting LOCALNAMESPACEPATH') namespacepath = parse_localnamespacepath(parser, next_event, next_node) (next_event, next_node) = parser.next() if not is_end(next_event, next_node, 'NAMESPACEPATH'): raise ParseError('Expecting end NAMESPACEPATH') return (host, namespacepath) # def parse_localnamespacepath(parser, event, node): (next_event, next_node) = parser.next() namespaces = [] if not is_start(next_event, next_node, 'NAMESPACE'): print next_event, next_node raise ParseError('Expecting NAMESPACE') namespaces.append(parse_namespace(parser, next_event, next_node)) while 1: (next_event, next_node) = parser.next() if is_end(next_event, next_node, 'LOCALNAMESPACEPATH'): break if is_start(next_event, next_node, 'NAMESPACE'): namespaces.append(parse_namespace(parser, next_event, next_node)) else: raise ParseError('Expecting NAMESPACE') return string.join(namespaces, '/') # def parse_host(parser, event, node): host = '' (next_event, next_node) = parser.next() if next_event == CHARACTERS: host = next_node.nodeValue (next_event, next_node) = parser.next() if not is_end(next_event, next_node, 'HOST'): raise ParseError('Expecting end HOST') return host # # def parse_namespace(parser, event, node): name = get_required_attribute(node, 'NAME') (next_event, next_node) = parser.next() if not is_end(next_event, next_node, 'NAMESPACE'): raise ParseError('Expecting end NAMESPACE') return name # # # # # def parse_instancepath(parser, event, node): (next_event, next_node) = parser.next() if not is_start(next_event, next_node, 'NAMESPACEPATH'): raise ParseError('Expecting NAMESPACEPATH') host, namespacepath = parse_namespacepath(parser, next_event, next_node) (next_event, next_node) = parser.next() if not is_start(next_event, next_node, 'INSTANCENAME'): print next_event, next_node raise ParseError('Expecting INSTANCENAME') instancename = parse_instancename(parser, next_event, next_node) instancename.host = host instancename.namespace = namespacepath return instancename # def parse_localinstancepath(parser, event, node): (next_event, next_node) = parser.next() if not is_start(next_event, next_node, 'LOCALNAMESPACEPATH'): raise ParseError('Expecting LOCALNAMESPACEPATH') namespacepath = parse_localnamespacepath(parser, next_event, next_node) (next_event, next_node) = parser.next() if not is_start(next_event, next_node, 'INSTANCENAME'): raise ParseError('Expecting INSTANCENAME') instancename = parse_instancename(parser, next_event, next_node) instancename.namespace = namespacepath return instancename # # def parse_instancename(parser, event, node): classname = get_required_attribute(node, 'CLASSNAME') keybindings = [] (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'KEYBINDING'): keybindings.append(parse_keybinding(parser, next_event, next_node)) while 1: (next_event, next_node) = parser.next() if is_end(next_event, next_node, 'INSTANCENAME'): break if is_start(next_event, next_node, 'KEYBINDING'): keybindings.append( parse_keybinding(parser, next_event, next_node)) else: raise ParseError('Expecting KEYBINDING element') if is_end(next_event, next_node, 'INSTANCENAME'): pass elif is_start(next_event, next_node, 'KEYVALUE'): keybindings.append(('', parse_keyvalue(parser, next_event, next_node))) elif is_start(next_event, next_node, 'VALUE.REFERENCE'): keybindings.append( parse_value_reference(parser, next_event, next_node)) else: raise ParseError( 'Expecting KEYBINDING* | KEYVALUE? | VALUE.REFERENCE') return CIMInstanceName(classname, keybindings) # # # def parse_keybinding(parser, event, node): name = get_required_attribute(node, 'NAME') (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'KEYVALUE'): keyvalue = parse_keyvalue(parser, next_event, next_node) result = (name, keyvalue) elif is_start(next_event, next_node, 'VALUE.REFERENCE'): value_reference = parse_value_reference(parser, next_event, next_node) result = (name, value_reference) else: raise ParseError('Expecting KEYVALUE or VALUE.REFERENCE element') get_end_event(parser, 'KEYBINDING') return result # # def parse_keyvalue(parser, event, node): valuetype = get_required_attribute(node, 'VALUETYPE') type = get_attribute(node, 'TYPE') (next_event, next_node) = parser.next() if next_event != CHARACTERS: raise ParseError('Expecting character data') value = next_node.nodeValue if valuetype == 'string': pass elif valuetype == 'boolean': # CIM-XML says "These values MUST be treated as # case-insensitive" (even though the XML definition # requires them to be lowercase.) p = value.strip().lower() if p == 'true': value = True elif p == 'false': value = False else: raise ParseError('invalid boolean value "%s"' % `p`) elif valuetype == 'numeric': try: # XXX: Use TYPE attribute to create named CIM type. # if attrs(tt).has_key('TYPE'): # return cim_obj.tocimobj(attrs(tt)['TYPE'], p.strip()) # XXX: Would like to use long() here, but that tends to cause # trouble when it's written back out as '2L' value = int(value.strip(), 0) except ValueError: raise ParseError( 'invalid numeric value "%s"' % value) else: raise ParseError('Invalid VALUETYPE') get_end_event(parser, 'KEYVALUE') return value # # # # # # # def parse_instance(parser, event, node): classname = get_required_attribute(node, 'CLASSNAME') properties = [] qualifiers = [] (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'QUALIFIER'): qualifiers.append(parse_qualifier(parser, next_event, next_node)) while 1: (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'PROPERTY') or \ is_start(next_event, next_node, 'PROPERTY.ARRAY') or \ is_start(next_event, next_node, 'PROPERTY.REFERENCE') or \ is_end(next_event, next_node, 'INSTANCE'): break if is_start(next_event, next_node, 'QUALIFIER'): qualifiers.append( parse_qualifier(parser, next_event, next_node)) else: raise ParseError('Expecting QUALIFIER') while 1: if is_end(next_event, next_node, 'INSTANCE'): break if is_start(next_event, next_node, 'PROPERTY'): properties.append(parse_property(parser, next_event, next_node)) elif is_start(next_event, next_node, 'PROPERTY.ARRAY'): properties.append( parse_property_array(parser, next_event, next_node)) elif is_start(next_event, next_node, 'PROPERTY.REFERENCE'): properties.append( parse_property_reference(parser, next_event, next_node)) else: raise ParseError( 'Expecting (PROPERTY | PROPERTY.ARRAY | PROPERTY.REFERENCE)') (next_event, next_node) = parser.next() if not is_end(next_event, next_node, 'INSTANCE'): raise ParseError('Expecting end INSTANCE') return CIMInstance(classname, properties = dict([(x.name, x) for x in properties]), qualifiers = dict([(x.name, x) for x in qualifiers])) # # def parse_qualifier(parser, event, node): name = get_required_attribute(node, 'NAME') type = get_required_attribute(node, 'TYPE') propagated = get_attribute(node, 'PROPAGATED') (next_event, next_node) = parser.next() if is_end(next_event, next_node, 'QUALIFIER'): return CIMQualifier(name, None, type = type) if is_start(next_event, next_node, 'VALUE'): value = parse_value(parser, next_event, next_node) elif is_start(next_event, next_node, 'VALUE.ARRAY'): value = parse_value_array(parser, next_event, next_node) else: raise ParseError('Expecting (VALUE | VALUE.ARRAY)') result = CIMQualifier(name, tocimobj(type, value)) get_end_event(parser, 'QUALIFIER') return result # # def parse_property(parser, event, node): name = get_required_attribute(node, 'NAME') type = get_required_attribute(node, 'TYPE') class_origin = get_attribute(node, 'CLASSORIGIN') propagated = get_attribute(node, 'PROPAGATED') qualifiers = [] value = None (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'QUALIFIER'): qualifiers.append(parse_qualifier(parser, next_event, next_node)) while 1: (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'VALUE'): break if is_start(next_event, next_node, 'QUALIFIER'): qualifiers.append( parse_qualifier(parser, next_event, next_node)) else: raise ParseError('Expecting QUALIFIER') if is_start(next_event, next_node, 'VALUE'): value = parse_value(parser, next_event, next_node) (next_event, next_node) = parser.next() if not is_end(next_event, next_node, 'PROPERTY'): raise ParseError('Expecting end PROPERTY') return CIMProperty(name, tocimobj(type, value), type = type, class_origin = class_origin, propagated = propagated, qualifiers = dict([(x.name, x) for x in qualifiers])) # # def parse_property_array(parser, event, node): name = get_required_attribute(node, 'NAME') type = get_required_attribute(node, 'TYPE') array_size = get_attribute(node, 'ARRAYSIZE') class_origin = get_attribute(node, 'CLASSORIGIN') propagated = get_attribute(node, 'PROPAGATED') qualifiers = [] value = None (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'QUALIFIER'): qualifiers.append(parse_qualifier(parser, next_event, next_node)) while 1: (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'VALUE.ARRAY'): break if is_start(next_event, next_node, 'QUALIFIER'): qualifiers.append( parse_qualifier(parser, next_event, next_node)) else: raise ParseError('Expecting QUALIFIER') if is_start(next_event, next_node, 'VALUE.ARRAY'): value = parse_value_array(parser, next_event, next_node) (next_event, next_node) = parser.next() if not is_end(next_event, next_node, 'PROPERTY.ARRAY'): raise ParseError('Expecting end PROPERTY.ARRAY') return CIMProperty(name, tocimobj(type, value), type = type, class_origin = class_origin, propagated = propagated, is_array = True, qualifiers = dict([(x.name, x) for x in qualifiers])) # # def parse_property_reference(parser, event, node): name = get_required_attribute(node, 'NAME') class_origin = get_attribute(node, 'CLASSORIGIN') propagated = get_attribute(node, 'PROPAGATED') qualifiers = [] value = None (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'QUALIFIER'): qualifiers.append(parse_qualifier(parser, next_event, next_node)) while 1: (next_event, next_node) = parser.next() if is_start(next_event, next_node, 'VALUE.REFERENCE'): break if is_start(next_event, next_node, 'QUALIFIER'): qualifiers.append( parse_qualifier(parser, next_event, next_node)) else: raise ParseError('Expecting QUALIFIER') if is_start(next_event, next_node, 'VALUE.REFERENCE'): value = parse_value_reference(parser, next_event, next_node) (next_event, next_node) = parser.next() if not is_end(next_event, next_node, 'PROPERTY.REFERENCE'): raise ParseError('Expecting end PROPERTY.REFERENCE') return CIMProperty(name, value, class_origin = class_origin, propagated = propagated, type = 'reference', qualifiers = dict([(x.name, x) for x in qualifiers])) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def make_parser(stream_or_string): """Create a xml.dom.pulldom parser.""" if type(stream_or_string) == str or type(stream_or_string) == unicode: # XXX: the pulldom.parseString() function doesn't seem to # like operating on unicode strings! return parseString(str(stream_or_string)) else: return parse(stream_or_string) def parse_any(stream_or_string): """Parse any XML string or stream.""" parser = make_parser(stream_or_string) (event, node) = parser.next() if event != START_DOCUMENT: raise ParseError('Expecting document start') (event, node) = parser.next() if event != START_ELEMENT: raise ParseError('Expecting element start') fn_name = 'parse_%s' % node.tagName.lower().replace('.', '_') fn = globals().get(fn_name) if fn is None: raise ParseError('No parser for element %s' % node.tagName) return fn(parser, event, node) # Test harness if __name__ == '__main__': import sys print parse_any(sys.stdin) pywbem-0.8.0~dev/pywbem/lex.py0000644000175000017500000011612712413747174016300 0ustar bzedbzed00000000000000# ----------------------------------------------------------------------------- # ply: lex.py # # Author: David M. Beazley (dave@dabeaz.com) # # Copyright (C) 2001-2009, David M. Beazley # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # See the file COPYING for a complete copy of the LGPL. # ----------------------------------------------------------------------------- __version__ = "3.0" __tabversion__ = "3.0" # Version of table file used import re, sys, types, copy, os # This tuple contains known string types try: # Python 2.6 StringTypes = (types.StringType, types.UnicodeType) except AttributeError: # Python 3.0 StringTypes = (str, bytes) # Extract the code attribute of a function. Different implementations # are for Python 2/3 compatibility. if sys.version_info[0] < 3: def func_code(f): return f.func_code else: def func_code(f): return f.__code__ # This regular expression is used to match valid token names _is_identifier = re.compile(r'^[a-zA-Z0-9_]+$') # Exception thrown when invalid token encountered and no default error # handler is defined. class LexError(Exception): def __init__(self,message,s): self.args = (message,) self.text = s # Token class. This class is used to represent the tokens produced. class LexToken(object): def __str__(self): return "LexToken(%s,%r,%d,%d)" % (self.type,self.value,self.lineno,self.lexpos) def __repr__(self): return str(self) # This object is a stand-in for a logging object created by the # logging module. class PlyLogger(object): def __init__(self,f): self.f = f def critical(self,msg,*args,**kwargs): self.f.write((msg % args) + "\n") def warning(self,msg,*args,**kwargs): self.f.write("WARNING: "+ (msg % args) + "\n") def error(self,msg,*args,**kwargs): self.f.write("ERROR: " + (msg % args) + "\n") info = critical debug = critical # Null logger is used when no output is generated. Does nothing. class NullLogger(object): def __getattribute__(self,name): return self def __call__(self,*args,**kwargs): return self # ----------------------------------------------------------------------------- # === Lexing Engine === # # The following Lexer class implements the lexer runtime. There are only # a few public methods and attributes: # # input() - Store a new string in the lexer # token() - Get the next token # clone() - Clone the lexer # # lineno - Current line number # lexpos - Current position in the input string # ----------------------------------------------------------------------------- class Lexer: def __init__(self): self.lexre = None # Master regular expression. This is a list of # tuples (re,findex) where re is a compiled # regular expression and findex is a list # mapping regex group numbers to rules self.lexretext = None # Current regular expression strings self.lexstatere = {} # Dictionary mapping lexer states to master regexs self.lexstateretext = {} # Dictionary mapping lexer states to regex strings self.lexstaterenames = {} # Dictionary mapping lexer states to symbol names self.lexstate = "INITIAL" # Current lexer state self.lexstatestack = [] # Stack of lexer states self.lexstateinfo = None # State information self.lexstateignore = {} # Dictionary of ignored characters for each state self.lexstateerrorf = {} # Dictionary of error functions for each state self.lexreflags = 0 # Optional re compile flags self.lexdata = None # Actual input data (as a string) self.lexpos = 0 # Current position in input text self.lexlen = 0 # Length of the input text self.lexerrorf = None # Error rule (if any) self.lextokens = None # List of valid tokens self.lexignore = "" # Ignored characters self.lexliterals = "" # Literal characters that can be passed through self.lexmodule = None # Module self.lineno = 1 # Current line number self.lexoptimize = 0 # Optimized mode def clone(self,object=None): c = copy.copy(self) # If the object parameter has been supplied, it means we are attaching the # lexer to a new object. In this case, we have to rebind all methods in # the lexstatere and lexstateerrorf tables. if object: newtab = { } for key, ritem in self.lexstatere.items(): newre = [] for cre, findex in ritem: newfindex = [] for f in findex: if not f or not f[0]: newfindex.append(f) continue newfindex.append((getattr(object,f[0].__name__),f[1])) newre.append((cre,newfindex)) newtab[key] = newre c.lexstatere = newtab c.lexstateerrorf = { } for key, ef in self.lexstateerrorf.items(): c.lexstateerrorf[key] = getattr(object,ef.__name__) c.lexmodule = object return c # ------------------------------------------------------------ # writetab() - Write lexer information to a table file # ------------------------------------------------------------ def writetab(self,tabfile,outputdir=""): if isinstance(tabfile,types.ModuleType): return basetabfilename = tabfile.split(".")[-1] filename = os.path.join(outputdir,basetabfilename)+".py" tf = open(filename,"w") tf.write("# %s.py. This file automatically created by PLY (version %s). Don't edit!\n" % (tabfile,__version__)) tf.write("_tabversion = %s\n" % repr(__version__)) tf.write("_lextokens = %s\n" % repr(self.lextokens)) tf.write("_lexreflags = %s\n" % repr(self.lexreflags)) tf.write("_lexliterals = %s\n" % repr(self.lexliterals)) tf.write("_lexstateinfo = %s\n" % repr(self.lexstateinfo)) tabre = { } # Collect all functions in the initial state initial = self.lexstatere["INITIAL"] initialfuncs = [] for part in initial: for f in part[1]: if f and f[0]: initialfuncs.append(f) for key, lre in self.lexstatere.items(): titem = [] for i in range(len(lre)): titem.append((self.lexstateretext[key][i],_funcs_to_names(lre[i][1],self.lexstaterenames[key][i]))) tabre[key] = titem tf.write("_lexstatere = %s\n" % repr(tabre)) tf.write("_lexstateignore = %s\n" % repr(self.lexstateignore)) taberr = { } for key, ef in self.lexstateerrorf.items(): if ef: taberr[key] = ef.__name__ else: taberr[key] = None tf.write("_lexstateerrorf = %s\n" % repr(taberr)) tf.close() # ------------------------------------------------------------ # readtab() - Read lexer information from a tab file # ------------------------------------------------------------ def readtab(self,tabfile,fdict): if isinstance(tabfile,types.ModuleType): lextab = tabfile else: if sys.version_info[0] < 3: exec("import %s as lextab" % tabfile) else: env = { } exec("import %s as lextab" % tabfile, env,env) lextab = env['lextab'] if getattr(lextab,"_tabversion","0.0") != __version__: raise ImportError("Inconsistent PLY version") self.lextokens = lextab._lextokens self.lexreflags = lextab._lexreflags self.lexliterals = lextab._lexliterals self.lexstateinfo = lextab._lexstateinfo self.lexstateignore = lextab._lexstateignore self.lexstatere = { } self.lexstateretext = { } for key,lre in lextab._lexstatere.items(): titem = [] txtitem = [] for i in range(len(lre)): titem.append((re.compile(lre[i][0],lextab._lexreflags),_names_to_funcs(lre[i][1],fdict))) txtitem.append(lre[i][0]) self.lexstatere[key] = titem self.lexstateretext[key] = txtitem self.lexstateerrorf = { } for key,ef in lextab._lexstateerrorf.items(): self.lexstateerrorf[key] = fdict[ef] self.begin('INITIAL') # ------------------------------------------------------------ # input() - Push a new string into the lexer # ------------------------------------------------------------ def input(self,s): # Pull off the first character to see if s looks like a string c = s[:1] if not isinstance(c,StringTypes): raise ValueError("Expected a string") self.lexdata = s self.lexpos = 0 self.lexlen = len(s) # ------------------------------------------------------------ # begin() - Changes the lexing state # ------------------------------------------------------------ def begin(self,state): if not state in self.lexstatere: raise ValueError("Undefined state") self.lexre = self.lexstatere[state] self.lexretext = self.lexstateretext[state] self.lexignore = self.lexstateignore.get(state,"") self.lexerrorf = self.lexstateerrorf.get(state,None) self.lexstate = state # ------------------------------------------------------------ # push_state() - Changes the lexing state and saves old on stack # ------------------------------------------------------------ def push_state(self,state): self.lexstatestack.append(self.lexstate) self.begin(state) # ------------------------------------------------------------ # pop_state() - Restores the previous state # ------------------------------------------------------------ def pop_state(self): self.begin(self.lexstatestack.pop()) # ------------------------------------------------------------ # current_state() - Returns the current lexing state # ------------------------------------------------------------ def current_state(self): return self.lexstate # ------------------------------------------------------------ # skip() - Skip ahead n characters # ------------------------------------------------------------ def skip(self,n): self.lexpos += n # ------------------------------------------------------------ # opttoken() - Return the next token from the Lexer # # Note: This function has been carefully implemented to be as fast # as possible. Don't make changes unless you really know what # you are doing # ------------------------------------------------------------ def token(self): # Make local copies of frequently referenced attributes lexpos = self.lexpos lexlen = self.lexlen lexignore = self.lexignore lexdata = self.lexdata while lexpos < lexlen: # This code provides some short-circuit code for whitespace, tabs, and other ignored characters if lexdata[lexpos] in lexignore: lexpos += 1 continue # Look for a regular expression match for lexre,lexindexfunc in self.lexre: m = lexre.match(lexdata,lexpos) if not m: continue # Create a token for return tok = LexToken() tok.value = m.group() tok.lineno = self.lineno tok.lexpos = lexpos i = m.lastindex func,tok.type = lexindexfunc[i] if not func: # If no token type was set, it's an ignored token if tok.type: self.lexpos = m.end() return tok else: lexpos = m.end() break lexpos = m.end() # If token is processed by a function, call it tok.lexer = self # Set additional attributes useful in token rules self.lexmatch = m self.lexpos = lexpos newtok = func(tok) # Every function must return a token, if nothing, we just move to next token if not newtok: lexpos = self.lexpos # This is here in case user has updated lexpos. lexignore = self.lexignore # This is here in case there was a state change break # Verify type of the token. If not in the token map, raise an error if not self.lexoptimize: if not newtok.type in self.lextokens: raise LexError("%s:%d: Rule '%s' returned an unknown token type '%s'" % ( func_code(func).co_filename, func_code(func).co_firstlineno, func.__name__, newtok.type),lexdata[lexpos:]) return newtok else: # No match, see if in literals if lexdata[lexpos] in self.lexliterals: tok = LexToken() tok.value = lexdata[lexpos] tok.lineno = self.lineno tok.type = tok.value tok.lexpos = lexpos self.lexpos = lexpos + 1 return tok # No match. Call t_error() if defined. if self.lexerrorf: tok = LexToken() tok.value = self.lexdata[lexpos:] tok.lineno = self.lineno tok.type = "error" tok.lexer = self tok.lexpos = lexpos self.lexpos = lexpos newtok = self.lexerrorf(tok) if lexpos == self.lexpos: # Error method didn't change text position at all. This is an error. raise LexError("Scanning error. Illegal character '%s'" % (lexdata[lexpos]), lexdata[lexpos:]) lexpos = self.lexpos if not newtok: continue return newtok self.lexpos = lexpos raise LexError("Illegal character '%s' at index %d" % (lexdata[lexpos],lexpos), lexdata[lexpos:]) self.lexpos = lexpos + 1 if self.lexdata is None: raise RuntimeError("No input string given with input()") return None # Iterator interface def __iter__(self): return self def next(self): t = self.token() if t is None: raise StopIteration return t __next__ = next # ----------------------------------------------------------------------------- # ==== Lex Builder === # # The functions and classes below are used to collect lexing information # and build a Lexer object from it. # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- # get_caller_module_dict() # # This function returns a dictionary containing all of the symbols defined within # a caller further down the call stack. This is used to get the environment # associated with the yacc() call if none was provided. # ----------------------------------------------------------------------------- def get_caller_module_dict(levels): try: raise RuntimeError except RuntimeError: e,b,t = sys.exc_info() f = t.tb_frame while levels > 0: f = f.f_back levels -= 1 ldict = f.f_globals.copy() if f.f_globals != f.f_locals: ldict.update(f.f_locals) return ldict # ----------------------------------------------------------------------------- # _funcs_to_names() # # Given a list of regular expression functions, this converts it to a list # suitable for output to a table file # ----------------------------------------------------------------------------- def _funcs_to_names(funclist,namelist): result = [] for f,name in zip(funclist,namelist): if f and f[0]: result.append((name, f[1])) else: result.append(f) return result # ----------------------------------------------------------------------------- # _names_to_funcs() # # Given a list of regular expression function names, this converts it back to # functions. # ----------------------------------------------------------------------------- def _names_to_funcs(namelist,fdict): result = [] for n in namelist: if n and n[0]: result.append((fdict[n[0]],n[1])) else: result.append(n) return result # ----------------------------------------------------------------------------- # _form_master_re() # # This function takes a list of all of the regex components and attempts to # form the master regular expression. Given limitations in the Python re # module, it may be necessary to break the master regex into separate expressions. # ----------------------------------------------------------------------------- def _form_master_re(relist,reflags,ldict,toknames): if not relist: return [] regex = "|".join(relist) try: lexre = re.compile(regex,re.VERBOSE | reflags) # Build the index to function map for the matching engine lexindexfunc = [ None ] * (max(lexre.groupindex.values())+1) lexindexnames = lexindexfunc[:] for f,i in lexre.groupindex.items(): handle = ldict.get(f,None) if type(handle) in (types.FunctionType, types.MethodType): lexindexfunc[i] = (handle,toknames[f]) lexindexnames[i] = f elif handle is not None: lexindexnames[i] = f if f.find("ignore_") > 0: lexindexfunc[i] = (None,None) else: lexindexfunc[i] = (None, toknames[f]) return [(lexre,lexindexfunc)],[regex],[lexindexnames] except Exception: m = int(len(relist)/2) if m == 0: m = 1 llist, lre, lnames = _form_master_re(relist[:m],reflags,ldict,toknames) rlist, rre, rnames = _form_master_re(relist[m:],reflags,ldict,toknames) return llist+rlist, lre+rre, lnames+rnames # ----------------------------------------------------------------------------- # def _statetoken(s,names) # # Given a declaration name s of the form "t_" and a dictionary whose keys are # state names, this function returns a tuple (states,tokenname) where states # is a tuple of state names and tokenname is the name of the token. For example, # calling this with s = "t_foo_bar_SPAM" might return (('foo','bar'),'SPAM') # ----------------------------------------------------------------------------- def _statetoken(s,names): nonstate = 1 parts = s.split("_") for i in range(1,len(parts)): if not parts[i] in names and parts[i] != 'ANY': break if i > 1: states = tuple(parts[1:i]) else: states = ('INITIAL',) if 'ANY' in states: states = tuple(names) tokenname = "_".join(parts[i:]) return (states,tokenname) # ----------------------------------------------------------------------------- # LexerReflect() # # This class represents information needed to build a lexer as extracted from a # user's input file. # ----------------------------------------------------------------------------- class LexerReflect(object): def __init__(self,ldict,log=None,reflags=0): self.ldict = ldict self.error_func = None self.tokens = [] self.reflags = reflags self.stateinfo = { 'INITIAL' : 'inclusive'} self.files = {} self.error = 0 if log is None: self.log = PlyLogger(sys.stderr) else: self.log = log # Get all of the basic information def get_all(self): self.get_tokens() self.get_literals() self.get_states() self.get_rules() # Validate all of the information def validate_all(self): self.validate_tokens() self.validate_literals() self.validate_rules() return self.error # Get the tokens map def get_tokens(self): tokens = self.ldict.get("tokens",None) if not tokens: self.log.error("No token list is defined") self.error = 1 return if not isinstance(tokens,(list, tuple)): self.log.error("tokens must be a list or tuple") self.error = 1 return if not tokens: self.log.error("tokens is empty") self.error = 1 return self.tokens = tokens # Validate the tokens def validate_tokens(self): terminals = {} for n in self.tokens: if not _is_identifier.match(n): self.log.error("Bad token name '%s'",n) self.error = 1 if n in terminals: self.log.warning("Token '%s' multiply defined", n) terminals[n] = 1 # Get the literals specifier def get_literals(self): self.literals = self.ldict.get("literals","") # Validate literals def validate_literals(self): try: for c in self.literals: if not isinstance(c,StringTypes) or len(c) > 1: self.log.error("Invalid literal %s. Must be a single character", repr(c)) self.error = 1 continue except TypeError: self.log.error("Invalid literals specification. literals must be a sequence of characters") self.error = 1 def get_states(self): self.states = self.ldict.get("states",None) # Build statemap if self.states: if not isinstance(self.states,(tuple,list)): self.log.error("states must be defined as a tuple or list") self.error = 1 else: for s in self.states: if not isinstance(s,tuple) or len(s) != 2: self.log.error("Invalid state specifier %s. Must be a tuple (statename,'exclusive|inclusive')",repr(s)) self.error = 1 continue name, statetype = s if not isinstance(name,StringTypes): self.log.error("State name %s must be a string", repr(name)) self.error = 1 continue if not (statetype == 'inclusive' or statetype == 'exclusive'): self.log.error("State type for state %s must be 'inclusive' or 'exclusive'",name) self.error = 1 continue if name in self.stateinfo: self.log.error("State '%s' already defined",name) self.error = 1 continue self.stateinfo[name] = statetype # Get all of the symbols with a t_ prefix and sort them into various # categories (functions, strings, error functions, and ignore characters) def get_rules(self): tsymbols = [f for f in self.ldict if f[:2] == 't_' ] # Now build up a list of functions and a list of strings self.toknames = { } # Mapping of symbols to token names self.funcsym = { } # Symbols defined as functions self.strsym = { } # Symbols defined as strings self.ignore = { } # Ignore strings by state self.errorf = { } # Error functions by state for s in self.stateinfo: self.funcsym[s] = [] self.strsym[s] = [] if len(tsymbols) == 0: self.log.error("No rules of the form t_rulename are defined") self.error = 1 return for f in tsymbols: t = self.ldict[f] states, tokname = _statetoken(f,self.stateinfo) self.toknames[f] = tokname if hasattr(t,"__call__"): if tokname == 'error': for s in states: self.errorf[s] = t elif tokname == 'ignore': line = func_code(t).co_firstlineno file = func_code(t).co_filename self.log.error("%s:%d: Rule '%s' must be defined as a string",file,line,t.__name__) self.error = 1 else: for s in states: self.funcsym[s].append((f,t)) elif isinstance(t, StringTypes): if tokname == 'ignore': for s in states: self.ignore[s] = t if "\\" in t: self.log.warning("%s contains a literal backslash '\\'",f) elif tokname == 'error': self.log.error("Rule '%s' must be defined as a function", f) self.error = 1 else: for s in states: self.strsym[s].append((f,t)) else: self.log.error("%s not defined as a function or string", f) self.error = 1 # Sort the functions by line number for f in self.funcsym.values(): if sys.version_info[0] < 3: f.sort(lambda x,y: cmp(func_code(x[1]).co_firstlineno,func_code(y[1]).co_firstlineno)) else: # Python 3.0 f.sort(key=lambda x: func_code(x[1]).co_firstlineno) # Sort the strings by regular expression length for s in self.strsym.values(): if sys.version_info[0] < 3: s.sort(lambda x,y: (len(x[1]) < len(y[1])) - (len(x[1]) > len(y[1]))) else: # Python 3.0 s.sort(key=lambda x: len(x[1]),reverse=True) # Validate all of the t_rules collected def validate_rules(self): for state in self.stateinfo: # Validate all rules defined by functions for fname, f in self.funcsym[state]: line = func_code(f).co_firstlineno file = func_code(f).co_filename self.files[file] = 1 tokname = self.toknames[fname] if isinstance(f, types.MethodType): reqargs = 2 else: reqargs = 1 nargs = func_code(f).co_argcount if nargs > reqargs: self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,f.__name__) self.error = 1 continue if nargs < reqargs: self.log.error("%s:%d: Rule '%s' requires an argument", file,line,f.__name__) self.error = 1 continue if not f.__doc__: self.log.error("%s:%d: No regular expression defined for rule '%s'",file,line,f.__name__) self.error = 1 continue try: c = re.compile("(?P<%s>%s)" % (fname,f.__doc__), re.VERBOSE | self.reflags) if c.match(""): self.log.error("%s:%d: Regular expression for rule '%s' matches empty string", file,line,f.__name__) self.error = 1 except re.error: _etype, e, _etrace = sys.exc_info() self.log.error("%s:%d: Invalid regular expression for rule '%s'. %s", file,line,f.__name__,e) if '#' in f.__doc__: self.log.error("%s:%d. Make sure '#' in rule '%s' is escaped with '\\#'",file,line, f.__name__) self.error = 1 # Validate all rules defined by strings for name,r in self.strsym[state]: tokname = self.toknames[name] if tokname == 'error': self.log.error("Rule '%s' must be defined as a function", name) self.error = 1 continue if not tokname in self.tokens and tokname.find("ignore_") < 0: self.log.error("Rule '%s' defined for an unspecified token %s",name,tokname) self.error = 1 continue try: c = re.compile("(?P<%s>%s)" % (name,r),re.VERBOSE | self.reflags) if (c.match("")): self.log.error("Regular expression for rule '%s' matches empty string",name) self.error = 1 except re.error: _etype, e, _etrace = sys.exc_info() self.log.error("Invalid regular expression for rule '%s'. %s",name,e) if '#' in r: self.log.error("Make sure '#' in rule '%s' is escaped with '\\#'",name) self.error = 1 if not self.funcsym[state] and not self.strsym[state]: self.log.error("No rules defined for state '%s'",state) self.error = 1 # Validate the error function efunc = self.errorf.get(state,None) if efunc: f = efunc line = func_code(f).co_firstlineno file = func_code(f).co_filename self.files[file] = 1 if isinstance(f, types.MethodType): reqargs = 2 else: reqargs = 1 nargs = func_code(f).co_argcount if nargs > reqargs: self.log.error("%s:%d: Rule '%s' has too many arguments",file,line,f.__name__) self.error = 1 if nargs < reqargs: self.log.error("%s:%d: Rule '%s' requires an argument", file,line,f.__name__) self.error = 1 for f in self.files: self.validate_file(f) # ----------------------------------------------------------------------------- # validate_file() # # This checks to see if there are duplicated t_rulename() functions or strings # in the parser input file. This is done using a simple regular expression # match on each line in the given file. # ----------------------------------------------------------------------------- def validate_file(self,filename): import os.path base,ext = os.path.splitext(filename) if ext != '.py': return # No idea what the file is. Return OK try: f = open(filename) lines = f.readlines() f.close() except IOError: return # Couldn't find the file. Don't worry about it fre = re.compile(r'\s*def\s+(t_[a-zA-Z_0-9]*)\(') sre = re.compile(r'\s*(t_[a-zA-Z_0-9]*)\s*=') counthash = { } linen = 1 for l in lines: m = fre.match(l) if not m: m = sre.match(l) if m: name = m.group(1) prev = counthash.get(name) if not prev: counthash[name] = linen else: self.log.error("%s:%d: Rule %s redefined. Previously defined on line %d",filename,linen,name,prev) self.error = 1 linen += 1 # ----------------------------------------------------------------------------- # lex(module) # # Build all of the regular expression rules from definitions in the supplied module # ----------------------------------------------------------------------------- def lex(module=None,object=None,debug=0,optimize=0,lextab="lextab",reflags=0,nowarn=0,outputdir="", debuglog=None, errorlog=None): global lexer ldict = None stateinfo = { 'INITIAL' : 'inclusive'} lexobj = Lexer() lexobj.lexoptimize = optimize global token,input if errorlog is None: errorlog = PlyLogger(sys.stderr) if debug: if debuglog is None: debuglog = PlyLogger(sys.stderr) # Get the module dictionary used for the lexer if object: module = object if module: _items = [(k,getattr(module,k)) for k in dir(module)] ldict = dict(_items) else: ldict = get_caller_module_dict(2) # Collect parser information from the dictionary linfo = LexerReflect(ldict,log=errorlog,reflags=reflags) linfo.get_all() if not optimize: if linfo.validate_all(): raise SyntaxError("Can't build lexer") if optimize and lextab: try: lexobj.readtab(lextab,ldict) token = lexobj.token input = lexobj.input lexer = lexobj return lexobj except ImportError: pass # Dump some basic debugging information if debug: debuglog.info("lex: tokens = %r", linfo.tokens) debuglog.info("lex: literals = %r", linfo.literals) debuglog.info("lex: states = %r", linfo.stateinfo) # Build a dictionary of valid token names lexobj.lextokens = { } for n in linfo.tokens: lexobj.lextokens[n] = 1 # Get literals specification if isinstance(linfo.literals,(list,tuple)): lexobj.lexliterals = type(linfo.literals[0])().join(linfo.literals) else: lexobj.lexliterals = linfo.literals # Get the stateinfo dictionary stateinfo = linfo.stateinfo regexs = { } # Build the master regular expressions for state in stateinfo: regex_list = [] # Add rules defined by functions first for fname, f in linfo.funcsym[state]: line = func_code(f).co_firstlineno file = func_code(f).co_filename regex_list.append("(?P<%s>%s)" % (fname,f.__doc__)) if debug: debuglog.info("lex: Adding rule %s -> '%s' (state '%s')",fname,f.__doc__, state) # Now add all of the simple rules for name,r in linfo.strsym[state]: regex_list.append("(?P<%s>%s)" % (name,r)) if debug: debuglog.info("lex: Adding rule %s -> '%s' (state '%s')",name,r, state) regexs[state] = regex_list # Build the master regular expressions if debug: debuglog.info("lex: ==== MASTER REGEXS FOLLOW ====") for state in regexs: lexre, re_text, re_names = _form_master_re(regexs[state],reflags,ldict,linfo.toknames) lexobj.lexstatere[state] = lexre lexobj.lexstateretext[state] = re_text lexobj.lexstaterenames[state] = re_names if debug: for i in range(len(re_text)): debuglog.info("lex: state '%s' : regex[%d] = '%s'",state, i, re_text[i]) # For inclusive states, we need to add the regular expressions from the INITIAL state for state,stype in stateinfo.items(): if state != "INITIAL" and stype == 'inclusive': lexobj.lexstatere[state].extend(lexobj.lexstatere['INITIAL']) lexobj.lexstateretext[state].extend(lexobj.lexstateretext['INITIAL']) lexobj.lexstaterenames[state].extend(lexobj.lexstaterenames['INITIAL']) lexobj.lexstateinfo = stateinfo lexobj.lexre = lexobj.lexstatere["INITIAL"] lexobj.lexretext = lexobj.lexstateretext["INITIAL"] # Set up ignore variables lexobj.lexstateignore = linfo.ignore lexobj.lexignore = lexobj.lexstateignore.get("INITIAL","") # Set up error functions lexobj.lexstateerrorf = linfo.errorf lexobj.lexerrorf = linfo.errorf.get("INITIAL",None) if not lexobj.lexerrorf: errorlog.warning("No t_error rule is defined") # Check state information for ignore and error rules for s,stype in stateinfo.items(): if stype == 'exclusive': if not s in linfo.errorf: errorlog.warning("No error rule is defined for exclusive state '%s'", s) if not s in linfo.ignore and lexobj.lexignore: errorlog.warning("No ignore rule is defined for exclusive state '%s'", s) elif stype == 'inclusive': if not s in linfo.errorf: linfo.errorf[s] = linfo.errorf.get("INITIAL",None) if not s in linfo.ignore: linfo.ignore[s] = linfo.ignore.get("INITIAL","") # Create global versions of the token() and input() functions token = lexobj.token input = lexobj.input lexer = lexobj # If in optimize mode, we write the lextab if lextab and optimize: lexobj.writetab(lextab,outputdir) return lexobj # ----------------------------------------------------------------------------- # runmain() # # This runs the lexer as a main program # ----------------------------------------------------------------------------- def runmain(lexer=None,data=None): if not data: try: filename = sys.argv[1] f = open(filename) data = f.read() f.close() except IndexError: sys.stdout.write("Reading from standard input (type EOF to end):\n") data = sys.stdin.read() if lexer: _input = lexer.input else: _input = input _input(data) if lexer: _token = lexer.token else: _token = token while 1: tok = _token() if not tok: break sys.stdout.write("(%s,%r,%d,%d)\n" % (tok.type, tok.value, tok.lineno,tok.lexpos)) # ----------------------------------------------------------------------------- # @TOKEN(regex) # # This decorator function can be used to set the regex expression on a function # when its docstring might need to be set in an alternative way # ----------------------------------------------------------------------------- def TOKEN(r): def set_doc(f): if hasattr(r,"__call__"): f.__doc__ = r.__doc__ else: f.__doc__ = r return f return set_doc # Alternative spelling of the TOKEN decorator Token = TOKEN pywbem-0.8.0~dev/pywbem/cim_http.py0000644000175000017500000003603612413747174017317 0ustar bzedbzed00000000000000# # (C) Copyright 2003-2005 Hewlett-Packard Development Company, L.P. # (C) Copyright 2006-2007 Novell, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter # Author: Martin Pool # Author: Bart Whiteley ''' This module implements CIM operations over HTTP. This module should not know anything about the fact that the data being transferred is XML. It is up to the caller to format the input data and interpret the result. ''' from M2Crypto import SSL, Err import sys, string, re, os, socket, getpass from stat import S_ISSOCK from types import StringTypes import platform from pywbem import cim_obj class Error(Exception): """This exception is raised when a transport error occurs.""" pass class AuthError(Error): """This exception is raised when an authentication error (401) occurs.""" pass def parse_url(url): """Return a tuple of (host, port, ssl) from the URL parameter. The returned port defaults to 5988 if not specified. SSL supports defaults to False if not specified.""" host = url # Defaults port = 5988 ssl = False if re.match("https", url): # Set SSL if specified ssl = True port = 5989 m = re.search("^https?://", url) # Eat protocol name if m: host = url[len(m.group(0)):] # IPv6 with/without port m = re.match("^\[?([0-9A-Fa-f:]*)\]?(:([0-9]*))?$", host) if m: host = m.group(1) port_tmp = m.group(3) if port_tmp: port = int(port_tmp) return host, port, ssl s = string.split(host, ":") # Set port number if len(s) != 1: host = s[0] port = int(s[1]) return host, port, ssl def get_default_ca_certs(): """ Try to find out system path with ca certificates. This path is cached and returned. If no path is found out, None is returned. """ if not hasattr(get_default_ca_certs, '_path'): for path in ( '/etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt', '/etc/ssl/certs', '/etc/ssl/certificates'): if os.path.exists(path): get_default_ca_certs._path = path break else: get_default_ca_certs._path = None return get_default_ca_certs._path def wbem_request(url, data, creds, headers = [], debug = 0, x509 = None, verify_callback = None, ca_certs = None, no_verification = False): """Send XML data over HTTP to the specified url. Return the response in XML. Uses Python's build-in httplib. x509 may be a dictionary containing the location of the SSL certificate and key files. The data argument must be a unicode object or a UTF-8 encoded str object. """ import httplib, base64, urllib class HTTPBaseConnection: def send(self, str): """ Same as httplib.HTTPConnection.send(), except we don't check for sigpipe and close the connection. If the connection gets closed, getresponse() fails. """ if self.sock is None: if self.auto_open: self.connect() else: raise httplib.NotConnected() if self.debuglevel > 0: print "send:", repr(str) self.sock.sendall(str) class HTTPConnection(HTTPBaseConnection, httplib.HTTPConnection): def __init__(self, host, port=None, strict=None): httplib.HTTPConnection.__init__(self, host, port, strict) class HTTPSConnection(HTTPBaseConnection, httplib.HTTPSConnection): def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, ca_certs=None, verify_callback=None): httplib.HTTPSConnection.__init__(self, host, port, key_file, cert_file, strict) self.ca_certs = ca_certs self.verify_callback = verify_callback def connect(self): "Connect to a host on a given (SSL) port." self.sock = socket.create_connection((self.host, self.port), self.timeout, self.source_address) if self._tunnel_host: self.sock = sock self._tunnel() ctx = SSL.Context('sslv23') if self.cert_file: ctx.load_cert(self.cert_file, keyfile=self.key_file) if self.ca_certs: ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9, callback=verify_callback) if os.path.isdir(self.ca_certs): ctx.load_verify_locations(capath=self.ca_certs) else: ctx.load_verify_locations(cafile=self.ca_certs) try: self.sock = SSL.Connection(ctx, self.sock) # Below is a body of SSL.Connection.connect() method # except for the first line (socket connection). We want to preserve # tunneling ability. self.sock.addr = (self.host, self.port) self.sock.setup_ssl() self.sock.set_connect_state() ret = self.sock.connect_ssl() if self.ca_certs: check = getattr(self.sock, 'postConnectionCheck', self.sock.clientPostConnectionCheck) if check is not None: if not check(self.sock.get_peer_cert(), self.host): raise Error('SSL error: post connection check failed') return ret except ( Err.SSLError, SSL.SSLError, SSL.SSLTimeoutError , SSL.Checker.WrongHost), arg: raise Error("SSL error: %s" % arg) class FileHTTPConnection(HTTPBaseConnection, httplib.HTTPConnection): def __init__(self, uds_path): httplib.HTTPConnection.__init__(self, 'localhost') self.uds_path = uds_path def connect(self): try: socket_af = socket.AF_UNIX except AttributeError: raise Error('file URL not supported on %s platform due '\ 'to missing AF_UNIX support' % platform.system()) self.sock = socket.socket(socket_af, socket.SOCK_STREAM) self.sock.connect(self.uds_path) host, port, use_ssl = parse_url(url) key_file = None cert_file = None if use_ssl and x509 is not None: cert_file = x509.get('cert_file') key_file = x509.get('key_file') numTries = 0 localAuthHeader = None tryLimit = 5 # Make sure the data argument is converted to a UTF-8 encoded str object. # This is important because according to RFC2616, the Content-Length HTTP # header must be measured in Bytes (and the Content-Type header will # indicate UTF-8). if isinstance(data, unicode): data = data.encode('utf-8') data = '\n' + data if not no_verification and ca_certs is None: ca_certs = get_default_ca_certs() elif no_verification: ca_certs = None local = False if use_ssl: h = HTTPSConnection(host, port = port, key_file = key_file, cert_file = cert_file, ca_certs = ca_certs, verify_callback = verify_callback) else: if url.startswith('http'): h = HTTPConnection(host, port = port) else: if url.startswith('file:'): url = url[5:] try: s = os.stat(url) if S_ISSOCK(s.st_mode): h = FileHTTPConnection(url) local = True else: raise Error('Invalid URL') except OSError: raise Error('Invalid URL') locallogin = None if host in ('localhost', 'localhost6', '127.0.0.1', '::1'): local = True if local: try: locallogin = getpass.getuser() except (KeyError, ImportError): locallogin = None while numTries < tryLimit: numTries = numTries + 1 h.putrequest('POST', '/cimom') h.putheader('Content-type', 'application/xml; charset="utf-8"') h.putheader('Content-length', str(len(data))) if localAuthHeader is not None: h.putheader(*localAuthHeader) elif creds is not None: h.putheader('Authorization', 'Basic %s' % base64.encodestring('%s:%s' % (creds[0], creds[1])).replace('\n','')) elif locallogin is not None: h.putheader('PegasusAuthorization', 'Local "%s"' % locallogin) for hdr in headers: if isinstance(hdr, unicode): hdr = hdr.encode('utf-8') s = map(lambda x: string.strip(x), string.split(hdr, ":", 1)) h.putheader(urllib.quote(s[0]), urllib.quote(s[1])) try: # See RFC 2616 section 8.2.2 # An http server is allowed to send back an error (presumably # a 401), and close the connection without reading the entire # request. A server may do this to protect itself from a DoS # attack. # # If the server closes the connection during our h.send(), we # will either get a socket exception 104 (TCP RESET), or a # socket exception 32 (broken pipe). In either case, thanks # to our fixed HTTPConnection classes, we'll still be able to # retrieve the response so that we can read and respond to the # authentication challenge. h.endheaders() try: h.send(data) except socket.error, arg: if arg[0] != 104 and arg[0] != 32: raise response = h.getresponse() body = response.read() if response.status != 200: if response.status == 401: if numTries >= tryLimit: raise AuthError(response.reason) if not local: raise AuthError(response.reason) authChal = response.getheader('WWW-Authenticate', '') if 'openwbem' in response.getheader('Server', ''): if 'OWLocal' not in authChal: try: uid = os.getuid() except AttributeError: raise Error("OWLocal authorization for "\ "openwbem server not supported on %s "\ "platform due to missing os.getuid()"%\ platform.system()) localAuthHeader = ('Authorization', 'OWLocal uid="%d"' % uid) continue else: try: nonceIdx = authChal.index('nonce=') nonceBegin = authChal.index('"', nonceIdx) nonceEnd = authChal.index('"', nonceBegin+1) nonce = authChal[nonceBegin+1:nonceEnd] cookieIdx = authChal.index('cookiefile=') cookieBegin = authChal.index('"', cookieIdx) cookieEnd = authChal.index('"', cookieBegin+1) cookieFile = authChal[cookieBegin+1:cookieEnd] f = open(cookieFile, 'r') cookie = f.read().strip() f.close() localAuthHeader = ('Authorization', 'OWLocal nonce="%s", cookie="%s"' % \ (nonce, cookie)) continue except: localAuthHeader = None continue elif 'Local' in authChal: try: beg = authChal.index('"') + 1 end = authChal.rindex('"') if end > beg: file = authChal[beg:end] fo = open(file, 'r') cookie = fo.read().strip() fo.close() localAuthHeader = ('PegasusAuthorization', 'Local "%s:%s:%s"' % \ (locallogin, file, cookie)) continue except ValueError: pass raise AuthError(response.reason) if response.getheader('CIMError', None) is not None and \ response.getheader('PGErrorDetail', None) is not None: import urllib raise Error( 'CIMError: %s: %s' % (response.getheader('CIMError'), urllib.unquote(response.getheader('PGErrorDetail')))) raise Error('HTTP error: %s' % response.reason) except httplib.BadStatusLine, arg: raise Error("The web server returned a bad status line: '%s'" % arg) except socket.error, arg: raise Error("Socket error: %s" % (arg,)) except socket.sslerror, arg: raise Error("SSL error: %s" % (arg,)) break return body def get_object_header(obj): """Return the HTTP header required to make a CIM operation request using the given object. Return None if the object does not need to have a header.""" # Local namespacepath if isinstance(obj, StringTypes): return 'CIMObject: %s' % obj # CIMLocalClassPath if isinstance(obj, cim_obj.CIMClassName): return 'CIMObject: %s:%s' % (obj.namespace, obj.classname) # CIMInstanceName with namespace if isinstance(obj, cim_obj.CIMInstanceName) and obj.namespace is not None: return 'CIMObject: %s' % obj raise TypeError('Don\'t know how to generate HTTP headers for %s' % obj) pywbem-0.8.0~dev/pywbem/cim_provider2.py0000644000175000017500000025067012413747174020256 0ustar bzedbzed00000000000000# # (C) Copyright 2003-2007 Hewlett-Packard Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Bart Whiteley # Jon Carey #### """Python CIM Providers (aka "nirvana") This module is an abstraction and utility layer between a CIMOM and Python providers. The CIMOM uses this module to load Python providers, and route requests to those providers. Python Provider Modules Python Providers are implemented as Python modules. By convention these modules are installed into /usr/lib/pycim. However, they can be anywhere. These modules are loaded on demand using load_module() from the imp module. The CIMOM's pycim interface stores the timestamp of the provider modules. If the modules change, the CIMOM reloads the modules. This is very useful while developing providers, since the latest code will always be loaded and used. A Python Provider Module will contain functions, attributes, and instances that will be accessed and manipulated by this module. Providers are often classified in the following catagories: Instance -- Instrument the retrieval, creation, modification, and deletion of CIM instances. Association -- Instrument CIM associations (CIM classes with the Association qualifier). Method -- Instrument methods as defined on CIM instances or CIM classes. Indication -- Generates indications based on indication subscriptions. Indication Consumer -- "Consumes" (or "Handles") an indication, possibly delivering it through some other means, such as email. Polled -- A polled provider is allowed to run periodically (by calling its poll function). This allows a provider to do some periodic work, without the need to create its own thread. An Instance, Association, and/or Method provider is created by defining one or more subclasses of CIMProvider2 within the provider module, and registering instances of the subclass(es) with CIM class names by way of the get_providers function (described below). Refer to the documentation for CIMProvider2 in this module. Indication, Indication Consumer, and Polled providers are defined by implementing some functions within the provider module. Provider module functions: init(env): This module function is optional. It is called immediately after the provider module is imported. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) get_providers(env): Return a dict that maps CIM class names to instances of CIMProvider2 subclasses. Note that multiple classes can be instrumented by the same instance of a CIMProvider2 subclass. The CIM class names are case-insensitive, since this dict is converted to a NocaseDict. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) For example, a Python Provider Module may contain the following: class Py_FooBarProvider(CIMProvider2): ... def get_providers(env): _fbp = Py_FooBarProvider() return {'Py_Foo':_fbp, 'Py_Bar':_fbp} can_unload(env): Return True if the provider can be unloaded. The CIMOM may try to unload a provider after a period of inactivity. Before unloading a provider, the CIMOM asks the provider if it can be unloaded. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) shutdown(env): Perform any cleanup tasks prior to being unloaded. The provider will shortly be unloaded, and is given an opportunity to perform any needed cleanup. The provider may be unloaded after a period of inactivity (see the documentation for can_unload), or because the CIMOM is shutting down. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) handle_indication(env, ns, handler_instance, indication_instance): Process an indication. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) ns -- The namespace where the event occurred handler_instance -- indication_instance -- The indication authorize_filter (env, filter, ns, classes, owner): Allow or disallow an indication subscription request. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) filter -- The WQL select statement namespace -- The namepace where the indication is registered for classes -- The classpath of the indication registered for owner -- The name of the principal (cimom user) activate_filter (env, filter, ns, classes, first_activation): Activate an indication subscription. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) filter -- The WQL select statement namespace -- The namepace where the indication is registered for classes -- The classpath of the indication registered for first_activation -- boolean - whether first activation deactivate_filter(env, filter, ns, classes, last_activation): Deactivate an indication subscription. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) filter -- The WQL select statement ns -- The namepace where the indication is registered for classes -- The classpath of the indication registered for last_activation -- boolean - whether last activation enable_indications(env): Enable indications. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) disable_indications(env): Disable indications. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) Provider Environment A pycimmb.ProviderEnvironment is passed to many functions. This is a handle back into the CIMOM. You can use it for logging and for making "up-calls" to the CIMOM. For example: logger = env.get_logger() logger.log_debug('Debug Info') ch = env.get_cimom_handle() other_inst = ch.GetInstance(inst_path, LocalOnly=False, IncludeQualifiers=False, IncludeClassOrigin=False) The API of the pycimmb.CIMOMHandle resembles that of pywbem.WBEMConnection. For more information on the ProviderEnvironments, and other features provided by pycimmb, refer to the pycimmb documentation. CodeGen The codegen function can be used to generate provider stub code for a given CIM class. This is a quick way to get started writing a provider. """ import sys from os.path import dirname import types import sys # for sys.modules import os import imp import threading import pywbem g_mod_lock = threading.RLock() __all__ = ['CIMProvider2', 'codegen'] def _paths_equal(lhs, rhs): """If one object path doesn't inlcude a host, don't include the hosts in the comparison """ if lhs is rhs: return True if lhs.host is not None and rhs.host is not None and lhs.host != rhs.host: return False # need to make sure this stays in sync with CIMInstanceName.__cmp__() return not (pywbem.cmpname(rhs.classname, lhs.classname) or cmp(rhs.keybindings, lhs.keybindings) or pywbem.cmpname(rhs.namespace, lhs.namespace)) class CIMProvider2(object): """Base class for CIM Providers. A derived class might normally override the following: - enum_instances - get_instance - set_instance - delete_instance - references If the provider is a "read-only" instance provider, set_instance and delete_instance need not be overridden. Only association providers need to override references. A method provider should implement a method of the form: def cim_method_(self, env, object_name, method, param_, param_, ...): Where is the name of the method from the CIM schema. needs to be all lowercase, regardless of the case of the method name in the CIM schema (CIM method names are case insensitive). Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) object_name -- A pywbem.CIMInstanceName or pywbem.CIMClassname specifying the object on which the method is to be invoked. method -- A pywbem.CIMMethod, representing the method to execute. param_ -- Corresponds to the input parameter from the CIM schema. needs to be all lowercase, regardless of the case of the parameter name in the CIM schema (CIM parameter names are case insensitive). The method returns a two-tuple containing the return value of the method, and a dictionary containing the output parameters. Example: def cim_method_requeststatechange(self, env, object_name, method, param_requestedstate, param_timeoutperiod): # do stuff. out_params = {'job': pywbem.CIMInstanceName(...)} rval = pywbem.Uint32(0) return (rval, out_params) The methods prefixed with "MI_" correspond to the WBEM operations from http://www.dmtf.org/standards/published_documents/DSP200.html The default implementations of these methods call the methods described above. These will not normally be overridden or extended by a subclass. """ def get_instance (self, env, model): """Return an instance. Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) model -- A template of the pywbem.CIMInstance to be returned. The key properties are set on this instance to correspond to the instanceName that was requested. The properties of the model are already filtered according to the PropertyList from the request. Only properties present in the model need to be given values. If you prefer, you can set all of the values, and the instance will be filtered for you. Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_NOT_FOUND (the CIM Class does exist, but the requested CIM Instance does not exist in the specified namespace) CIM_ERR_FAILED (some other unspecified error occurred) """ return None def enum_instances(self, env, model, keys_only): """Enumerate instances. The WBEM operations EnumerateInstances and EnumerateInstanceNames are both mapped to this method. This method is a python generator Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) model -- A template of the pywbem.CIMInstances to be generated. The properties of the model are already filtered according to the PropertyList from the request. Only properties present in the model need to be given values. If you prefer, you can always set all of the values, and the instance will be filtered for you. keys_only -- A boolean. True if only the key properties should be set on the generated instances. Possible Errors: CIM_ERR_FAILED (some other unspecified error occurred) """ pass def set_instance(self, env, instance, modify_existing): """Return a newly created or modified instance. Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) instance -- The new pywbem.CIMInstance. If modifying an existing instance, the properties on this instance have been filtered by the PropertyList from the request. modify_existing -- True if ModifyInstance, False if CreateInstance Return the new instance. The keys must be set on the new instance. Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_NOT_SUPPORTED CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_ALREADY_EXISTS (the CIM Instance already exists -- only valid if modify_existing is False, indicating that the operation was CreateInstance) CIM_ERR_NOT_FOUND (the CIM Instance does not exist -- only valid if modify_existing is True, indicating that the operation was ModifyInstance) CIM_ERR_FAILED (some other unspecified error occurred) """ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED, "") def delete_instance(self, env, instance_name): """Delete an instance. Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) instance_name -- A pywbem.CIMInstanceName specifying the instance to delete. Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_NOT_SUPPORTED CIM_ERR_INVALID_NAMESPACE CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_INVALID_CLASS (the CIM Class does not exist in the specified namespace) CIM_ERR_NOT_FOUND (the CIM Class does exist, but the requested CIM Instance does not exist in the specified namespace) CIM_ERR_FAILED (some other unspecified error occurred) """ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED, "") def references(self, env, object_name, model, result_class_name, role, result_role, keys_only): """Instrument Associations. All four association-related operations (Associators, AssociatorNames, References, ReferenceNames) are mapped to this method. This method is a python generator Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) object_name -- A pywbem.CIMInstanceName that defines the source CIM Object whose associated Objects are to be returned. model -- A template pywbem.CIMInstance to serve as a model of the objects to be returned. Only properties present on this model need to be set. result_class_name -- If not empty, this string acts as a filter on the returned set of Instances by mandating that each returned Instances MUST represent an association between object_name and an Instance of a Class whose name matches this parameter or a subclass. role -- If not empty, MUST be a valid Property name. It acts as a filter on the returned set of Instances by mandating that each returned Instance MUST refer to object_name via a Property whose name matches the value of this parameter. result_role -- If not empty, MUST be a valid Property name. It acts as a filter on the returned set of Instances by mandating that each returned Instance MUST represent associations of object_name to other Instances, where the other Instances play the specified result_role in the association (i.e. the name of the Property in the Association Class that refers to the Object related to object_name MUST match the value of this parameter). keys_only -- A boolean. True if only the key properties should be set on the generated instances. The following diagram may be helpful in understanding the role, result_role, and result_class_name parameters. +------------------------+ +-------------------+ | object_name.classname | | result_class_name | | ~~~~~~~~~~~~~~~~~~~~~ | | ~~~~~~~~~~~~~~~~~ | +------------------------+ +-------------------+ | +-----------------------------------+ | | | [Association] model.classname | | | object_name | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | +--------------+ object_name.classname REF role | | (CIMInstanceName) | result_class_name REF result_role +------+ | |(CIMInstanceName) +-----------------------------------+ Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_NOT_SUPPORTED CIM_ERR_INVALID_NAMESPACE CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_FAILED (some other unspecified error occurred) """ # Don't change this return value. If affects the behavior # of the MI_* methods. return None def simple_refs(self, env, object_name, model, result_class_name, role, result_role, keys_only): gen = self.enum_instances(env, model, keys_only) if role: role = role.lower() for inst in gen: for prop in inst.properties.values(): if prop.type != 'reference': continue if role and prop.name.lower() != role: continue if self.paths_equal(object_name, prop.value): yield inst def paths_equal(self, lhs, rhs): """If one object path doesn't inlcude a host, don't include the hosts in the comparison """ if lhs is rhs: return True if lhs.host is not None and rhs.host is not None and lhs.host != rhs.host: return False # need to make sure this stays in sync with CIMInstanceName.__cmp__() return not (pywbem.cmpname(rhs.classname, lhs.classname) or cmp(rhs.keybindings, lhs.keybindings) or pywbem.cmpname(rhs.namespace, lhs.namespace)) def MI_enumInstanceNames(self, env, objPath): """Return instance names of a given CIM class Implements the WBEM operation EnumerateInstanceNames in terms of the enum_instances method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_enumInstanceNames called...') model = pywbem.CIMInstance(classname=objPath.classname, path=objPath) gen = self.enum_instances(env=env, model=model, keys_only=True) try: iter(gen) except TypeError: logger.log_debug('CIMProvider2 MI_enumInstanceNames returning') return for inst in gen: yield inst.path logger.log_debug('CIMProvider2 MI_enumInstanceNames returning') def MI_enumInstances(self, env, objPath, propertyList): """Return instances of a given CIM class Implements the WBEM operation EnumerateInstances in terms of the enum_instances method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_enumInstances called...') model = pywbem.CIMInstance(classname=objPath.classname, path=objPath) gen = self.enum_instances(env=env, model=model, keys_only=False) try: iter(gen) except TypeError: logger.log_debug('CIMProvider2 MI_enumInstances returning') return return gen def MI_getInstance(self, env, instanceName, propertyList): """Return a specific CIM instance Implements the WBEM operation GetInstance in terms of the get_instance method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_getInstance called...') plist = None if propertyList is not None: plist = [s.lower() for s in propertyList] plist+= [s.lower() for s in instanceName.keybindings.keys()] model = pywbem.CIMInstance(classname=instanceName.classname, path=instanceName, property_list=plist) model.update(model.path.keybindings) rval = self.get_instance(env=env, model=model) logger.log_debug('CIMProvider2 MI_getInstance returning') if rval is None: raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "") return rval def MI_createInstance(self, env, instance): """Create a CIM instance, and return its instance name Implements the WBEM operation CreateInstance in terms of the set_instance method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_createInstance called...') rval = None ''' ch = env.get_cimom_handle() cimClass = ch.GetClass(instance.classname, instance.path.namespace, LocalOnly=False, IncludeQualifiers=True) ''' # CIMOM has already filled in default property values for # props with default values, if values not supplied by client. rval = self.set_instance(env=env, instance=instance, modify_existing=False) logger.log_debug('CIMProvider2 MI_createInstance returning') return rval.path def MI_modifyInstance(self, env, modifiedInstance, propertyList): """Modify a CIM instance Implements the WBEM operation ModifyInstance in terms of the set_instance method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_modifyInstance called...') plist = None if propertyList is not None: plist = [s.lower() for s in propertyList] plist+= [s.lower() for s in modifiedInstance.path.keybindings.keys()] self.filter_instance(modifiedInstance, plist) modifiedInstance.property_list = plist modifiedInstance.update(modifiedInstance.path) self.set_instance(env=env, instance=modifiedInstance, modify_existing=True) logger.log_debug('CIMProvider2 MI_modifyInstance returning') def MI_deleteInstance(self, env, instanceName): """Delete a CIM instance Implements the WBEM operation DeleteInstance in terms of the delete_instance method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_deleteInstance called...') self.delete_instance(env=env, instance_name=instanceName) logger.log_debug('CIMProvider2 MI_deleteInstance returning') def MI_associators(self, env, objectName, assocClassName, resultClassName, role, resultRole, propertyList): """Return instances associated to a given object. Implements the WBEM operation Associators in terms of the references method. A derived class will not normally override this method. """ # NOTE: This should honor the parameters resultClassName, role, resultRole, # and propertyList logger = env.get_logger() logger.log_debug('CIMProvider2 MI_associators called. assocClass: %s' % (assocClassName)) if not assocClassName: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Empty assocClassName passed to Associators") ch = env.get_cimom_handle() model = pywbem.CIMInstance(classname=assocClassName) model.path = pywbem.CIMInstanceName(classname=assocClassName, namespace=objectName.namespace) gen = self.references(env=env, object_name=objectName, model=model, result_class_name=resultClassName, role=role, result_role=None, keys_only=False) if gen is None: logger.log_debug('references() returned None instead of generator object') return for inst in gen: for prop in inst.properties.values(): lpname = prop.name.lower() if prop.type != 'reference': continue if role and role.lower() == lpname: continue if resultRole and resultRole.lower() != lpname: continue if self.paths_equal(prop.value, objectName): continue if resultClassName and \ resultClassName.lower() != prop.value.classname.lower(): continue try: if prop.value.namespace is None: prop.value.namespace = objectName.namespace inst = ch.GetInstance(prop.value, propertyList) except pywbem.CIMError, (num, msg): if num == pywbem.CIM_ERR_NOT_FOUND: continue else: raise if inst.path is None: inst.path = prop.value yield inst logger.log_debug('CIMProvider2 MI_associators returning') def MI_associatorNames(self, env, objectName, assocClassName, resultClassName, role, resultRole): """Return instances names associated to a given object. Implements the WBEM operation AssociatorNames in terms of the references method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_associatorNames called. assocClass: %s' % (assocClassName)) if not assocClassName: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Empty assocClassName passed to AssociatorNames") model = pywbem.CIMInstance(classname=assocClassName) model.path = pywbem.CIMInstanceName(classname=assocClassName, namespace=objectName.namespace) gen = self.references(env=env, object_name=objectName, model=model, result_class_name=resultClassName, role=role, result_role=None, keys_only=False) if gen is None: logger.log_debug('references() returned None instead of generator object') return for inst in gen: for prop in inst.properties.values(): lpname = prop.name.lower() if prop.type != 'reference': continue if role and role.lower() == lpname: continue if resultRole and resultRole.lower() != lpname: continue if self.paths_equal(prop.value, objectName): continue if resultClassName and \ resultClassName.lower() != prop.value.classname.lower(): continue if prop.value.namespace is None: prop.value.namespace = objectName.namespace yield prop.value logger.log_debug('CIMProvider2 MI_associatorNames returning') def MI_references(self, env, objectName, resultClassName, role, propertyList): """Return instances of an association class. Implements the WBEM operation References in terms of the references method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_references called. resultClass: %s' % (resultClassName)) if not resultClassName: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Empty resultClassName passed to References") plist = None if propertyList is not None: plist = [s.lower() for s in propertyList] model = pywbem.CIMInstance(classname=resultClassName, property_list=plist) model.path = pywbem.CIMInstanceName(classname=resultClassName, namespace=objectName.namespace) if role: if role in model.properties: model[role] = objectName gen = self.references(env=env, object_name=objectName, model=model, result_class_name='', role=role, result_role=None, keys_only=False) if gen is None: logger.log_debug('references() returned None instead of generator object') return for inst in gen: for prop in inst.properties.values(): if hasattr(prop.value, 'namespace') and \ prop.value.namespace is None: prop.value.namespace = objectName.namespace yield inst logger.log_debug('CIMProvider2 MI_references returning') def MI_referenceNames(self, env, objectName, resultClassName, role): """Return instance names of an association class. Implements the WBEM operation ReferenceNames in terms of the references method. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_referenceNames <2> called. resultClass: %s' % (resultClassName)) if not resultClassName: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Empty resultClassName passed to ReferenceNames") model = pywbem.CIMInstance(classname=resultClassName) model.path = pywbem.CIMInstanceName(classname=resultClassName, namespace=objectName.namespace) if role: if role in model.properties: model[role] = objectName gen = self.references(env=env, object_name=objectName, model=model, result_class_name='', role=role, result_role=None, keys_only=True) if gen is None: logger.log_debug('references() returned None instead of generator object') return for inst in gen: for prop in inst.properties.values(): if hasattr(prop.value, 'namespace') and prop.value.namespace is None: prop.value.namespace = objectName.namespace yield inst.path logger.log_debug('CIMProvider2 MI_referenceNames returning') def MI_invokeMethod(self, env, objectName, methodName, inputParams): """Invoke an extrinsic method. Implements the InvokeMethod WBEM operation by calling the method on a derived class called cim_method_, where is the name of the CIM method, in all lower case. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) objectName -- The InstanceName or ClassName of the object on which the method is invoked. methodName -- The name of the method to be invoked. inputParams -- A Dictionary where the key is the parameter name and the value is the parameter value. The return value for invokeMethod must be a tuple of size 2 where: element 0 is a tuple of size 2 where element 0 is the return data type name and element 1 is the actual data value. element 1 is a dictionary where the key is the output parameter name and the value is a tuple of size 2 where element 0 is the data type name for the output parameter and element 1 is the actual value of the output parameter. A derived class will not normally override this method. """ logger = env.get_logger() logger.log_debug('CIMProvider2 MI_invokeMethod called. method: %s:%s' \ % (objectName.classname,methodName)) lmethName = "cim_method_%s" % methodName.lower() if hasattr(self, lmethName) : method = getattr(self, lmethName) new_inputs = dict([('param_%s' % k.lower(), v) \ for k, v in inputParams.items()]) try: (rval, outs) = method(env=env, object_name=objectName, **new_inputs) except TypeError, e: raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, str(e)) def add_type(v): if isinstance(v, pywbem.CIMParameter): return (v.type, v.value) lv = v if type(v) == list and len(v) > 0: lv = v[0] if isinstance(lv, pywbem.CIMClass): tp = 'class' elif isinstance(lv, pywbem.CIMInstance): tp = 'instance' elif isinstance(lv, pywbem.CIMInstanceName): tp = 'reference' elif v is None or (type(v) == list and len(v) == 0): assert(None == 'This should not happen') else: tp = pywbem.cimtype(v) return (tp, v) louts = {} for op in outs: louts[op.name] = (op.type, op.value) rval = add_type(rval) rval = (rval, louts) else: raise pywbem.CIMError(pywbem.CIM_ERR_METHOD_NOT_FOUND, "%s:%s"%(objectName.classname, methodName)) logger.log_debug('CIMProvider2 MI_invokeMethod returning') return rval def filter_instance(self, inst, plist): """Remove properties from an instance that aren't in the PropertyList inst -- The CIMInstance plist -- The property List, or None. The list items must be all lowercase. """ if plist is not None: for pname in inst.properties.keys(): if pname.lower() not in plist and pname: if inst.path is not None and pname in inst.path.keybindings: continue del inst.properties[pname] def authorize_filter (env, filter, ns, classes, owner): """Allow or disallow an indication subscription request. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) filter -- The WQL select statement namespace -- The namepace where the indication is registered for classes -- The classpath of the indication registered for owner -- The name of the principal (cimom user) """ pass def activate_filter (env, filter, ns, classes, first_activation): """Activate an indication subscription. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) filter -- The WQL select statement namespace -- The namepace where the indication is registered for classes -- The classpath of the indication registered for first_activation -- boolean - whether first activation """ pass def deactivate_filter(env, filter, ns, classes, last_activation): """Deactivate an indication subscription. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) filter -- The WQL select statement ns -- The namepace where the indication is registered for classes -- The classpath of the indication registered for last_activation -- boolean - whether last activation """ pass def enable_indications(env): """Enable indications. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) """ pass def disable_indications(env): """Disable indications. Arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) """ pass def codegen (cc): """Generate a Python Provider template. Parameters: cc - A CIMClass to generate code for. Returns a two-tuple containing the Python provider code stubs, and the provider registration MOF. """ import inspect def format_desc (obj, indent): linelen = 75 - indent if isinstance(obj, basestring): raw = obj else: try: raw = obj.qualifiers['description'].value except KeyError: return '' txt = '' beg = 0 end = 0 while beg < len(raw): beg = end end += linelen while beg < len(raw) and raw[beg].isspace(): beg = beg+1 while end < len(raw) and end > beg and not raw[end].isspace(): end = end-1 if beg == end: # a long URL while end < len(raw) and not raw[end].isspace(): end+= 1 line = raw[beg:end] line = line.replace('\n',' ') line = line.replace('\r','') txt += '\n%s%s'% (''.ljust(indent), line) return txt ################# def map_value(obj, val): rv = str(val) if 'ValueMap' not in obj.qualifiers: return rv if 'Values' not in obj.qualifiers: return rv vals = [str(x) for x in obj.qualifiers['Values'].value] maps = [str(x) for x in obj.qualifiers['ValueMap'].value] d = dict(zip(maps, vals)) try: tmp = d[str(val)] rv = '' for ch in tmp: rv+= ch.isalnum() and ch or '_' except KeyError: pass return rv ################# def type_hint (obj, method_name=None): if hasattr(obj, 'type'): tx = obj.type if 'embeddedinstance' in obj.qualifiers: tx = "pywbem.CIMInstance(classname='%s', ...)" % \ obj.qualifiers['embeddedinstance'].value elif tx == 'reference': tx = "pywbem.CIMInstanceName(classname='%s', ...)" % \ obj.reference_class else: tx = obj.return_type if hasattr(obj, 'value') and obj.value is not None: defval = str(obj.value) else: defval = '' if not tx.startswith('pywbem.'): if tx == 'boolean': tx = 'bool(%s)' % defval elif tx == 'datetime': tx = 'pywbem.CIMDateTime()' elif tx == 'string': tx = "''" else: tx = 'pywbem.%s(%s)' % (tx.capitalize(), defval) if 'valuemap' in obj.qualifiers: if defval: defval = map_value(obj, defval) else: defval = '' tx = 'self.Values.%s%s.%s' % \ (method_name and '%s.'%method_name or '', obj.name, defval) if hasattr(obj, 'is_array') and obj.is_array: tx = '[%s,]' % tx return tx ################# def type_str (obj, method_name=None): if hasattr(obj, 'type'): tx = obj.type if 'embeddedinstance' in obj.qualifiers: return "pywbem.CIMInstance(classname='%s', ...)" % \ obj.qualifiers['embeddedinstance'].value elif tx == 'reference': return "REF (pywbem.CIMInstanceName(classname='%s', ...)" % \ obj.reference_class else: tx = obj.return_type if tx == 'boolean': tx = 'bool' elif tx == 'datetime': tx = 'pywbem.CIMDateTime' elif tx == 'string': tx = 'unicode' else: tx = 'pywbem.%s' % tx.capitalize() if hasattr(obj, 'is_array') and obj.is_array: tx = '[%s,]' % tx if 'valuemap' in obj.qualifiers: tx+= ' self.Values.%s%s' % \ (method_name and '%s.'%method_name or '',obj.name) return tx ################# def is_required (obj): if 'required' in obj.qualifiers and obj.qualifiers['required'].value: return '(Required)' return '' ################# def build_reverse_val_map(obj): vm = obj.qualifiers['valuemap'].value if 'values' in obj.qualifiers: vals = obj.qualifiers['values'].value else: vals = vm tmap = zip(vals,vm) rv = {} for val, vm in tmap: try: vmi = int(vm) except ValueError: continue rv[vmi] = str(val) # we want normal strings, not unicode return rv ################# def build_val_map(obj): vm = obj.qualifiers['valuemap'].value if 'values' in obj.qualifiers: vals = obj.qualifiers['values'].value else: vals = vm tmap = zip(vals,vm) map = [] for t in tmap: nname = '' for ch in t[0]: if ch.isalnum(): nname+= ch else: nname+= '_' if hasattr(obj, 'return_type'): tp = obj.return_type else: tp = obj.type if tp == 'string': val = "'%s'" % t[1] else: try: int(t[1]) val = 'pywbem.%s(%s)' % (tp.capitalize(), t[1]) except ValueError: val = t[1] nname = "# "+nname map.append((nname,val)) return map valuemaps = {} rvaluemaps = pywbem.NocaseDict() for prop in cc.properties.values(): if 'valuemap' in prop.qualifiers and 'values' in prop.qualifiers: rvaluemaps[prop.name] = build_reverse_val_map(prop) for obj in cc.properties.values() + cc.methods.values(): if 'valuemap' in obj.qualifiers: valuemaps[obj.name] = {'':build_val_map(obj)} for meth in cc.methods.values(): for parm in meth.parameters.values(): if 'valuemap' in parm.qualifiers: if meth.name not in valuemaps: valuemaps[meth.name] = {} valuemaps[meth.name][parm.name] = build_val_map(parm) mappings = {'classname':cc.classname, 'classname_l':cc.classname.lower()} isAssoc = 'association' in cc.qualifiers isIndication = 'indication' in cc.qualifiers code = '''"""Python Provider for %(classname)s Instruments the CIM class %(classname)s """ import pywbem from pywbem.cim_provider2 import CIMProvider2 class %(classname)s(CIMProvider2): """Instrument the CIM class %(classname)s \n''' % mappings code+= format_desc(cc, 4) code+= ''' """''' args = inspect.getargspec(CIMProvider2.get_instance)[0] args = ', '.join(args) code+= ''' def __init__ (self, env): logger = env.get_logger() logger.log_debug('Initializing provider %%s from %%s' \\ %% (self.__class__.__name__, __file__)) def get_instance(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.get_instance()' \\ %% self.__class__.__name__) ''' % (args, CIMProvider2.get_instance.__doc__ ) keyProps = [p for p in cc.properties.values() \ if 'key' in p.qualifiers] if not keyProps and 'association' in cc.qualifiers: # SFCB has problems with qualifiers on REF properties. # http://sourceforge.net/tracker/index.php?func=detail&aid=2104565&group_id=128809&atid=712784 keyProps = [p for p in cc.properties.values() \ if p.type == 'reference'] for prop in keyProps: prop.qualifiers['KEY'] = True code+= ''' # TODO fetch system resource matching the following keys:''' for kp in keyProps: code+= ''' # model['%s']''' % kp.name code+= '\n' props = cc.properties.values() props.sort() for prop in props: if 'key' in prop.qualifiers: continue line = "#model['%s'] = %s # TODO %s" % \ (prop.name, type_hint(prop), is_required(prop)) code+= ''' %s''' % line args = inspect.getargspec(CIMProvider2.enum_instances)[0] args = ', '.join(args) code+= ''' return model def enum_instances(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.enum_instances()' \\ %% self.__class__.__name__) ''' % (args, CIMProvider2.enum_instances.__doc__) keydict = dict([(str(kp.name), None) for kp in keyProps]) code+= ''' # Prime model.path with knowledge of the keys, so key values on # the CIMInstanceName (model.path) will automatically be set when # we set property values on the model. model.pa%s ''' % format_desc('th.update('+str(keydict)+')', 12).strip() code+= ''' while False: # TODO more instances? # TODO fetch system resource # Key properties''' for kp in keyProps: if kp.name == 'CreationClassName': line = "model['%s'] = '%s'" % (kp.name, cc.classname) else: line = "#model['%s'] = %s # TODO (type = %s)" % \ (kp.name, type_hint(kp), type_str(kp)) code+=''' %s''' % line code+=''' if keys_only: yield model else: try: yield self.get_instance(env, model) except pywbem.CIMError, (num, msg): if num not in (pywbem.CIM_ERR_NOT_FOUND, pywbem.CIM_ERR_ACCESS_DENIED): raise\n''' args = inspect.getargspec(CIMProvider2.set_instance)[0] args = ', '.join(args) code+= ''' def set_instance(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.set_instance()' \\ %% self.__class__.__name__) # TODO create or modify the instance raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement return instance''' % (args, CIMProvider2.set_instance.__doc__) args = inspect.getargspec(CIMProvider2.delete_instance)[0] args = ', '.join(args) code+= ''' def delete_instance(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.delete_instance()' \\ %% self.__class__.__name__) # TODO delete the resource raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement ''' % (args, CIMProvider2.delete_instance.__doc__) for method in cc.methods.values(): inParms = [ p for p in method.parameters.values() if \ 'in' in p.qualifiers and p.qualifiers['in'].value ] outParms = [ p for p in method.parameters.values() if \ 'out' in p.qualifiers and p.qualifiers['out'].value ] code+= ''' def cim_method_%s(self, env, object_name''' % method.name.lower() for p in inParms: if 'required' in p.qualifiers and p.qualifiers['required']: code+= ''',\n%sparam_%s''' % (''.rjust(len(method.name)+20), p.name.lower()) for p in inParms: if 'required' not in p.qualifiers or not p.qualifiers['required']: code+= ''',\n%sparam_%s=None'''%\ (''.rjust(len(method.name)+20), p.name.lower()) code+= '''): """Implements %s.%s()\n''' % (cc.classname, method.name) code+= format_desc(method, 8) code+= ''' Keyword arguments: env -- Provider Environment (pycimmb.ProviderEnvironment) object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName specifying the object on which the method %s() should be invoked.'''\ % method.name for p in inParms: code+= ''' param_%s -- The input parameter %s (type %s) %s''' \ % (p.name.lower(), p.name, type_str(p, method.name), is_required(p)) code+= format_desc(p, 12) code+=''' Returns a two-tuple containing the return value (type %s) and a list of CIMParameter objects representing the output parameters Output parameters:''' % type_str(method) if not outParms: code+= ' none' else: for p in outParms: code+=''' %s -- (type %s) %s''' % (p.name, type_str(p, method.name), is_required(p)) code+= format_desc(p, 12) code+=''' Possible Errors: CIM_ERR_ACCESS_DENIED CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized or otherwise incorrect parameters) CIM_ERR_NOT_FOUND (the target CIM Class or instance does not exist in the specified namespace) CIM_ERR_METHOD_NOT_AVAILABLE (the CIM Server is unable to honor the invocation request) CIM_ERR_FAILED (some other unspecified error occurred) """ logger = env.get_logger() logger.log_debug('Entering %%s.cim_method_%s()' \\ %% self.__class__.__name__) # TODO do something raise pywbem.CIMError(pywbem.CIM_ERR_METHOD_NOT_AVAILABLE) # Remove to implemented out_params = []''' % method.name.lower() for p in outParms: code+=''' #out_params+= [pywbem.CIMParameter('%s', type='%s', # value=%s)] # TODO''' % (p.name.lower(), p.type, type_hint(p, method.name)) code+=''' #rval = # TODO (type %s) return (rval, out_params) ''' % type_str(method) if isAssoc: args = inspect.getargspec(CIMProvider2.references)[0] args = format_desc(', '.join(args), 19).strip() code+= ''' def references(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.references()' \\ %% self.__class__.__name__) ch = env.get_cimom_handle()''' % \ (args, CIMProvider2.references.__doc__) refprops = [] for prop in cc.properties.values(): if prop.reference_class is not None: refprops.append((prop.name, prop.reference_class)) code+= '''\n # If you want to get references for free, implemented in terms # of enum_instances, just leave the code below unaltered.''' for i, refprop in enumerate(refprops): if i == 0: code+= ''' if ch.is_subclass(object_name.namespace, sub=object_name.classname, super='%s')''' % refprop[1] else: code+= ''' or \\ ch.is_subclass(object_name.namespace, sub=object_name.classname, super='%s')''' % refprop[1] code+=''': return self.simple_refs(env, object_name, model, result_class_name, role, result_role, keys_only) ''' code+=''' # If you are doing simple refs with the code above, remove the # remainder of this method. Or, remove the stuff above and # implement references below. You need to pick either the # above approach or the below, and delete the other. Otherwise # you'll get a SyntaxError on the first yield below. # Prime model.path with knowledge of the keys, so key values on # the CIMInstanceName (model.path) will automatically be set when # we set property values on the model. model.pa%s # This is a common pattern. YMMV''' % \ format_desc('th.update('+str(keydict)+')', 12).strip() for refprop in refprops: code+= ''' if (not role or role.lower() == '%(refpropnamel)s') and \\ ch.is_subclass(object_name.namespace, sub=object_name.classname, super='%(rolecname)s'): model['%(refpropname)s'] = object_name yield model # TODO: Add other REF properties. # Yield association instances where # object_name is %(refpropnamel)s. # Only appropriate if object_name.classname # is '%(rolecname)s' or a subclass.\n''' \ % {'refpropname':refprop[0], 'refpropnamel':refprop[0].lower(), 'rolecname':refprop[1]} if valuemaps: code+= ''' class Values(object):''' for group, maps in valuemaps.items(): code+= ''' class %s(object):''' % group if '' in maps: for value, vm in maps['']: if value in maps: value = value+'_' code+= ''' %s = %s''' % (value, vm) if group in rvaluemaps: code+= ''' _reverse_map = %s''' % repr(rvaluemaps[group]) for pname, vms in maps.items(): if pname == '': continue code+= ''' class %s(object):''' % pname for value, vm in vms: code+= ''' %s = %s''' % (value, vm) code+= '\n' code+= ''' ## end of class %(classname)sProvider ## get_providers() for associating CIM Class Name to python provider class name def get_providers(env): %(classname_l)s_prov = %(classname)s(env) return {'%(classname)s': %(classname_l)s_prov} ''' % mappings if isIndication: code+= ''' ## Indication support methods... ## Use these methods if this class will deliver indications. ## Remove these methods if this class will not deliver indications.''' args = inspect.getargspec(CIMProvider2.authorize_filter)[0] args = format_desc(', '.join(args), 19).strip() code+= ''' def authorize_filter(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.authorize_filter()' \\ %% self.__class__.__name__) ch = env.get_cimom_handle() #raise pywbem.CIMError(pywbem.CIM_ERR_***) to indicate failure #otherwise just fall through for success''' % \ (args, CIMProvider2.authorize_filter.__doc__ or "Doc Goes Here") args = inspect.getargspec(CIMProvider2.enable_indications)[0] args = format_desc(', '.join(args), 19).strip() code+= ''' def enable_indications(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.enable_indications()' \\ %% self.__class__.__name__) ch = env.get_cimom_handle() #raise pywbem.CIMError(pywbem.CIM_ERR_***) to indicate failure #otherwise just fall through for success''' % \ (args, CIMProvider2.enable_indications.__doc__ or "Doc Goes Here") args = inspect.getargspec(CIMProvider2.disable_indications)[0] args = format_desc(', '.join(args), 19).strip() code+= ''' def disable_indications(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.disable_indications()' \\ %% self.__class__.__name__) ch = env.get_cimom_handle() #raise pywbem.CIMError(pywbem.CIM_ERR_***) to indicate failure #otherwise just fall through for success''' % \ (args, CIMProvider2.disable_indications.__doc__ or "Doc Goes Here") args = inspect.getargspec(CIMProvider2.activate_filter)[0] args = format_desc(', '.join(args), 19).strip() code+= ''' def activate_filter(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.activate_filter()' \\ %% self.__class__.__name__) ch = env.get_cimom_handle() #raise pywbem.CIMError(pywbem.CIM_ERR_***) to indicate failure #otherwise just fall through for success''' % \ (args, CIMProvider2.activate_filter.__doc__ or "Doc Goes Here") args = inspect.getargspec(CIMProvider2.deactivate_filter)[0] args = format_desc(', '.join(args), 19).strip() code+= ''' def deactivate_filter(%s): """%s""" logger = env.get_logger() logger.log_debug('Entering %%s.deactivate_filter()' \\ %% self.__class__.__name__) ch = env.get_cimom_handle() #raise pywbem.CIMError(pywbem.CIM_ERR_***) to indicate failure #otherwise just fall through for success''' % \ (args, CIMProvider2.deactivate_filter.__doc__ or "Doc Goes Here") code+= ''' ## End of Indication Support Methods''' owtypes = ['1', 'Instance'] pegtypes = ['2', 'Instance'] sfcbtypes = 'instance' if isAssoc: owtypes[0]+= ',3' owtypes[1]+= ', Associator' pegtypes[0]+= ',3' pegtypes[1]+= ', Associator' sfcbtypes+= ' association' if cc.methods: owtypes[0]+= ',6' owtypes[1]+= ', Method' pegtypes[0]+= ',5' pegtypes[1]+= ', Method' sfcbtypes+= ' method' omitted = ''' // OpenWBEM Provider registration for %(classname)s instance of OpenWBEM_PyProviderRegistration { InstanceID = ""; // TODO NamespaceNames = {"root/cimv2"}; // TODO ClassName = "%(classname)s"; ProviderTypes = {%(owtypeNums)s}; // %(owtypeStrs)s ModulePath = "/usr/lib/pycim/%(classname)sProvider.py"; // TODO }; ''' mof =''' // SFCB Provider registration for %(classname)s [%(classname)s] provider: %(classname)s location: pyCmpiProvider type: %(sfcbtypes)s namespace: root/cimv2 // TODO // Pegasus Provider registration for %(classname)s instance of PG_ProviderModule { Name = "pyCmpiProvider_%(classname)s"; InterfaceType = "CMPI"; InterfaceVersion = "2.0.0"; Location = "pyCmpiProvider"; UserContext = 2; // Requestor Vendor = "TODO"; // TODO Version = "1.0"; }; instance of PG_Provider { Name = "%(classname)s"; ProviderModuleName = "pyCmpiProvider_%(classname)s"; }; instance of PG_ProviderCapabilities { CapabilityID = "%(classname)s"; ProviderModuleName = "pyCmpiProvider_%(classname)s"; ProviderName = "%(classname)s"; ClassName = "%(classname)s"; Namespaces = {"root/cimv2"}; // TODO ProviderType = {%(pegtypeNum)s}; // %(pegtypeStr)s };\n''' % {'classname': cc.classname, 'owtypeNums': owtypes[0], 'owtypeStrs': owtypes[1], 'pegtypeNum': pegtypes[0], 'pegtypeStr': pegtypes[1], 'sfcbtypes' : sfcbtypes} return code, mof class ProviderProxy(object): """Wraps a provider module, and routes requests into the module """ def __init__ (self, env, provid): self.env = env if isinstance(provid, types.ModuleType): self.provmod = provid self.provid = provid.__name__ self.filename = provid.__file__ else: logger = env.get_logger() logger.log_debug('Loading python provider at %s' %provid) self.provid = provid self._load_provider_source(logger) self._init_provider(env) def _init_provider (self, env): self.provregs = {} if hasattr(self.provmod, 'init'): self.provmod.init(env) if hasattr(self.provmod, 'get_providers'): self.provregs = pywbem.NocaseDict(self.provmod.get_providers(env)) def _load_provider_source (self, logger): self.provider_module_name = os.path.basename(self.provid)[:-3] # let providers import other providers in the same directory provdir = dirname(self.provid) if provdir not in sys.path: sys.path.append(provdir) try: self.provmod = sys.modules[self.provider_module_name] logger.log_debug('Provider %s already loaded, found in sys.modules' \ % self.provmod) except KeyError: try: # use full path in module name for uniqueness. logger.log_debug('Loading provider %s from source' % self.provid) fn = imp.find_module(self.provider_module_name, [provdir]) try: g_mod_lock.acquire() imp.acquire_lock() self.provmod = imp.load_module( self.provider_module_name, *fn) self.provmod.provmod_timestamp = \ os.path.getmtime(self.provid) finally: imp.release_lock() g_mod_lock.release() fn[0].close() except IOError, arg: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Error loading provider %s: %s" % (self.provid, arg)) self.filename = self.provmod.__file__ def _get_callable (self, classname, cname): """Return a function or method object appropriate to fulfill a request classname -- The CIM class name associated with the request. cname -- The function or method name to look for. """ callable = None if classname in self.provregs: provClass = self.provregs[classname] if hasattr(provClass, cname): callable = getattr(provClass, cname) elif hasattr(self.provmod, cname): callable = getattr(self.provmod, cname) if callable is None: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "No provider registered for %s or no callable for %s:%s on provider %s"%(classname, classname, cname, self.provid)) return callable def _reload_if_necessary (self, env): """Check timestamp of loaded python provider module, and if it has changed since load, then reload the provider module. """ try: mod = sys.modules[self.provider_module_name] except KeyError: mod = None if (mod is None or \ mod.provmod_timestamp != os.path.getmtime(self.provid)): logger = env.get_logger() logger.log_debug("Need to reload provider at %s" % self.provid) #first unload the module if self.provmod and hasattr(self.provmod, "shutdown"): self.provmod.shutdown(env) #now reload and reinit module try: del sys.modules[self.provider_module_name] except KeyError: pass try: self._load_provider_source(logger) self._init_provider(env) except IOError, arg: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Error loading provider %s: %s" % (provid, arg)) ############################################################################## # enumInstanceNames ############################################################################## def MI_enumInstanceNames (self, env, objPath): logger = env.get_logger() logger.log_debug('ProviderProxy MI_enumInstanceNames called...') self._reload_if_necessary(env) return self._get_callable(objPath.classname, 'MI_enumInstanceNames')(env, objPath) ############################################################################## # enumInstances ############################################################################## def MI_enumInstances(self, env, objPath, propertyList): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_enumInstances called...') self._reload_if_necessary(env) return self._get_callable(objPath.classname, 'MI_enumInstances') \ (env, objPath, propertyList) ############################################################################## # getInstance ############################################################################## def MI_getInstance(self, env, instanceName, propertyList): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_getInstance called...') self._reload_if_necessary(env) rval = self._get_callable(instanceName.classname, 'MI_getInstance') \ (env, instanceName, propertyList) logger.log_debug('CIMProvider2 MI_getInstance returning') return rval ############################################################################## # createInstance ############################################################################## def MI_createInstance(self, env, instance): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_createInstance called...') self._reload_if_necessary(env) rval = self._get_callable(instance.classname, 'MI_createInstance') \ (env, instance) logger.log_debug('CIMProvider2 MI_createInstance returning') return rval ############################################################################## # modifyInstance ############################################################################## def MI_modifyInstance(self, env, modifiedInstance, propertyList): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_modifyInstance called...') self._reload_if_necessary(env) self._get_callable(modifiedInstance.classname, 'MI_modifyInstance') \ (env, modifiedInstance, propertyList) logger.log_debug('CIMProvider2 MI_modifyInstance returning') ############################################################################## # deleteInstance ############################################################################## def MI_deleteInstance(self, env, instanceName): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_deleteInstance called...') self._reload_if_necessary(env) self._get_callable(instanceName.classname, 'MI_deleteInstance') \ (env, instanceName) logger.log_debug('CIMProvider2 MI_deleteInstance returning') ############################################################################## # associators ############################################################################## def MI_associators(self, env, objectName, assocClassName, resultClassName, role, resultRole, propertyList): # NOTE: This should honor the parameters resultClassName, role, resultRole, # and propertyList logger = env.get_logger() logger.log_debug('CIMProvider2 MI_associators called. assocClass: %s' % (assocClassName)) self._reload_if_necessary(env) cname = assocClassName if not cname and hasattr(self.provmod, 'MI_associators'): for i in self.provmod.MI_associators( env, objectName, assocClassName, resultClassName, role, resultRole, propertyList): yield i return lcnames = [] if cname: lcnames = [cname] else: lcnames = self.provregs.keys() for lcname in lcnames: fn = self._get_callable(lcname, 'MI_associators') for i in fn(env, objectName, lcname, resultClassName, role, resultRole, propertyList): yield i logger.log_debug('CIMProvider2 MI_associators returning') ############################################################################## # associatorNames ############################################################################## def MI_associatorNames(self, env, objectName, assocClassName, resultClassName, role, resultRole): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_associatorNames called. assocClass: %s' % (assocClassName)) self._reload_if_necessary(env) cname = assocClassName if not cname and hasattr(self.provmod, 'MI_associatorNames'): for i in self.provmod.MI_associatorNames( env, objectName, assocClassName, resultClassName, role, resultRole): yield i return lcnames = [] if cname: lcnames = [cname] else: lcnames = self.provregs.keys() for lcname in lcnames: fn = self._get_callable(lcname, 'MI_associatorNames') for i in fn(env, objectName, lcname, resultClassName, role, resultRole): yield i logger.log_debug('CIMProvider2 MI_associatorNames returning') ############################################################################## # references ############################################################################## def MI_references(self, env, objectName, resultClassName, role, propertyList): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_references called. resultClass: %s' % (resultClassName)) self._reload_if_necessary(env) cname = resultClassName if not cname and hasattr(self.provmod, 'MI_references'): for i in self.provmod.MI_references(env, objectName, resultClassName, role, propertyList): yield i return lcnames = [] if cname: lcnames = [cname] else: lcnames = self.provregs.keys() for lcname in lcnames: fn = self._get_callable(lcname, 'MI_references') for i in fn(env, objectName, lcname, role, propertyList): yield i logger.log_debug('CIMProvider2 MI_references returning') ############################################################################## # referenceNames ############################################################################## def MI_referenceNames(self, env, objectName, resultClassName, role): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_referenceNames <1> called. resultClass: %s' % (resultClassName)) self._reload_if_necessary(env) cname = resultClassName if not cname and hasattr(self.provmod, 'MI_referenceNames'): for i in self.provmod.MI_referenceNames(env, objectName, resultClassName, role): yield i return lcnames = [] if cname: lcnames = [cname] else: lcnames = self.provregs.keys() for lcname in lcnames: fn = self._get_callable(lcname, 'MI_referenceNames') for i in fn(env, objectName, lcname, role): yield i logger.log_debug('CIMProvider2 MI_referenceNames returning') ############################################################################## # invokeMethod # inputParam is a Dictionary where the key is the parameter name # and the value is the parameter value # The return value for invokeMethod must be a tuple of size 2 where # element 0 is a tuple of size 2 where element 0 is the return data type name # and element 1 is the actual data value # element 1 is a dictionary where the key is the output parameter name # and the value is a tuple of size 2 where element 0 is the data type name # for the output parameter and element 1 is the actual value of the # output parameter. ############################################################################## def MI_invokeMethod(self, env, objectName, methodName, inputParams): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_invokeMethod called. method: %s:%s' \ % (objectName.classname,methodName)) self._reload_if_necessary(env) rval = self._get_callable(objectName.classname, 'MI_invokeMethod') \ (env, objectName, methodName, inputParams) logger.log_debug('CIMProvider2 MI_invokeMethod returning') return rval ############################################################################## def MI_authorizeFilter (self, env, filter, classname, classPath, owner): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_authorizeFilter called') self._reload_if_necessary(env) if hasattr(self.provmod, 'authorize_filter'): self.provmod.authorize_filter(env, filter, classname, classPath, owner) elif hasattr(self.provmod, 'MI_authorizeFilter'): self.provmod.MI_authorizeFilter(env, filter, classname, classPath, owner) else: # if not instrumented in provider, assume success logger.log_debug("Provider %s has no support for authorize filter"%self.provid) logger.log_debug('CIMProvider2 MI_authorizeFilter returning') return ############################################################################## def MI_activateFilter (self, env, filter, namespace, classes, firstActivation): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_activateFilter called') self._reload_if_necessary(env) if hasattr(self.provmod, 'activate_filter'): self.provmod.activate_filter(env, filter, namespace, classes, firstActivation) elif hasattr(self.provmod, 'MI_activateFilter'): self.provmod.MI_activateFilter(env, filter, namespace, classes, firstActivation) else: # if not instrumented in provider, assume success logger.log_debug("Provider %s has no support for activate filter"%self.provid) logger.log_debug('CIMProvider2 MI_activateFilter returning') return ############################################################################## def MI_deActivateFilter(self, env, filter, namespace, classes, lastActivation): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_deActivateFilter called') self._reload_if_necessary(env) if hasattr(self.provmod, 'deactivate_filter'): self.provmod.deactivate_filter(env, filter, namespace, classes, lastActivation) elif hasattr(self.provmod, 'MI_deActivateFilter'): self.provmod.MI_deActivateFilter(env, filter, namespace, classes, lastActivation) else: # if not instrumented in provider, assume success logger.log_debug("Provider %s has no support for deactivate filter"%self.provid) logger.log_debug('CIMProvider2 MI_deActivateFilter returning') return ############################################################################## def MI_enableIndications(self, env): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_enableIndications called') self._reload_if_necessary(env) if hasattr(self.provmod, 'enable_indications'): self.provmod.enable_indications(env) elif hasattr(self.provmod, 'MI_enableIndications'): self.provmod.MI_enableIndications(env) else: # if not instrumented in provider, assume success logger.log_debug("Provider %s has no support for enable indications"%self.provid) logger.log_debug('CIMProvider2 MI_enableIndications returning') return ############################################################################## def MI_disableIndications(self, env): logger = env.get_logger() logger.log_debug('CIMProvider2 MI_disableIndications called') self._reload_if_necessary(env) if hasattr(self.provmod, 'disable_indications'): self.provmod.disable_indications(env) elif hasattr(self.provmod, 'MI_disableIndications'): self.provmod.MI_disableIndications(env) else: # if not instrumented in provider, assume success logger.log_debug("Provider %s has no support for disable indications"%self.provid) logger.log_debug('CIMProvider2 MI_disableIndications returning') return ############################################################################## def MI_shutdown (self, env): # shutdown may be called multiple times -- once per MI type # (instance/method/association/...) We'll only do stuff on # the first time. if self.provmod is None: return modname = self.provmod.__name__ if hasattr(self.provmod, "shutdown"): self.provmod.shutdown(env) self.provmod = None del sys.modules[modname] #TODO concurrency problems here?? ############################################################################## def MI_canunload(self, env): if hasattr(self.provmod, "can_unload"): return self.provmod.can_unload(env) else: return True ############################################################################## def MI_consumeIndication(self, env, destinationPath, indicationInstance): logger = env.get_logger() logger.log_debug('ProviderProxy MI_consumeIndication called') self._reload_if_necessary(env) if hasattr(self.provmod, 'consume_indication'): self.provmod.consume_indication(env, destinationPath, indicationInstance) elif hasattr(self.provmod, 'MI_consumeIndication'): self.provmod.MI_consumeIndication(env, destinationPath, indicationInstance) else: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Provider %s has no support for consume indication" % \ self.provid) logger.log_debug('ProviderProxy MI_consumeIndication returning') ############################################################################## def MI_handleIndication(self, env, ns, handlerInstance, indicationInstance): logger = env.get_logger() logger.log_debug('ProviderProxy MI_handleIndication called') self._reload_if_necessary(env) if hasattr(self.provmod, 'handle_indication'): self.provmod.handle_indication(env, ns, handlerInstance, indicationInstance) elif hasattr(self.provmod, 'MI_handleIndication'): self.provmod.MI_handleIndication(env, ns, handlerInstance, indicationInstance) else: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Provider %s has no support for handle indication"%self.provid) logger.log_debug('ProviderProxy MI_handleIndication returning') pywbem-0.8.0~dev/pywbem/wbemcli.py0000755000175000017500000001751112413747174017132 0ustar bzedbzed00000000000000#!/usr/bin/python # (C) Copyright 2008 Hewlett-Packard Development Company, L.P. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # Author: Tim Potter # # A small utility to wrap up a PyWBEM session in a Python interactive # console. # # Usage: # # wbemcli.py HOSTNAME [-u USERNAME -p PASSWORD] [-n namespace] [--no-ssl] \ # [--port PORT] # # CIM operations can be executed by using the PyWBEM connection object # called 'cli' in the global scope. There are two sets of aliases # available for usage in the interpreter. For example the following # three commands are equivalent: # # >>> cli.EnumerateInstanceNames('SMX_ComputerSystem') # >>> EnumerateInstanceNames('SMX_ComputerSystem') # >>> ein('SMX_ComputerSystem') # # Pretty-printing of results is also available using the 'pp' # function. For example: # # >>> cs = ei('SMX_ComputerSystem')[0] # >>> pp(cs.items()) # [(u'RequestedState', 12L), # (u'Dedicated', [1L]), # (u'StatusDescriptions', [u'System is Functional']), # (u'IdentifyingNumber', u'6F880AA1-F4F5-11D5-8C45-C0116FBAE02A'), # ... # import os, stat, sys, string, getpass, errno from pywbem import * from code import InteractiveConsole from optparse import OptionParser from pprint import pprint as pp # Conditional support of readline module have_readline = False try: import readline have_readline = True except ImportError, arg: pass # # Parse command line args # optparser = OptionParser( usage = '%prog HOSTNAME [-u USER -p PASS] [-n NAMESPACE] [--no-ssl]') # Username and password optparser.add_option('-u', '--user', dest = 'user', action = 'store', type = 'string', help = 'user to connect as') optparser.add_option('-p', '--password', dest = 'password', action = 'store', type = 'string', help = 'password to connect user as') # Change the default namespace used optparser.add_option('-n', '--namespace', dest = 'namespace', action = 'store', type = 'string', default = 'root/cimv2', help = 'default namespace to use') # Don't use SSL for remote connections optparser.add_option('--no-ssl', dest = 'no_ssl', action = 'store_true', help = 'don\'t use SSL') # Specify non-standard port optparser.add_option('--port', dest = 'port', action = 'store', type = 'int', help = 'port to connect as', default = None) # Check usage (opts, argv) = optparser.parse_args() if len(argv) != 1: optparser.print_usage() sys.exit(1) # # Set up a client connection # def remote_connection(): """Initiate a remote connection, via PyWBEM.""" if argv[0][0] == '/': url = argv[0] else: proto = 'https' if opts.no_ssl: proto = 'http' url = '%s://%s' % (proto, argv[0]) if opts.port is not None: url += ':%d' % opts.port creds = None if opts.user is not None and opts.password is None: opts.password = getpass.getpass('Enter password for %s: ' % opts.user) if opts.user is not None or opts.password is not None: creds = (opts.user, opts.password) cli = WBEMConnection(url, creds, default_namespace = opts.namespace) cli.debug = True return cli cli = remote_connection() # # Create some convenient global functions to reduce typing # def EnumerateInstanceNames(classname, namespace = None): """Enumerate the names of the instances of a CIM Class (including the names of any subclasses) in the target namespace.""" return cli.EnumerateInstanceNames(classname, namespace = namespace) def EnumerateInstances(classname, namespace = None, LocalOnly = True, DeepInheritance = True, IncludeQualifiers = False, IncludeClassOrigin = False): """Enumerate instances of a CIM Class (includeing the instances of any subclasses in the target namespace.""" return cli.EnumerateInstances(classname, namespace = namespace, DeepInheritance = DeepInheritance, IncludeQualifiers = IncludeQualifiers, IncludeClassOrigin = IncludeClassOrigin) def GetInstance(instancename, LocalOnly = True, IncludeQualifiers = False, IncludeClassOrigin = False): """Return a single CIM instance corresponding to the instance name given.""" return cli.GetInstance(instancename, LocalOnly = LocalOnly, IncludeQualifiers = IncludeQualifiers, IncludeClassOrigin = IncludeClassOrigin) def DeleteInstance(instancename): """Delete a single CIM instance.""" return cli.DeleteInstance(instancename) def ModifyInstance(*args, **kwargs): return cli.ModifyInstance(*args, **kwargs) def CreateInstance(*args, **kwargs): return cli.CreateInstance(*args, **kwargs) def InvokeMethod(*args, **kwargs): return cli.InvokeMethod(*args, **kwargs) def AssociatorNames(*args, **kwargs): return cli.AssociatorNames(*args, **kwargs) def Associators(*args, **kwargs): return cli.Associators(*args, **kwargs) def ReferenceNames(*args, **kwargs): return cli.ReferenceNames(*args, **kwargs) def References(*args, **kwargs): return cli.References(*args, **kwargs) def EnumerateClassNames(*args, **kwargs): return cli.EnumerateClassNames(*args, **kwargs) def EnumerateClasses(*args, **kwargs): return cli.EnumerateClasses(*args, **kwargs) def GetClass(*args, **kwargs): return cli.GetClass(*args, **kwargs) def DeleteClass(*args, **kwargs): return cli.DeleteClass(*args, **kwargs) def ModifyClass(*args, **kwargs): return cli.ModifyClass(*args, **kwargs) def CreateClass(*args, **kwargs): return cli.CreateClass(*args, **kwargs) def EnumerateQualifiers(*args, **kwargs): return cli.EnumerateQualifiers(*args, **kwargs) def GetQualifier(*args, **kwargs): return cli.GetQualifier(*args, **kwargs) def SetQualifier(*args, **kwargs): return cli.SetQualifier(*args, **kwargs) def DeleteQualifier(*args, **kwargs): return cli.DeleteQualifier(*args, **kwargs) # Aliases for global functions above ein = EnumerateInstanceNames ei = EnumerateInstances gi = GetInstance di = DeleteInstance mi = ModifyInstance ci = CreateInstance im = InvokeMethod an = AssociatorNames ao = Associators rn = ReferenceNames re = References ecn = EnumerateClassNames ec = EnumerateClasses gc = GetClass dc = DeleteClass mc = ModifyClass cc = CreateClass eq = EnumerateQualifiers gq = GetQualifier sq = SetQualifier dq = DeleteQualifier # # Enter interactive console # def get_banner(): result = '' # Note how we are connected result += 'Connected to %s' % cli.url if cli.creds is not None: result += ' as %s' % cli.creds[0] return result # Read previous command line history histfile = '%s/.wbemcli_history' % os.environ['HOME'] try: if have_readline: readline.read_history_file(histfile) except IOError, arg: if arg[0] != errno.ENOENT: raise # Interact i = InteractiveConsole(globals()) i.interact(get_banner()) # Save command line history if have_readline: readline.write_history_file(histfile) pywbem-0.8.0~dev/PKG-INFO0000644000175000017500000000045712413747232014721 0ustar bzedbzed00000000000000Metadata-Version: 1.0 Name: pywbem Version: 0.8.0~dev Summary: Python WBEM client library Home-page: http://pywbem.sf.net/ Author: Tim Potter Author-email: tpot@hp.com License: LGPLv2 Description: A pure-Python library for performing operations using the WBEM management protocol. Platform: any pywbem-0.8.0~dev/setup.py0000644000175000017500000000340112413747174015333 0ustar bzedbzed00000000000000'''A pure-Python library for performing operations using the WBEM management protocol.''' # # (C) Copyright 2004 Hewlett-Packard Development Company, L.P. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Author: Tim Potter from distutils.core import setup, Extension import sys, string, os import shutil # Build the lex/yacc table .py files from pywbem import mof_compiler mof_compiler._build() # Get package version from __init__.py init_py = os.path.abspath(os.path.join( os.path.dirname(sys.argv[0]), 'pywbem/__init__.py')) init_globals = {} execfile(init_py, init_globals) # defines __version__ args = { 'name': 'pywbem', 'author': 'Tim Potter', 'author_email': 'tpot@hp.com', 'description': 'Python WBEM client library', 'long_description': __doc__, 'platforms': ['any'], 'url': 'http://pywbem.sf.net/', 'version': init_globals['__version__'], 'license': 'LGPLv2', 'packages': ['pywbem'], 'package_data': { 'pywbem': [ 'NEWS', 'LICENSE.txt', ] }, 'scripts': [ 'pywbem/wbemcli.py', 'pywbem/mof_compiler.py', ], } setup(**args) pywbem-0.8.0~dev/INSTALL0000644000175000017500000000341712413731640014650 0ustar bzedbzed00000000000000Installation PyWBEM can be installed quite easily using the standard Python distutils that is part of the Python distribution. The source for the installation can be a copy of the SVN code repository (for example, if you want to get the latest level of code in development), or a downloaded and unpacked distribution archive. From the pywbem/trunk directory of the copy of the SVN code repository, or from the unpack directory of the downloaded distribution archive, PyWBEM is installed with the following shell command. The command syntax is shown for Linux, but this works the same way on Windows and on other operating systems supported by Python. This copies the PyWBEM source to the Python site-packages directory where it can be loaded by the interpreter. On Linux, you need to have root rights: # python setup.py install running install running build running build_py running install_lib copying build/lib/pywbem/cim_xml.py -> /usr/lib/python [...] [...] If you do not have root access, or would like to install PyWBEM in a different directory, use the --install-lib option when installing: $ python setup.py install --install-lib $HOME/python/lib running install running build running build_py running install_lib creating /home/tpot/python/lib creating /home/tpot/python/lib/pywbem copying build/lib/pywbem/cim_xml.py -> /home/tpot/python/lib/pywbem [...] To test that PyWBEM is sucessfully installed, start up a Python interpreter and try to import the pywbem module: $ python Python 2.3.5 (#2, Mar 26 2005, 17:32:32) [GCC 3.3.5 (Debian 1:3.3.5-12)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import pywbem >>> If you do not see any text after the import command, PyWBEM has been sucessfully installed. pywbem-0.8.0~dev/README0000644000175000017500000000100412413746730014473 0ustar bzedbzed00000000000000PyWBEM provides a WBEM client library and some related utilities, written in pure Python. The WBEM client library allows issuing operations to a WBEM server, using the CIM operations over HTTP (CIM-XML) protocol defined in the DMTF standards DSP0200 and DSP0201. See http://www.dmtf.org/standards/wbem for information about WBEM. Please see the PyWBEM project at http://sourceforge.net/projects/pywbem/ for more details. It is licensed under the GNU LGPL v2. For installation instructions, see the INSTALL file.