def generate(self): doc = super(W3ObjectDocument, self).generate() tag = self.tag body = doc.find('body') # Convert the top Description section into body text with a TOC for # other sections, convert all <h3> elements into <h2> elements with a # blue bar style (to denote different section types) and add "Back to # top" links, all as per w3v8 sections = [ elem for elem in body[4][2] if elem.tag == 'div' and elem.attrib.get('class') == 'section' and iselement(elem.find('h3')) and 'id' in elem.attrib ] sections[0].remove(sections[0].find('h3')) sections[0].append( tag.ul( tag.li( tag.a(section.find('h3').text, href='#' + section.attrib['id'], title='Jump to section')) for section in sections[1:])) for section in sections[1:]: heading = section.find('h3') heading.tag = 'h2' heading.attrib['class'] = 'bar-blue-med' section.append(tag.p(tag.a('Back to top', href='#masthead'))) return doc
def __iter__(self): if isinstance(self.xml, basestring): root = fromstring(xml) elif hasattr(self.xml, 'read'): # Assume self.xml is a file-like object root = fromstring(self.xml.read()) if root.tag != 'database': raise Exception( 'Expected root element to be "database", but found "%s"' % root.tag) for schema in root.findall('schema'): if not 'name' in schema.attrib: raise Exception('Mandatory "name" attribute missing') for relation in schema.findall('relation'): if not 'name' in relation.attrib: raise Exception( 'Mandatory "name" attribute missing from relation in schema %s' % schema.attrib['name']) description = relation.find('description') if iselement(description): description = description.text or '' else: description = '' columns = dict((column.attrib['name'], column.text or '') for column in relation.findall('column')) yield (schema.attrib['name'], relation.attrib['name'], description, columns)
def generate(self): doc = super(W3ObjectDocument, self).generate() tag = self.tag body = doc.find('body') # Convert the top Description section into body text with a TOC for # other sections, convert all <h3> elements into <h2> elements with a # blue bar style (to denote different section types) and add "Back to # top" links, all as per w3v8 sections = [ elem for elem in body[4][2] if elem.tag == 'div' and elem.attrib.get('class') == 'section' and iselement(elem.find('h3')) and 'id' in elem.attrib ] sections[0].remove(sections[0].find('h3')) sections[0].append( tag.ul( tag.li(tag.a(section.find('h3').text, href='#' + section.attrib['id'], title='Jump to section')) for section in sections[1:] ) ) for section in sections[1:]: heading = section.find('h3') heading.tag = 'h2' heading.attrib['class'] = 'bar-blue-med' section.append(tag.p(tag.a('Back to top', href='#masthead'))) return doc
def generate(self): doc = super(PlainObjectDocument, self).generate() tag = self.tag body = doc.find('body') # Build a TOC from all <h3> elements contained in <div class="section"> # elements, and insert it after the page title i = 3 if self.site.search: i += 1 body[i:i] = [ tag.ul((tag.li( tag.a(elem.find('h3').text, href='#' + elem.attrib['id'], title='Jump to section')) for elem in body if iselement(elem) and elem.tag == 'div' and elem.attrib.get('class') == 'section' and iselement(elem.find('h3')) and 'id' in elem.attrib), id='toc') ] return doc
def text(value): """Utility routine for extracting text from a potential element. This routine is used to extract text from within an element, if one is found. If value is None, the result is None. Otherwise, the value is the text property of the provided element. """ if iselement(value): return value.text else: return None
def generate(self): doc = super(PlainObjectDocument, self).generate() tag = self.tag body = doc.find('body') # Build a TOC from all <h3> elements contained in <div class="section"> # elements, and insert it after the page title i = 3 if self.site.search: i += 1 body[i:i] = [ tag.ul( ( tag.li(tag.a(elem.find('h3').text, href='#' + elem.attrib['id'], title='Jump to section')) for elem in body if iselement(elem) and elem.tag == 'div' and elem.attrib.get('class') == 'section' and iselement(elem.find('h3')) and 'id' in elem.attrib ), id='toc' ) ] return doc
def get_datatypes(self): """Retrieves the details of datatypes stored in the database. Override this function to return a list of Datatype tuples containing details of the datatypes defined in the database (including system types). Datatype tuples have the following named fields: schema -- The schema of the datatype name -- The name of the datatype owner* -- The name of the user who owns the datatype system -- True if the type is system maintained (bool) created* -- When the type was created (datetime) description* -- Descriptive text variable_size -- True if the type has a variable length (e.g. VARCHAR) variable_scale -- True if the type has a variable scale (e.g. DECIMAL) source_schema* -- The schema of the base system type of the datatype source_name* -- The name of the base system type of the datatype size* -- The length of the type for character based types or the maximum precision for decimal types scale* -- The maximum scale for decimal types * Optional (can be None) """ for row in super(InputPlugin, self).get_datatypes(): yield row for schema in self.doc.findall('schema'): for datatype in schema.findall('datatype'): source = self.ids.get(datatype.attrib.get('source')) usertype = [None, True][iselement(source)] yield Datatype( schema.attrib['name'], datatype.attrib['name'], datatype.attrib.get('owner'), bool(datatype.attrib.get('system')), timestamp(datatype.attrib.get('created')), text(datatype.find('description')), datatype.attrib.get('variable') in ('size', 'scale'), datatype.attrib.get('variable') == 'scale', usertype and self.parents[source].attrib['name'], usertype and source.attrib['name'], usertype and datatype.attrib.get('size'), usertype and datatype.attrib.get('scale'), )
def __iter__(self): if isinstance(self.xml, basestring): root = fromstring(xml) elif hasattr(self.xml, 'read'): # Assume self.xml is a file-like object root = fromstring(self.xml.read()) if root.tag != 'database': raise Exception('Expected root element to be "database", but found "%s"' % root.tag) for schema in root.findall('schema'): if not 'name' in schema.attrib: raise Exception('Mandatory "name" attribute missing') for relation in schema.findall('relation'): if not 'name' in relation.attrib: raise Exception('Mandatory "name" attribute missing from relation in schema %s' % schema.attrib['name']) description = relation.find('description') if iselement(description): description = description.text or '' else: description = '' columns = dict( (column.attrib['name'], column.text or '') for column in relation.findall('column') ) yield (schema.attrib['name'], relation.attrib['name'], description, columns)
def __iter__(self): for (schema, obj, url) in self._get_object_urls(): logging.info('Retrieving descriptions for object %s.%s' % (schema, obj)) f = self._get_xml(url) # The only reliable way to find the object description is to look # for a <div class="section"> element (for 9.5) and, if that fails # look for the first <p>aragraph (for 9 and 8). divs = [ d for d in f.findall('.//div') if d.attrib.get('class') == 'section' ] if len(divs) == 1: obj_desc = divs[0] else: obj_desc = f.find('.//p') if iselement(obj_desc): obj_desc = convert_desc(obj_desc) else: logging.error('Failed to find description for object %s.%s' % (schema, obj)) obj_desc = '' table = f.find('.//table') part_count = 0 part = 0 columns = {} for row in table.find('tbody'): cells = row.findall('td') # Test for 4 or 5 data cells exactly. Anything else is either a # header or footnotes row and should be ignored (the SYSCAT # documentation uses 4 columns, SYSSTAT uses 5). # Workaround: The v8 InfoCenter has a bug in the PROCOPTIONS # documentation - the table rows erroneously contain 3 columns # although the table is 4 columns wide if 3 <= len(cells) <= 5: column = cells[0] # If a description spans multiple rows reuse the initial # cell if part == part_count: col_desc = cells[-1] part_count = int(col_desc.attrib.get('rowspan', '1')) part = 1 else: part += 1 # Strip all whitespace (newlines, space, etc.) - sometimes # the docs include essentially erroneous whitespace to # allow wrapping for really long column names column = re.sub(ur'\s', '', convert_name(column)) # Workaround: DB2 9.5 and 9.7 catalog spelling error: the # documentation lists SYSCAT.INDEXES.COLLECTSTATISTICS but # the column in the actual view in the database is called # SYSCAT.INDEXES.COLLECTSTATISTCS if (self.version in ('95', '97') and schema == 'SYSCAT' and obj == 'INDEXES' and column == 'COLLECTSTATISTICS'): column = 'COLLECTSTATISTCS' # Workaround: DB2 9.5 catalog spelling error: the # documentation lists SYSCAT.THRESHOLDS.QUEUEING, but the # column in the database is SYSCAT.THRESHOLDS.QUEUING if (self.version == '95' and schema == 'SYSCAT' and obj == 'THRESHOLDS' and column == 'QUEUEING'): column = 'QUEUING' # Workaround: DB2 9.5 catalog error: the documentation # lists SYSCAT.SECURITYPOLICIES.USERAUTHS but the column # doesn't exist in the database if (self.version == '95' and schema == 'SYSCAT' and obj == 'SECURITYPOLICIES' and column == 'USERAUTHS'): continue logging.debug('Retrieving description for column %s' % column) # For _really_ long descriptions, the docs sometimes use # separate consecutive "COLUMN_NAME (cont'd)" entries, so # we need to append to an existing description instead of # creating a new one if column[-8:] == "(cont'd)": column = column[:-8] columns[column] += convert_desc(col_desc) elif part_count > 1: columns[column] = '(%d/%d) %s' % ( part, part_count, convert_desc(col_desc)) else: columns[column] = convert_desc(col_desc) yield (schema, obj, obj_desc, columns)
def __iter__(self): for (schema, obj, url) in self._get_object_urls(): logging.info('Retrieving descriptions for object %s.%s' % (schema, obj)) f = self._get_xml(url) # The only reliable way to find the object description is to look # for a <div class="section"> element (for 9.5) and, if that fails # look for the first <p>aragraph (for 9 and 8). divs = [ d for d in f.findall('.//div') if d.attrib.get('class') == 'section' ] if len(divs) == 1: obj_desc = divs[0] else: obj_desc = f.find('.//p') if iselement(obj_desc): obj_desc = convert_desc(obj_desc) else: logging.error('Failed to find description for object %s.%s' % (schema, obj)) obj_desc = '' table = f.find('.//table') part_count = 0 part = 0 columns = {} for row in table.find('tbody'): cells = row.findall('td') # Test for 4 or 5 data cells exactly. Anything else is either a # header or footnotes row and should be ignored (the SYSCAT # documentation uses 4 columns, SYSSTAT uses 5). # Workaround: The v8 InfoCenter has a bug in the PROCOPTIONS # documentation - the table rows erroneously contain 3 columns # although the table is 4 columns wide if 3 <= len(cells) <= 5: column = cells[0] # If a description spans multiple rows reuse the initial # cell if part == part_count: col_desc = cells[-1] part_count = int(col_desc.attrib.get('rowspan', '1')) part = 1 else: part += 1 # Strip all whitespace (newlines, space, etc.) - sometimes # the docs include essentially erroneous whitespace to # allow wrapping for really long column names column = re.sub(ur'\s', '', convert_name(column)) # Workaround: DB2 9.5 and 9.7 catalog spelling error: the # documentation lists SYSCAT.INDEXES.COLLECTSTATISTICS but # the column in the actual view in the database is called # SYSCAT.INDEXES.COLLECTSTATISTCS if (self.version in ('95', '97') and schema == 'SYSCAT' and obj == 'INDEXES' and column == 'COLLECTSTATISTICS'): column = 'COLLECTSTATISTCS' # Workaround: DB2 9.5 catalog spelling error: the # documentation lists SYSCAT.THRESHOLDS.QUEUEING, but the # column in the database is SYSCAT.THRESHOLDS.QUEUING if (self.version == '95' and schema == 'SYSCAT' and obj == 'THRESHOLDS' and column == 'QUEUEING'): column = 'QUEUING' # Workaround: DB2 9.5 catalog error: the documentation # lists SYSCAT.SECURITYPOLICIES.USERAUTHS but the column # doesn't exist in the database if (self.version == '95' and schema == 'SYSCAT' and obj == 'SECURITYPOLICIES' and column == 'USERAUTHS'): continue logging.debug('Retrieving description for column %s' % column) # For _really_ long descriptions, the docs sometimes use # separate consecutive "COLUMN_NAME (cont'd)" entries, so # we need to append to an existing description instead of # creating a new one if column[-8:] == "(cont'd)": column = column[:-8] columns[column] += convert_desc(col_desc) elif part_count > 1: columns[column] = '(%d/%d) %s' % (part, part_count, convert_desc(col_desc)) else: columns[column] = convert_desc(col_desc) yield (schema, obj, obj_desc, columns)
def test_element(): tag = ElementFactory() test_tag = tag.a() assert iselement(test_tag) assert test_tag.tag == 'a' assert len(test_tag.attrib) == 0