#!/usr/bin/python import sys import os import re """ @todo: string trailing "#" @todo: support function args split into multiple lines """ args = sys.argv[1:] indent_level = 4 # spaces func_reg = re.compile(r"\s*def.*?\w\(.*?\):$") indent_level_reg = re.compile(r"^\s*") args_reg = re.compile(r"\(.*?\)") do_docstring_private = False do_docstring_protected = True do_write_return_docstring = True if not args: sys.stdout.write("usage: %s [path]\n" % (sys.argv[0],)) raise SystemExit(1) def write_new_line(buf, data): buf.write(data) sys.stdout.write(data) for path in args: if not (os.path.isfile(path) and os.access(path, os.R_OK | os.W_OK)): sys.stderr.write("unable to deal with %s\n" % (path,)) sys.stderr.flush() continue f = open(path, "r") line = f.readline() out = open(path + ".ds", "w") while line: # function name r_match = func_reg.match(line) if r_match is not None: ### ### extract metadata ### # we've found a defined function raw_func_str = r_match.group() my_indent_level = len(indent_level_reg.match(line).group()) extr_str = r_match.group()[:-1].strip()[len("def"):].strip() dodoc = True if extr_str.startswith("__") and not do_docstring_private: dodoc = False elif extr_str.startswith("__") and not do_docstring_protected: dodoc = False dowrite = False grab_lines = [] args_string = '' if dodoc: # write current line, to make sure to have function definition # in place write_new_line(out, line) my_indent_level += indent_level # extract arguments my_args = args_reg.findall(extr_str) if my_args: my_args = [x for x in my_args[0][1:-1].split(",") \ if x.strip()] if "self" in my_args: my_args.remove("self") # eventually write arguments string for myarg in my_args: if "=" in myarg: myarg = myarg.strip().split()[0] # keyword arg args_string += '%s@keyword %s: \n' % ( " "*my_indent_level, myarg,) else: myarg = myarg.strip() # arg args_string += '%s@param %s: \n' % ( " "*my_indent_level, myarg,) args_string += '%s@type %s: \n' % ( " "*my_indent_level, myarg,) if do_write_return_docstring: args_string += '%s@return: \n' % ( " "*my_indent_level,) args_string += '%s@rtype: ' % ( " "*my_indent_level,) # now it is necessary to check if a docstring is # already set, if so, skip this # grab next line while 1: line = f.readline() if not line.strip(): # line empty grab_lines.append(line) continue elif not (line.strip().startswith('"""') or \ line.strip().startswith("'''")): # line is not empty and does not contain # a docstring dowrite = True grab_lines.append(line) # current line will be written to stdout # after if condition break if dowrite: mydocstr = '%s"""\n%s%s\n\n%s\n%s"""\n' % ( " "*my_indent_level, " "*my_indent_level, "docstring_title", args_string, " "*my_indent_level, ) grab_lines.insert(0, mydocstr) # flushing read lines, preparing for contining or # writing docstring for grab_line in grab_lines: write_new_line(out, grab_line) if dowrite: line = f.readline() continue write_new_line(out, line) line = f.readline() sys.stdout.flush() out.flush() out.close() f.close()