Last active
December 22, 2015 05:49
-
-
Save josef-pkt/6426618 to your computer and use it in GitHub Desktop.
parsing Fortran docstrings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
"""Parsing the Fortran files to create raw docstrings | |
Created on Tue Sep 03 10:11:10 2013 | |
Author: Josef Perktold | |
open problems | |
cumnor.f doesn't define segment headers besides "Function" | |
""" | |
import os | |
from collections import defaultdict | |
import textwrap | |
def reformat(s): | |
# remove duplicate spaces | |
for i in range(6): | |
s = s.replace(' ', ' ') | |
return textwrap.fill(s, 66) | |
template_arg = '''\ | |
%s : array_like | |
%s | |
''' | |
template = '''\ | |
%(signature)s | |
%(short)s | |
%(long)s | |
Parameters | |
---------- | |
%(Parameters)s | |
Returns | |
------- | |
%(Returns)s | |
Notes | |
----- | |
%(Notes)s | |
''' | |
def fdocstring(filepath): | |
lines = file(filepath).readlines() | |
header = lines[0].strip() | |
description = [] | |
# get docstring at beginning of file | |
section = 0 | |
for line in lines[2:]: | |
#if line == sep: | |
if line.startswith('C********'): | |
section += 1 | |
continue | |
if section == 0: | |
description.append(line[1:]) | |
# get separate segments in docstring | |
segments = defaultdict(list) | |
section = 'start' | |
for line in description[1:]: | |
if len(line.strip()) == 0: | |
continue | |
if ' Function' in line: | |
section = 'func' | |
elif ' Arguments' in line: | |
section = 'args' | |
elif ' Method' in line: | |
section = 'method' | |
elif ' Variables' in line: | |
section = 'ignore' | |
segments[section].append(line[1:].strip(' ')) | |
# for debugging | |
print_seg = False | |
if print_seg: | |
for seg in segments: | |
print '\n' | |
print seg | |
print ''.join(segments[seg]) | |
# process Arguments | |
import re | |
expr_in = re.compile('(.*)-->(.*)') | |
expr_out = re.compile('(.*)<--(.*)') | |
expr_inout = re.compile('(.*)<.*-->(.*)') | |
argsli = [] | |
argdesc = [] | |
inout = '' | |
argname = '' | |
for line in segments['args']: | |
if len(line.strip()) == 0: | |
continue | |
if '<-->' in line or '< -->' in line: | |
# need to check this first or it will be captured by --> | |
# '< -->' is typo in cdff.f | |
#TODO: in or out or both ? depends on case | |
argsli.append((inout, argname, '\n'.join(argdesc))) | |
inout = 'inout' | |
res = expr_inout.match(line).groups() | |
argname = res[0].strip().lower() | |
argdesc = [' '*4 + res[1].strip(' ')] | |
elif '-->' in line: | |
argsli.append((inout, argname, '\n'.join(argdesc))) | |
inout = 'in' | |
res = expr_in.match(line).groups() | |
argname = res[0].strip().lower() | |
argdesc = [' '*4 + res[1].strip(' ')] | |
elif '<--' in line: | |
argsli.append((inout, argname, '\n'.join(argdesc))) | |
inout = 'out' | |
res = expr_out.match(line).groups() | |
argname = res[0].strip().lower() | |
argdesc = [' '*4 + res[1].strip(' ')] | |
else: | |
# don't add comment about return precision | |
if not 'PREC' in line: | |
argdesc.append(' '*4 + line.strip()) | |
argsli.append((inout, argname, '\n'.join(argdesc))) # finish last args | |
del argsli[0] # remove initialization, could be cleaned up | |
# build docstring | |
docstring = {} | |
docstring['signature'] = header.split(' ')[1].replace(',', ', ') | |
if len(segments['start']) > 1: | |
docstring['short'] = reformat(''.join(segments['start'][1:])) | |
else: | |
docstring['short'] = '' | |
docstring['long'] = reformat(''.join(segments['func'][1:])) | |
docstring['Notes'] = reformat(''.join(segments['method'][1:])) | |
docstring['Parameters'] = '' | |
docstring['Returns'] = '' | |
for i in argsli: | |
if i[0] == 'in': | |
# string concatenation but short loop | |
docstring['Parameters'] += template_arg % i[1:]# + '\n' | |
elif i[0] == 'out': | |
# string concatenation but short loop | |
docstring['Returns'] += template_arg % i[1:]# + '\n' | |
elif i[0] == 'inout': | |
# string concatenation but short loop | |
docstring['Parameters'] += template_arg % i[1:]# + '\n' | |
docstring['Returns'] += template_arg % i[1:]# + '\n' | |
return template % docstring | |
root = r'<path to\scipy\scipy\special\cdflib' | |
names = ['cumchn.f', 'cumtnc.f'] | |
#names = [os.path.join(root, ffile) for ffile in names] | |
use_glob = True | |
if use_glob: | |
import glob | |
names = glob.glob(root+'/c*.f') | |
for ffile in names: | |
fn = os.path.join(root, ffile) #redundant for glob with full path | |
print '#################' | |
print fdocstring(fn) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment