html_functions.py 3.98 KB
Newer Older
1
from __future__ import print_function
2 3
import sys

4 5
import logging
import os
6
from pprint import pprint
7
import traceback
8 9

try:
10
    import bs4
11 12 13 14 15 16 17 18
    from bs4 import BeautifulSoup
except ImportError:
    raise ImportError('Error: '
                      'Install BeautifulSoup (bs4) for adding'
                      ' Python & Java signatures documentation')

def load_html_file(file_dir):
    """ Uses BeautifulSoup to load an html """
19
    with open(file_dir, 'rb') as fp:
tribta's avatar
tribta committed
20 21
        soup = BeautifulSoup(fp, 'html.parser')
    return soup
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 61 62 63 64 65 66 67 68 69 70 71 72 73
def update_html(file, soup):
    s = str(soup)
    if os.name == 'nt' or sys.version_info[0] == 3: # if Windows
        s = s.encode('utf-8', 'ignore')
    with open(file, 'wb') as f:
        f.write(s)


def insert_python_signatures(python_signatures, symbols_dict, filepath):
    soup = load_html_file(filepath)
    entries = soup.find_all(lambda tag: tag.name == "a" and tag.has_attr('id'))
    for e in entries:
        anchor = e['id']
        if anchor in symbols_dict:
            s = symbols_dict[anchor]
            logging.info('Process: %r' % s)
            if s.type == 'fn' or s.type == 'method':
                process_fn(soup, e, python_signatures[s.cppname], s)
            elif s.type == 'const':
                process_const(soup, e, python_signatures[s.cppname], s)
            else:
                logging.error('unsupported type: %s' % s);

    update_html(filepath, soup)


def process_fn(soup, anchor, python_signature, symbol):
    try:
        r = anchor.find_next_sibling(class_='memitem').find(class_='memproto').find('table')
        insert_python_fn_signature(soup, r, python_signature, symbol)
    except:
        logging.error("Can't process: %s" % symbol)
        traceback.print_exc()
        pprint(anchor)


def process_const(soup, anchor, python_signature, symbol):
    try:
        #pprint(anchor.parent)
        description = append(soup.new_tag('div', **{'class' : ['python_language']}),
            'Python: ' + python_signature[0]['name'])
        old = anchor.find_next_sibling('div', class_='python_language')
        if old is None:
            anchor.parent.append(description)
        else:
            old.replace_with(description)
        #pprint(anchor.parent)
    except:
        logging.error("Can't process: %s" % symbol)
        traceback.print_exc()
        pprint(anchor)
74 75


76 77
def insert_python_fn_signature(soup, table, variants, symbol):
    description = create_python_fn_description(soup, variants)
tribta's avatar
tribta committed
78
    description['class'] = 'python_language'
79
    soup = insert_or_replace(table, description, 'table', 'python_language')
tribta's avatar
tribta committed
80 81
    return soup

tribta's avatar
tribta committed
82

83 84 85 86 87 88 89 90 91 92 93 94
def create_python_fn_description(soup, variants):
    language = 'Python:'
    table = soup.new_tag('table')
    heading_row = soup.new_tag('th')
    table.append(
        append(soup.new_tag('tr'),
               append(soup.new_tag('th', colspan=999, style="text-align:left"), language)))
    for v in variants:
        #logging.debug(v)
        add_signature_to_table(soup, table, v, language, type)
    #print(table)
    return table
tribta's avatar
tribta committed
95 96


97 98 99 100
def add_signature_to_table(soup, table, signature, language, type):
    """ Add a signature to an html table"""
    row = soup.new_tag('tr')
    row.append(soup.new_tag('td', style='width: 20px;'))
tribta's avatar
tribta committed
101

102 103 104 105 106 107
    if 'ret' in signature:
        row.append(append(soup.new_tag('td'), signature['ret']))
        row.append(append(soup.new_tag('td'), '='))
    else:
        row.append(soup.new_tag('td')) # return values
        row.append(soup.new_tag('td')) # '='
tribta's avatar
tribta committed
108

109 110 111 112
    row.append(append(soup.new_tag('td'), signature['name'] + '('))
    row.append(append(soup.new_tag('td', **{'class': 'paramname'}), signature['arg']))
    row.append(append(soup.new_tag('td'), ')'))
    table.append(row)
tribta's avatar
tribta committed
113 114


115 116 117
def append(target, obj):
    target.append(obj)
    return target
tribta's avatar
tribta committed
118

119 120 121 122 123

def insert_or_replace(element_before, new_element, tag, tag_class):
    old = element_before.find_next_sibling(tag, class_=tag_class)
    if old is None:
        element_before.insert_after(new_element)
124
    else:
125
        old.replace_with(new_element)