Added Python Docstrings

This commit is contained in:
lewisjb
2017-06-12 12:18:00 +10:00
parent 772a8188c0
commit 078b4cc971
2 changed files with 73 additions and 28 deletions
+42 -20
View File
@@ -21,12 +21,13 @@ opencv_hdr_list = [
]
"""
Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>],
Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>, original_return_type, docstring],
where each element of <list_of_arguments> is 4-element list itself:
[argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
where the list of modifiers is yet another nested list of strings
(currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
and "/A value" for the plain C arrays with counters)
original_return_type is None if the original_return_type is the same as return_value_type
"""
class CppHeaderParser(object):
@@ -226,7 +227,7 @@ class CppHeaderParser(object):
else:
prev_val_delta = 0
prev_val = val = pv[1].strip()
decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], []])
decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], [], None, ""])
return decl
def parse_class_decl(self, decl_str):
@@ -256,7 +257,7 @@ class CppHeaderParser(object):
bases = ll[2:]
return classname, bases, modlist
def parse_func_decl_no_wrap(self, decl_str, static_method = False):
def parse_func_decl_no_wrap(self, decl_str, static_method=False, docstring=""):
decl_str = (decl_str or "").strip()
virtual_method = False
explicit_method = False
@@ -299,7 +300,7 @@ class CppHeaderParser(object):
apos = fdecl.find("(", apos+1)
fname = "cv." + fname.replace("::", ".")
decl = [fname, rettype, [], []]
decl = [fname, rettype, [], [], None, docstring]
# inline constructor implementation
implmatch = re.match(r"(\(.*?\))\s*:\s*(\w+\(.*?\),?\s*)+", fdecl[apos:])
@@ -370,7 +371,7 @@ class CppHeaderParser(object):
print(decl_str)
return decl
def parse_func_decl(self, decl_str, use_umat=False):
def parse_func_decl(self, decl_str, use_umat=False, docstring=""):
"""
Parses the function or method declaration in the form:
[([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
@@ -379,7 +380,7 @@ class CppHeaderParser(object):
[const] {; | <function_body>}
Returns the function declaration entry:
[<func name>, <return value C-type>, <list of modifiers>, <list of arguments>] (see above)
[<func name>, <return value C-type>, <list of modifiers>, <list of arguments>, <original return type>, <docstring>] (see above)
"""
if self.wrap_mode:
@@ -484,7 +485,7 @@ class CppHeaderParser(object):
funcname = self.get_dotted_name(funcname)
if not self.wrap_mode:
decl = self.parse_func_decl_no_wrap(decl_str, static_method)
decl = self.parse_func_decl_no_wrap(decl_str, static_method, docstring)
decl[0] = funcname
return decl
@@ -574,10 +575,7 @@ class CppHeaderParser(object):
if static_method:
func_modlist.append("/S")
if original_type is None:
return [funcname, rettype, func_modlist, args]
else:
return [funcname, rettype, func_modlist, args, original_type]
return [funcname, rettype, func_modlist, args, original_type, docstring]
def get_dotted_name(self, name):
"""
@@ -612,7 +610,7 @@ class CppHeaderParser(object):
n = "cv.Algorithm"
return n
def parse_stmt(self, stmt, end_token, use_umat=False):
def parse_stmt(self, stmt, end_token, use_umat=False, docstring=""):
"""
parses the statement (ending with ';' or '}') or a block head (ending with '{')
@@ -659,7 +657,7 @@ class CppHeaderParser(object):
exit(1)
if classname.startswith("_Ipl"):
classname = classname[1:]
decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], None, docstring]
if bases:
decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
return stmt_type, classname, True, decl
@@ -674,7 +672,7 @@ class CppHeaderParser(object):
exit(1)
decl = []
if ("CV_EXPORTS_W" in stmt) or ("CV_EXPORTS_AS" in stmt) or (not self.wrap_mode):# and ("CV_EXPORTS" in stmt)):
decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, [], None, docstring]
if bases:
decl[1] = ": " + ", ".join([self.get_dotted_name(b).replace(".","::") for b in bases])
return stmt_type, classname, True, decl
@@ -704,7 +702,7 @@ class CppHeaderParser(object):
# since we filtered off the other places where '(' can normally occur:
# - code blocks
# - function pointer typedef's
decl = self.parse_func_decl(stmt, use_umat=use_umat)
decl = self.parse_func_decl(stmt, use_umat=use_umat, docstring=docstring)
# we return parse_flag == False to prevent the parser to look inside function/method bodies
# (except for tracking the nested blocks)
return stmt_type, "", False, decl
@@ -759,11 +757,13 @@ class CppHeaderParser(object):
SCAN = 0 # outside of a comment or preprocessor directive
COMMENT = 1 # inside a multi-line comment
DIRECTIVE = 2 # inside a multi-line preprocessor directive
DOCSTRING = 3 # inside a multi-line docstring
state = SCAN
self.block_stack = [["file", hname, True, True, None]]
block_head = ""
docstring = ""
self.lineno = 0
self.wrap_mode = wmode
@@ -789,6 +789,15 @@ class CppHeaderParser(object):
l = l[pos+2:]
state = SCAN
if state == DOCSTRING:
pos = l.find("*/")
if pos < 0:
docstring += l + "\n"
continue
docstring += l[:pos] + "\n"
l = l[pos+2:]
state = SCAN
if state != SCAN:
print("Error at %d: invlid state = %d" % (self.lineno, state))
sys.exit(-1)
@@ -806,11 +815,20 @@ class CppHeaderParser(object):
if token == "/*":
block_head += " " + l[:pos]
pos = l.find("*/", pos+2)
if pos < 0:
end_pos = l.find("*/", pos+2)
if len(l) > pos + 2 and l[pos+2] == "*":
# '/**', it's a docstring
if end_pos < 0:
state = DOCSTRING
docstring = l[pos+3:] + "\n"
break
else:
docstring = l[pos+3:end_pos]
elif end_pos < 0:
state = COMMENT
break
l = l[pos+2:]
l = l[end_pos+2:]
continue
if token == "\"":
@@ -840,7 +858,8 @@ class CppHeaderParser(object):
if stack_top[self.PROCESS_FLAG]:
# even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
# since it can start with "public:"
stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token)
docstring = docstring.strip()
stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring)
if decl:
if stmt_type == "enum":
for d in decl:
@@ -854,8 +873,9 @@ class CppHeaderParser(object):
args = decl[3]
has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
if has_mat:
_, _, _, umat_decl = self.parse_stmt(stmt, token, use_umat=True)
_, _, _, umat_decl = self.parse_stmt(stmt, token, use_umat=True, docstring=docstring)
decls.append(umat_decl)
docstring = ""
if stmt_type == "namespace":
chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name]
self.namespaces.add('.'.join(chunks))
@@ -887,6 +907,8 @@ class CppHeaderParser(object):
"""
for d in decls:
print(d[0], d[1], ";".join(d[2]))
# Uncomment below line to see docstrings
# print('"""\n' + d[5] + '\n"""')
for a in d[3]:
print(" ", a[0], a[1], a[2], end="")
if a[3]: