Skip to content
This repository has been archived by the owner on Feb 28, 2022. It is now read-only.

Commit

Permalink
Add ability to get signature from a method/function
Browse files Browse the repository at this point in the history
  • Loading branch information
ericholscher committed May 3, 2017
1 parent 919ff75 commit 4ab09a9
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 6 deletions.
18 changes: 12 additions & 6 deletions docfx_yaml/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from sphinx.util import ensuredir
from sphinx.errors import ExtensionError

from .utils import transform_node, transform_string
from .utils import transform_node, transform_string, get_method_sig
from .settings import API_ROOT
from .monkeypatch import patch_docfields

Expand Down Expand Up @@ -141,6 +141,11 @@ def _create_datam(app, cls, module, name, _type, obj, lines=None):
except Exception:
print("Can't get argspec for {}: {}".format(type(obj), name))

try:
sig = get_method_sig(obj)
except (Exception):
sig = None

try:
full_path = inspect.getsourcefile(obj)
# Sub git repo path
Expand Down Expand Up @@ -179,11 +184,12 @@ def _create_datam(app, cls, module, name, _type, obj, lines=None):

if summary:
datam['summary'] = summary
if args:
datam['syntax'] = {
'parameters': args,
}

if args or sig:
datam['syntax'] = {}
if args:
datam['syntax']['parameters'] = args
if sig:
datam['syntax']['content'] = sig
if cls:
datam[CLASS] = cls
if _type in [CLASS, MODULE]:
Expand Down
1 change: 1 addition & 0 deletions docfx_yaml/monkeypatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@


def _get_desc_data(node):
assert node.tagname == 'desc'
if node.attributes['domain'] != 'py':
print(
'Skipping Domain Object (%s)' % node.attributes['domain']
Expand Down
65 changes: 65 additions & 0 deletions docfx_yaml/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from docutils.io import StringOutput
from docutils.utils import new_document
from docutils import nodes
import inspect
from collections import namedtuple

from .writer import MarkdownWriter as Writer

Expand Down Expand Up @@ -38,3 +40,66 @@ def transform_node(app, node):
writer = Writer(app.builder)
writer.write(doc, destination)
return destination.destination.decode('utf-8').strip()




def _get_default_arg(args, defaults, arg_index):
""" Method that determines if an argument has default value or not,
and if yes what is the default value for the argument
:param args: array of arguments, eg: ['first_arg', 'second_arg', 'third_arg']
:param defaults: array of default values, eg: (42, 'something')
:param arg_index: index of the argument in the argument array for which,
this function checks if a default value exists or not. And if default value
exists it would return the default value. Example argument: 1
:return: Tuple of whether there is a default or not, and if yes the default
value, eg: for index 2 i.e. for "second_arg" this function returns (True, 42)
"""

DefaultArgSpec = namedtuple('DefaultArgSpec', 'has_default default_value')

if not defaults:
return DefaultArgSpec(False, None)

args_with_no_defaults = len(args) - len(defaults)

if arg_index < args_with_no_defaults:
return DefaultArgSpec(False, None)
else:
value = defaults[arg_index - args_with_no_defaults]
if (type(value) is str):
value = '"%s"' % value
return DefaultArgSpec(True, value)


def get_method_sig(method):
""" Given a function, it returns a string that pretty much looks how the
function signature would be written in python.
:param method: a python method
:return: A string similar describing the pythong method signature.
eg: "my_method(first_argArg, second_arg=42, third_arg='something')"
**From http://stackoverflow.com/a/11202399/4169**
"""

# The return value of ArgSpec is a bit weird, as the list of arguments and
# list of defaults are returned in separate array.
# eg: ArgSpec(args=['first_arg', 'second_arg', 'third_arg'],
# varargs=None, keywords=None, defaults=(42, 'something'))
argspec = inspect.getargspec(method)
arg_index = 0
args = []

# Use the args and defaults array returned by argspec and find out
# which arguments has default
for arg in argspec.args:
default_arg = _get_default_arg(argspec.args, argspec.defaults, arg_index)
if default_arg.has_default:
args.append("%s=%s" % (arg, default_arg.default_value))
else:
args.append(arg)
arg_index += 1
return "%s(%s)" % (method.__name__, ", ".join(args))
4 changes: 4 additions & 0 deletions tests/test_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ def test_docfields(self):
item['syntax']['parameters'][1]['description'],
'The foo param',
)
self.assertEqual(
item['syntax']['content'],
'method_okay(self, foo=None, bar=None)',
)

def test_vcs(self):
"""
Expand Down

0 comments on commit 4ab09a9

Please sign in to comment.