# docpy.py - david.barkhuizn@gmail.com
# 1. module methods - signature, followed by docstring
# 2. module fields ?
# 3. module classes
# class name, parent class, __init__ method parameters & docstring
# instance fields (get from self.? refs in __init__ method)
# ---------------------------------------------------------------
# ISSUES
# need to strip out classes before extracting method info
# can't handle multi-line method signatures
# ---------------------------------------------------------------
import sys
# ---------------------------------------------------------------
single_marker = '\'\'\''
double_marker = '\"\"\"'
# ---------------------------------------------------------------
class MethodInfo:
def __init__(self, method_name, params, docstrings):
'''
method_name - string
params - list of param name strings
'''
self.method_name = method_name
self.params = params
self.docstrings = docstrings
# ---------------------------------------------------------------
def load_text_file(file_path):
'''
return list of lines in text file @ 'file_path'
'''
try:
text_file = open(file_path, 'r')
text_block = text_file.read()
lines = text_block.split('\n')
text_file.close()
return lines
except Exception, err:
print('error during reading of text file %s' % file_path)
print(err)
return []
def src_file_path_from_cmdargs():
valid_args = []
for arg in sys.argv:
if arg.lower() not in ['docpy.py', 'python']:
valid_args.append(arg.lower())
return 'docpy.py'
if len(valid_args) != 1:
return ''
else:
return valid_args[0]
def get_sig_line_idxs(lines):
'''
lines = list of lines in python source file (in sequence)
'''
token = 'def '
indices = []
for i in range(len(lines)):
if lines[i].strip()[:4] == token:
indices.append(i)
return indices
def parse_method_sig(sig):
# e.g.' def parse_methodsig(sig):#comment '
sig = sig.strip()
# e.g.'def parse_methodsig(sig):#comment'
sig = sig[4:len(sig)]
# e.g.'parse_methodsig(sig):#comment'
i = sig.find('#')
if i != -1:
sig = sig[:i-1]
# e.g.'parse_methodsig(sig):
left = sig.find('(')
right = sig.rfind(')')
meth_name = sig[:left]
params = []
if right - left != 1:
params = sig[left+1:right]
params = params.replace(',', ' ')
got_double = True
while got_double == True:
got_double = (params.find(' ') != -1)
if got_double:
params = params.replace(' ', ' ')
params = params.split(' ')
return MethodInfo(meth_name, params, [])
def extract_single_line_docstring(docstring):
'''example of single line method docstring'''
lsingle = docstring.find(single_marker)
ldouble = docstring.find(double_marker)
marker = ''
left = -1
if lsingle != -1:
marker = single_marker
left = lsingle
elif ldouble != -1:
marker = double_marker
left = ldouble
else:
return ''
right = docstring.rfind(marker)
if (right != -1) and (right != left):
return docstring[left+3:right]
else:
return ''
def strip_leading_triplequotes(line):
left = line.find(single_marker)
if left == -1:
left = line.find(double_marker)
if left == -1:
return ''
return line[left + 3:]
def strip_trailing_triplequotes(line):
right = line.rfind(double_marker)
if right == -1:
right = line.rfind(double_marker)
if right == -1:
return ''
return line[:right]
def extract_docstrings(lines, meth_sig_idx, next_meth_sig_idx):
# determine line indices of starting and ending triple quotes
start = -1
end = -1
for i in range(meth_sig_idx + 1, next_meth_sig_idx):
line = lines[i]
sidx = line.find(single_marker)
if sidx == -1:
sidx = line.find(double_marker)
if sidx != -1:
if start == -1:
start = i
else:
end = i
break
if start == -1:
return []
elif end == -1:
single_line = extract_single_line_docstring(lines[start])
if single_line != '':
return [ single_line ]
else:
return []
else:
docstrings = []
for i in range(start, end + 1):
no_whitespace = lines[i].strip()
if i == start:
stripped = strip_leading_triplequotes(no_whitespace)
if stripped != '':
docstrings.append(stripped)
elif i == end:
stripped = strip_trailing_triplequotes(no_whitespace)
if stripped != '':
docstrings.append(stripped)
else:
docstrings.append(no_whitespace)
return docstrings
def get_method_info(lines, meth_sig_idx, next_meth_sig_idx):
method_info = parse_method_sig(lines[meth_sig_idx])
method_info.docstrings = extract_docstrings(lines, meth_sig_idx, next_meth_sig_idx)
return method_info
def mock_method(one, two, three, four):
print('vokol')
def display_module_method_info(meth_info):
print(meth_info.method_name)
for p in meth_info.params:
print(' ' + p)
for docstring in meth_info.docstrings:
print(docstring)
def main():
text_file_path = src_file_path_from_cmdargs()
lines = load_text_file(text_file_path)
sig_line_idxs = get_sig_line_idxs(lines)
module_methods_info = []
for i in range(len(sig_line_idxs)):
idx = sig_line_idxs[i]
if i < len(sig_line_idxs) - 1:
next_idx = sig_line_idxs[i + 1]
else:
next_idx = len(sig_line_idxs)
module_methods_info.append( get_method_info(lines, idx, next_idx) )
for meth_info in module_methods_info:
display_module_method_info(meth_info)
if __name__ == '__main__':
main()
Tuesday, July 20, 2010
DocPy - Python Source Doc Gen
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment
comment: