File: scipyoptdoc.py

package info (click to toggle)
python-scipy 0.18.1-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 75,464 kB
  • ctags: 79,406
  • sloc: python: 143,495; cpp: 89,357; fortran: 81,650; ansic: 79,778; makefile: 364; sh: 265
file content (156 lines) | stat: -rw-r--r-- 5,178 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"""
===========
scipyoptdoc
===========

Proper docstrings for scipy.optimize.minimize et al.

Usage::

    .. scipy-optimize:function:: scipy.optimize.minimize
       :impl: scipy.optimize.optimize._minimize_nelder_mead
       :method: Nelder-Mead

Produces output similar to autodoc, except

- The docstring is obtained from the 'impl' function
- The call signature is mangled so that the default values for method keyword
  and options dict are substituted
- 'Parameters' section is replaced by 'Options' section
- See Also link to the actual function documentation is inserted

"""
from __future__ import division, absolute_import, print_function

import os, sys, re, pydoc
import sphinx
import inspect
import collections
import textwrap

if sphinx.__version__ < '1.0.1':
    raise RuntimeError("Sphinx 1.0.1 or newer is required")

from numpydoc.numpydoc import mangle_docstrings
from docutils.parsers.rst import Directive
from docutils.statemachine import ViewList
from sphinx.domains.python import PythonDomain


if sys.version_info[0] >= 3:
    sixu = lambda s: s
else:
    sixu = lambda s: unicode(s, 'unicode_escape')


def setup(app):
    app.add_domain(ScipyOptimizeInterfaceDomain)


def _option_required_str(x):
    if not x:
        raise ValueError("value is required")
    return str(x)


def _import_object(name):
    parts = name.split('.')
    module_name = '.'.join(parts[:-1])
    __import__(module_name)
    obj = getattr(sys.modules[module_name], parts[-1])
    return obj


class ScipyOptimizeInterfaceDomain(PythonDomain):
    name = 'scipy-optimize'

    def __init__(self, *a, **kw):
        super(ScipyOptimizeInterfaceDomain, self).__init__(*a, **kw)
        self.directives = dict(self.directives)
        self.directives['function'] = wrap_mangling_directive(self.directives['function'])


BLURB = """
.. seealso:: For documentation for the rest of the parameters, see `%s`
"""

def wrap_mangling_directive(base_directive):
    class directive(base_directive):
        def run(self):
            env = self.state.document.settings.env

            # Interface function
            name = self.arguments[0].strip()
            obj = _import_object(name)
            args, varargs, keywords, defaults = inspect.getargspec(obj)

            # Implementation function
            impl_name = self.options['impl']
            impl_obj = _import_object(impl_name)
            impl_args, impl_varargs, impl_keywords, impl_defaults = inspect.getargspec(impl_obj)

            # Format signature taking implementation into account
            args = list(args)
            defaults = list(defaults)

            def set_default(arg, value):
                j = args.index(arg)
                defaults[len(defaults) - (len(args) - j)] = value

            def remove_arg(arg):
                if arg not in args:
                    return
                j = args.index(arg)
                if j < len(args) - len(defaults):
                    del args[j]
                else:
                    del defaults[len(defaults) - (len(args) - j)]
                    del args[j]

            options = []
            for j, opt_name in enumerate(impl_args):
                if opt_name in args:
                    continue
                if j >= len(impl_args) - len(impl_defaults):
                    options.append((opt_name, impl_defaults[len(impl_defaults) - (len(impl_args) - j)]))
                else:
                    options.append((opt_name, None))
            set_default('options', dict(options))
            set_default('method', self.options['method'].strip())

            for arg in list(args):
                if arg not in impl_args and arg not in ('fun', 'x0', 'args', 'tol',
                                                        'callback', 'method', 'options'):
                    remove_arg(arg)

            signature = inspect.formatargspec(args, varargs, keywords, defaults)

            # Produce output
            self.options['noindex'] = True
            self.arguments[0] = name + signature
            lines = textwrap.dedent(pydoc.getdoc(impl_obj)).splitlines()
            new_lines = []
            for line in lines:
                if line.strip() == 'Options':
                    new_lines.append("Other Parameters")
                elif line.strip() == "-"*len('Options'):
                    new_lines.append("-"*len("Other Parameters"))
                else:
                    new_lines.append(line)
            mangle_docstrings(env.app, 'function', name, None, None, new_lines)
            lines = new_lines
            new_lines = []
            for line in lines:
                if line.strip() == ':Other Parameters:':
                    new_lines.extend((BLURB % (name,)).splitlines())
                    new_lines.append(':Options:')
                else:
                    new_lines.append(line)
            self.content = ViewList(new_lines, self.content.parent)
            return base_directive.run(self)

        option_spec = dict(base_directive.option_spec)
        option_spec['impl'] = _option_required_str
        option_spec['method'] = _option_required_str

    return directive