Parse the field_safe parameter in Python's IDL parser
authordbs <dbs@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sat, 19 Mar 2011 03:06:58 +0000 (03:06 +0000)
committerdbs <dbs@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sat, 19 Mar 2011 03:06:58 +0000 (03:06 +0000)
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

index e875dd0..fd6f3e2 100644 (file)
@@ -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
+