mkdoc.py: sanitize_name fixes, PEP 8 cleanups

This commit is contained in:
Wenzel Jakob 2016-04-27 00:35:03 +02:00
parent e84f557edf
commit a57e51c5d8

View File

@ -5,7 +5,12 @@
# Extract documentation from C++ header files to use it in Python bindings # Extract documentation from C++ header files to use it in Python bindings
# #
import os, sys, platform, re, textwrap import os
import sys
import platform
import re
import textwrap
from clang import cindex from clang import cindex
from clang.cindex import CursorKind from clang.cindex import CursorKind
from collections import OrderedDict from collections import OrderedDict
@ -32,32 +37,35 @@ PRINT_LIST = [
] ]
CPP_OPERATORS = { CPP_OPERATORS = {
'<=' : 'le', '>=' : 'ge', '==' : 'eq', '!=' : 'ne', '[]' : 'array', '<=': 'le', '>=': 'ge', '==': 'eq', '!=': 'ne', '[]': 'array',
'+=' : 'iadd', '-=' : 'isub', '*=' : 'imul', '/=' : 'idiv', '%=' : '+=': 'iadd', '-=': 'isub', '*=': 'imul', '/=': 'idiv', '%=':
'imod', '&=' : 'iand', '|=' : 'ior', '^=' : 'ixor', '<<=' : 'ilshift', 'imod', '&=': 'iand', '|=': 'ior', '^=': 'ixor', '<<=': 'ilshift',
'>>=' : 'irshift', '++' : 'inc', '--' : 'dec', '<<' : 'lshift', '>>' : '>>=': 'irshift', '++': 'inc', '--': 'dec', '<<': 'lshift', '>>':
'rshift', '&&' : 'land', '||' : 'lor', '!' : 'lnot', '~' : 'bnot', '&' 'rshift', '&&': 'land', '||': 'lor', '!': 'lnot', '~': 'bnot',
: 'band', '|' : 'bor', '+' : 'add', '-' : 'sub', '*' : 'mul', '/' : '&': 'band', '|': 'bor', '+': 'add', '-': 'sub', '*': 'mul', '/':
'div', '%' : 'mod', '<' : 'lt', '>' : 'gt', '=' : 'assign' 'div', '%': 'mod', '<': 'lt', '>': 'gt', '=': 'assign'
} }
CPP_OPERATORS = OrderedDict(sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0])))
CPP_OPERATORS = OrderedDict(
sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0])))
job_count = cpu_count() job_count = cpu_count()
job_semaphore = Semaphore(job_count) job_semaphore = Semaphore(job_count)
registered_names = dict() registered_names = dict()
def d(s): def d(s):
return s.decode('utf8') return s.decode('utf8')
def sanitize_name(name): def sanitize_name(name):
global registered_names global registered_names
for k, v in CPP_OPERATORS.items(): for k, v in CPP_OPERATORS.items():
name = name.replace('operator%s' % k, 'operator_%s' % v) name = name.replace('operator%s' % k, 'operator_%s' % v)
name = name.replace('<', '_') name = re.sub('<.*>', '', name)
name = name.replace('>', '_') name = ''.join([ch if ch.isalnum() else '_' for ch in name])
name = name.replace(' ', '_') name = re.sub('_$', '', re.sub('_+', '_', name))
name = name.replace(',', '_')
if name in registered_names: if name in registered_names:
registered_names[name] += 1 registered_names[name] += 1
name += '_' + str(registered_names[name]) name += '_' + str(registered_names[name])
@ -65,6 +73,7 @@ def sanitize_name(name):
registered_names[name] = 1 registered_names[name] = 1
return '__doc_' + name return '__doc_' + name
def process_comment(comment): def process_comment(comment):
result = '' result = ''
@ -91,20 +100,22 @@ def process_comment(comment):
s = re.sub(r'\\e\s+%s' % cpp_group, r'*\1*', s) s = re.sub(r'\\e\s+%s' % cpp_group, r'*\1*', s)
s = re.sub(r'\\em\s+%s' % cpp_group, r'*\1*', s) s = re.sub(r'\\em\s+%s' % cpp_group, r'*\1*', s)
s = re.sub(r'\\b\s+%s' % cpp_group, r'**\1**', s) s = re.sub(r'\\b\s+%s' % cpp_group, r'**\1**', s)
s = re.sub(r'\\param%s?\s+%s' % (param_group, cpp_group), r'\n\n$Parameter ``\2``:\n\n', s) s = re.sub(r'\\param%s?\s+%s' % (param_group, cpp_group),
r'\n\n$Parameter ``\2``:\n\n', s)
for in_, out_ in { for in_, out_ in {
'return' : 'Returns', 'return': 'Returns',
'author' : 'Author', 'author': 'Author',
'authors' : 'Authors', 'authors': 'Authors',
'copyright' : 'Copyright', 'copyright': 'Copyright',
'date' : 'Date', 'date': 'Date',
'remark' : 'Remark', 'remark': 'Remark',
'sa' : 'See also', 'sa': 'See also',
'see' : 'See also', 'see': 'See also',
'extends' : 'Extends', 'extends': 'Extends',
'throw' : 'Throws', 'throw': 'Throws',
'throws' : 'Throws' }.items(): 'throws': 'Throws'
}.items():
s = re.sub(r'\\%s\s*' % in_, r'\n\n$%s:\n\n' % out_, s) s = re.sub(r'\\%s\s*' % in_, r'\n\n$%s:\n\n' % out_, s)
s = re.sub(r'\\details\s*', r'\n\n', s) s = re.sub(r'\\details\s*', r'\n\n', s)
@ -133,7 +144,7 @@ def process_comment(comment):
wrapped = wrapper.fill(x.strip()) wrapped = wrapper.fill(x.strip())
if len(wrapped) > 0 and wrapped[0] == '$': if len(wrapped) > 0 and wrapped[0] == '$':
result += wrapped[1:] + '\n' result += wrapped[1:] + '\n'
wrapper.initial_indent = wrapper.subsequent_indent = ' '*4 wrapper.initial_indent = wrapper.subsequent_indent = ' ' * 4
else: else:
result += wrapped + '\n\n' result += wrapped + '\n\n'
wrapper.initial_indent = wrapper.subsequent_indent = '' wrapper.initial_indent = wrapper.subsequent_indent = ''
@ -142,7 +153,8 @@ def process_comment(comment):
def extract(filename, node, prefix, output): def extract(filename, node, prefix, output):
num_extracted = 0 num_extracted = 0
if not (node.location.file is None or os.path.samefile(d(node.location.file.name), filename)): if not (node.location.file is None or
os.path.samefile(d(node.location.file.name), filename)):
return 0 return 0
if node.kind in RECURSE_LIST: if node.kind in RECURSE_LIST:
sub_prefix = prefix sub_prefix = prefix
@ -161,12 +173,14 @@ def extract(filename, node, prefix, output):
if len(sub_prefix) > 0: if len(sub_prefix) > 0:
sub_prefix += '_' sub_prefix += '_'
name = sanitize_name(sub_prefix + d(node.spelling)) name = sanitize_name(sub_prefix + d(node.spelling))
output.append('\nstatic const char *%s = %sR"doc(%s)doc";' % (name, '\n' if '\n' in comment else '', comment)) output.append('\nstatic const char *%s =%sR"doc(%s)doc";' %
(name, '\n' if '\n' in comment else ' ', comment))
num_extracted += 1 num_extracted += 1
return num_extracted return num_extracted
class ExtractionThread(Thread): class ExtractionThread(Thread):
def __init__ (self, filename, parameters, output): def __init__(self, filename, parameters, output):
Thread.__init__(self) Thread.__init__(self)
self.filename = filename self.filename = filename
self.parameters = parameters self.parameters = parameters
@ -174,9 +188,10 @@ class ExtractionThread(Thread):
job_semaphore.acquire() job_semaphore.acquire()
def run(self): def run(self):
print('Processing "%s" ..' % self.filename, file = sys.stderr) print('Processing "%s" ..' % self.filename, file=sys.stderr)
try: try:
index = cindex.Index(cindex.conf.lib.clang_createIndex(False, True)) index = cindex.Index(
cindex.conf.lib.clang_createIndex(False, True))
tu = index.parse(self.filename, self.parameters) tu = index.parse(self.filename, self.parameters)
extract(self.filename, tu.cursor, '', self.output) extract(self.filename, tu.cursor, '', self.output)
finally: finally:
@ -187,15 +202,18 @@ if __name__ == '__main__':
filenames = [] filenames = []
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
libclang = '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib' dev_path = '/Applications/Xcode.app/Contents/Developer/'
lib_dir = dev_path + 'Toolchains/XcodeDefault.xctoolchain/usr/lib/'
sdk_dir = dev_path + 'Platforms/MacOSX.platform/Developer/SDKs'
libclang = lib_dir + 'libclang.dylib'
if os.path.exists(libclang): if os.path.exists(libclang):
cindex.Config.set_library_path(os.path.dirname(libclang)) cindex.Config.set_library_path(os.path.dirname(libclang))
base_path = '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs' if os.path.exists(sdk_dir):
if os.path.exists(base_path): sysroot_dir = os.path.join(sdk_dir, next(os.walk(sdk_dir))[1][0])
sysroot = os.path.join(base_path, next(os.walk(base_path))[1][0])
parameters.append('-isysroot') parameters.append('-isysroot')
parameters.append(sysroot) parameters.append(sysroot_dir)
for item in sys.argv[1:]: for item in sys.argv[1:]:
if item.startswith('-'): if item.startswith('-'):
@ -235,7 +253,7 @@ if __name__ == '__main__':
thr = ExtractionThread(filename, parameters, output) thr = ExtractionThread(filename, parameters, output)
thr.start() thr.start()
print('Waiting for jobs to finish ..', file = sys.stderr) print('Waiting for jobs to finish ..', file=sys.stderr)
for i in range(job_count): for i in range(job_count):
job_semaphore.acquire() job_semaphore.acquire()