From 45802f9c79eaa552a9e475a6a5c7ce2965274c15 Mon Sep 17 00:00:00 2001 From: dbs Date: Sat, 19 Mar 2011 03:06:58 +0000 Subject: [PATCH] Parse the field_safe parameter in Python's IDL parser Also set the correct namespace for the tablename attribute. The rest of the changes are for PEP8 compliance. We retain the IDLParser set_IDL() and parse_IDL() methods because things like constrictor call them directly, but note in the docstrings that they are deprecated names. git-svn-id: svn://svn.open-ils.org/ILS/trunk@19816 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/src/python/oils/utils/idl.py | 239 +++++++++++++++++++--------------- 1 file changed, 134 insertions(+), 105 deletions(-) diff --git a/Open-ILS/src/python/oils/utils/idl.py b/Open-ILS/src/python/oils/utils/idl.py index e875dd0694..fd6f3e2082 100644 --- a/Open-ILS/src/python/oils/utils/idl.py +++ b/Open-ILS/src/python/oils/utils/idl.py @@ -12,15 +12,17 @@ Typical usage: ... print oils.utils.idl.IDLParser.get_class('bre').tablename biblio.record_entry """ -import sys, string, xml.dom.minidom +import xml.dom.minidom #import osrf.net_obj, osrf.log, osrf.set, osrf.ex, osrf.ses import osrf.net_obj, osrf.log, osrf.ex, osrf.ses from oils.const import OILS_NS_OBJ, OILS_NS_PERSIST, OILS_NS_REPORTER, OILS_APP_ACTOR class IDLException(osrf.ex.OSRFException): + """Exception thrown when parsing the IDL file""" pass class IDLParser(object): + """Evergreen fieldmapper IDL file parser""" # ------------------------------------------------------------ # static methods and variables for managing a global parser @@ -43,8 +45,8 @@ class IDLParser(object): parser = IDLParser() idl_path = osrf.ses.ClientSession.atomic_request( OILS_APP_ACTOR, 'opensrf.open-ils.fetch_idl.file') - parser.set_IDL(idl_path) - parser.parse_IDL() + parser.set_idl(idl_path) + parser.parse_idl() IDLParser._global_parser = parser @staticmethod @@ -53,36 +55,37 @@ class IDLParser(object): network hint / IDL class name. @param The class ID from the IDL ''' - return IDLParser.get_parser().IDLObject[class_name] + return IDLParser.get_parser().idl_object[class_name] # ------------------------------------------------------------ # instance methods # ------------------------------------------------------------ def __init__(self): - self.IDLObject = {} + """Initializes the IDL object""" + self.idl_object = {} + self.idl_file = None - def set_IDL(self, file): - self.idlFile = file + def set_IDL(self, idlfile): + """Deprecated non-PEP8 version of set_idl()""" + self.set_idl(idlfile) - def _get_attr(self, node, name, ns=None): - """ Find the attribute value on a given node - Namespace is ignored for now.. - not sure if minidom has namespace support. - """ - attr = node.attributes.get(name) - if attr: - return attr.nodeValue - return None + def set_idl(self, idlfile): + """Specifies the filename or file that contains the IDL""" + self.idl_file = idlfile def parse_IDL(self): + """Deprecated non-PEP8 version of parse_idl()""" + self.parse_idl() + + def parse_idl(self): """Parses the IDL file and builds class, field, and link objects""" - # in case we're calling parse_IDL directly + # in case we're calling parse_idl directly if not IDLParser._global_parser: IDLParser._global_parser = self - doc = xml.dom.minidom.parse(self.idlFile) + doc = xml.dom.minidom.parse(self.idl_file) root = doc.documentElement for child in root.childNodes: @@ -95,119 +98,67 @@ class IDLParser(object): # ----------------------------------------------------------------------- obj = IDLClass( - self._get_attr(child, 'id'), - controller = self._get_attr(child, 'controller'), - fieldmapper = self._get_attr(child, 'oils_obj:fieldmapper', OILS_NS_OBJ), - virtual = self._get_attr(child, 'oils_persist:virtual', OILS_NS_PERSIST), - label = self._get_attr(child, 'reporter:label', OILS_NS_REPORTER), - tablename = self._get_attr(child, 'oils_persist:tablename', OILS_NS_REPORTER), + _attr(child, 'id'), + controller = _attr(child, 'controller'), + fieldmapper = _attr(child, 'oils_obj:fieldmapper', OILS_NS_OBJ), + virtual = _attr(child, 'oils_persist:virtual', OILS_NS_PERSIST), + label = _attr(child, 'reporter:label', OILS_NS_REPORTER), + tablename = _attr(child, 'oils_persist:tablename', OILS_NS_PERSIST), + field_safe = _attr(child, 'oils_persist:field_safe', OILS_NS_PERSIST), ) - - self.IDLObject[obj.name] = obj + self.idl_object[obj.name] = obj fields = [f for f in child.childNodes if f.nodeName == 'fields'] links = [f for f in child.childNodes if f.nodeName == 'links'] - fields = self.parse_fields(obj, fields[0]) + fields = _parse_fields(obj, fields[0]) if len(links) > 0: - self.parse_links(obj, links[0]) + _parse_links(obj, links[0]) - osrf.net_obj.register_hint(obj.name, [f.name for f in fields], 'array') + osrf.net_obj.register_hint( + obj.name, [f.name for f in fields], 'array' + ) doc.unlink() - def parse_links(self, idlobj, links): - - for link in [l for l in links.childNodes if l.nodeName == 'link']: - obj = IDLLink( - field = idlobj.get_field(self._get_attr(link, 'field')), - reltype = self._get_attr(link, 'reltype'), - key = self._get_attr(link, 'key'), - map = self._get_attr(link, 'map'), - class_ = self._get_attr(link, 'class') - ) - idlobj.links.append(obj) - - - def parse_fields(self, idlobj, fields): - """Takes the fields node and parses the included field elements""" - - idlobj.primary = self._get_attr(fields, 'oils_persist:primary', OILS_NS_PERSIST) - idlobj.sequence = self._get_attr(fields, 'oils_persist:sequence', OILS_NS_PERSIST) - - position = 0 - for field in [l for l in fields.childNodes if l.nodeName == 'field']: - - name = self._get_attr(field, 'name') - - if name in ['isnew', 'ischanged', 'isdeleted']: - continue - - obj = IDLField( - idlobj, - name = name, - position = position, - virtual = self._get_attr(field, 'oils_persist:virtual', OILS_NS_PERSIST), - label = self._get_attr(field, 'reporter:label', OILS_NS_REPORTER), - rpt_datatype = self._get_attr(field, 'reporter:datatype', OILS_NS_REPORTER), - rpt_select = self._get_attr(field, 'reporter:selector', OILS_NS_REPORTER), - primitive = self._get_attr(field, 'oils_persist:primitive', OILS_NS_PERSIST) - ) - - idlobj.fields.append(obj) - idlobj.field_map[obj.name] = obj - position += 1 - - for name in ['isnew', 'ischanged', 'isdeleted']: - obj = IDLField(idlobj, - name = name, - position = position, - virtual = 'true' - ) - idlobj.fields.append(obj) - position += 1 - - return idlobj.fields - - - class IDLClass(object): + """Represents a class in the fieldmapper IDL""" + def __init__(self, name, **kwargs): self.name = name self.controller = kwargs.get('controller') self.fieldmapper = kwargs.get('fieldmapper') - self.virtual = kwargs.get('virtual') + self.virtual = _to_bool(kwargs.get('virtual')) self.label = kwargs.get('label') self.tablename = kwargs.get('tablename') self.primary = kwargs.get('primary') self.sequence = kwargs.get('sequence') + self.field_safe = _to_bool(kwargs.get('field_safe')) self.fields = [] self.links = [] self.field_map = {} - if self.virtual and self.virtual.lower() == 'true': - self.virtual = True - else: - self.virtual = False - def __str__(self): ''' Stringify the parsed IDL ''' # TODO: improve the format/content - s = '-'*60 + '\n' - s += "%s [%s] %s\n" % (self.label, self.name, self.tablename) - s += '-'*60 + '\n' + idl = '-'*60 + '\n' + idl += "%s [%s] %s\n" % (self.label, self.name, self.tablename) + idl += '-'*60 + '\n' idx = 0 - for f in self.fields: - s += "[%d] " % idx - if idx < 10: s += " " - s += str(f) + '\n' + for field in self.fields: + idl += "[%d] " % idx + if idx < 10: + idl += " " + idl += str(field) + '\n' idx += 1 - return s + return idl def get_field(self, field_name): + """Return the specified field from the class""" + try: return self.field_map[field_name] except: @@ -216,6 +167,8 @@ class IDLClass(object): #raise IDLException(msg) class IDLField(object): + """Represents a field in a class in the fieldmapper IDL""" + def __init__(self, idl_class, **kwargs): ''' @param idl_class The IDLClass object which owns this field @@ -229,25 +182,30 @@ class IDLField(object): self.virtual = kwargs.get('virtual') self.position = kwargs.get('position') - if self.virtual and self.virtual.lower() == 'true': + if self.virtual and str(self.virtual).lower() == 'true': self.virtual = True else: self.virtual = False def __str__(self): ''' Format as field name and data type, plus linked class for links. ''' - s = self.name + field = self.name if self.rpt_datatype: - s += " [" + self.rpt_datatype + field += " [" + self.rpt_datatype if self.rpt_datatype == 'link': - link = [ l for l in self.idl_class.links if l.field.name == self.name ] + link = [ + l for l in self.idl_class.links + if l.field.name == self.name + ] if len(link) > 0 and link[0].class_: - s += " @%s" % link[0].class_ - s += ']' - return s + field += " @%s" % link[0].class_ + field += ']' + return field class IDLLink(object): + """Represents a link between objects defined in the IDL""" + def __init__(self, field, **kwargs): ''' @param field The IDLField object this link references @@ -257,3 +215,74 @@ class IDLLink(object): self.key = kwargs.get('key') self.map = kwargs.get('map') self.class_ = kwargs.get('class_') + +def _attr(node, name, namespace=None): + """ Find the attribute value on a given node + Namespace is ignored for now; + not sure if minidom has namespace support. + """ + attr = node.attributes.get(name) + if attr: + return attr.nodeValue + return None + +def _parse_links(idlobj, links): + """Parses the links between objects defined in the IDL""" + + for link in [l for l in links.childNodes if l.nodeName == 'link']: + obj = IDLLink( + field = idlobj.get_field(_attr(link, 'field')), + reltype = _attr(link, 'reltype'), + key = _attr(link, 'key'), + map = _attr(link, 'map'), + class_ = _attr(link, 'class') + ) + idlobj.links.append(obj) + +def _parse_fields(idlobj, fields): + """Takes the fields node and parses the included field elements""" + + idlobj.primary = _attr(fields, 'oils_persist:primary', OILS_NS_PERSIST) + idlobj.sequence = _attr(fields, 'oils_persist:sequence', OILS_NS_PERSIST) + + position = 0 + for field in [l for l in fields.childNodes if l.nodeName == 'field']: + + name = _attr(field, 'name') + + if name in ['isnew', 'ischanged', 'isdeleted']: + continue + + obj = IDLField( + idlobj, + name = name, + position = position, + virtual = _attr(field, 'oils_persist:virtual', OILS_NS_PERSIST), + label = _attr(field, 'reporter:label', OILS_NS_REPORTER), + rpt_datatype = _attr(field, 'reporter:datatype', OILS_NS_REPORTER), + rpt_select = _attr(field, 'reporter:selector', OILS_NS_REPORTER), + primitive = _attr(field, 'oils_persist:primitive', OILS_NS_PERSIST) + ) + + idlobj.fields.append(obj) + idlobj.field_map[obj.name] = obj + position += 1 + + for name in ['isnew', 'ischanged', 'isdeleted']: + obj = IDLField(idlobj, + name = name, + position = position, + virtual = 'true' + ) + idlobj.fields.append(obj) + position += 1 + + return idlobj.fields + +def _to_bool(field): + """Converts a string from the DOM into a boolean value. """ + + if field and str(field).lower() == 'true': + return True + return False + -- 2.11.0