Merged in dhellmann/wsme-sphinx (pull request #5)
This commit is contained in:
commit
f9b76d3a5d
@ -3,6 +3,7 @@ import sphinx
|
|||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
import wsme.types
|
import wsme.types
|
||||||
|
from wsme import sphinxext
|
||||||
|
|
||||||
docpath = os.path.join(
|
docpath = os.path.join(
|
||||||
os.path.dirname(__file__),
|
os.path.dirname(__file__),
|
||||||
@ -24,3 +25,21 @@ class TestSphinxExt(unittest.TestCase):
|
|||||||
'-d', '.test_sphinxext/doctree',
|
'-d', '.test_sphinxext/doctree',
|
||||||
docpath,
|
docpath,
|
||||||
'.test_sphinxext/html']) == 0
|
'.test_sphinxext/html']) == 0
|
||||||
|
|
||||||
|
|
||||||
|
class TestDataTypeName(unittest.TestCase):
|
||||||
|
def test_user_type(self):
|
||||||
|
self.assertEqual(sphinxext.datatypename(ASampleType),
|
||||||
|
'ASampleType')
|
||||||
|
|
||||||
|
def test_dict_type(self):
|
||||||
|
d = wsme.types.DictType(str, str)
|
||||||
|
self.assertEqual(sphinxext.datatypename(d), 'dict(str: str)')
|
||||||
|
d = wsme.types.DictType(str, ASampleType)
|
||||||
|
self.assertEqual(sphinxext.datatypename(d), 'dict(str: ASampleType)')
|
||||||
|
|
||||||
|
def test_array_type(self):
|
||||||
|
d = wsme.types.ArrayType(str)
|
||||||
|
self.assertEqual(sphinxext.datatypename(d), 'list(str)')
|
||||||
|
d = wsme.types.ArrayType(ASampleType)
|
||||||
|
self.assertEqual(sphinxext.datatypename(d), 'list(ASampleType)')
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -57,6 +58,7 @@ def wsexpose(*args, **kwargs):
|
|||||||
funcdef = wsme.api.FunctionDefinition.get(f)
|
funcdef = wsme.api.FunctionDefinition.get(f)
|
||||||
funcdef.resolve_types(wsme.types.registry)
|
funcdef.resolve_types(wsme.types.registry)
|
||||||
|
|
||||||
|
@functools.wraps(f)
|
||||||
def callfunction(self, *args, **kwargs):
|
def callfunction(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
args, kwargs = wsme.rest.args.get_args(
|
args, kwargs = wsme.rest.args.get_args(
|
||||||
|
@ -27,6 +27,11 @@ field_re = re.compile(r':(?P<field>\w+)(\s+(?P<name>\w+))?:')
|
|||||||
def datatypename(datatype):
|
def datatypename(datatype):
|
||||||
if isinstance(datatype, wsme.types.UserType):
|
if isinstance(datatype, wsme.types.UserType):
|
||||||
return datatype.name
|
return datatype.name
|
||||||
|
if isinstance(datatype, wsme.types.DictType):
|
||||||
|
return 'dict(%s: %s)' % (datatypename(datatype.key_type),
|
||||||
|
datatypename(datatype.value_type))
|
||||||
|
if isinstance(datatype, wsme.types.ArrayType):
|
||||||
|
return 'list(%s)' % datatypename(datatype.item_type)
|
||||||
return datatype.__name__
|
return datatype.__name__
|
||||||
|
|
||||||
|
|
||||||
@ -157,15 +162,36 @@ class AttributeDirective(PyClassmember):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def check_samples_slot(value):
|
||||||
|
"""Validate the samples_slot option to the TypeDocumenter.
|
||||||
|
|
||||||
|
Valid positions are 'before-docstring' and
|
||||||
|
'after-docstring'. Using the explicit 'none' disables sample
|
||||||
|
output. The default is after-docstring.
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return 'after-docstring'
|
||||||
|
val = directives.choice(
|
||||||
|
value,
|
||||||
|
('none', # do not include
|
||||||
|
'before-docstring', # show samples then docstring
|
||||||
|
'after-docstring', # show docstring then samples
|
||||||
|
))
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
class TypeDocumenter(autodoc.ClassDocumenter):
|
class TypeDocumenter(autodoc.ClassDocumenter):
|
||||||
objtype = 'type'
|
objtype = 'type'
|
||||||
directivetype = 'type'
|
directivetype = 'type'
|
||||||
domain = 'wsme'
|
domain = 'wsme'
|
||||||
|
|
||||||
required_arguments = 1
|
required_arguments = 1
|
||||||
|
default_samples_slot = 'after-docstring'
|
||||||
|
|
||||||
option_spec = dict(autodoc.ClassDocumenter.option_spec, **{
|
option_spec = dict(
|
||||||
'protocols': lambda l: [v.strip() for v in l.split(',')]
|
autodoc.ClassDocumenter.option_spec,
|
||||||
|
**{'protocols': lambda l: [v.strip() for v in l.split(',')],
|
||||||
|
'samples-slot': check_samples_slot,
|
||||||
})
|
})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -194,6 +220,16 @@ class TypeDocumenter(autodoc.ClassDocumenter):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def add_content(self, more_content, no_docstring=False):
|
def add_content(self, more_content, no_docstring=False):
|
||||||
|
# Check where to include the samples
|
||||||
|
samples_slot = self.options.samples_slot or self.default_samples_slot
|
||||||
|
|
||||||
|
print 'SAMPLES SLOT:', self.options.samples_slot
|
||||||
|
|
||||||
|
def add_docstring():
|
||||||
|
super(TypeDocumenter, self).add_content(
|
||||||
|
more_content, no_docstring)
|
||||||
|
|
||||||
|
def add_samples():
|
||||||
protocols = get_protocols(
|
protocols = get_protocols(
|
||||||
self.options.protocols or self.env.app.config.wsme_protocols
|
self.options.protocols or self.env.app.config.wsme_protocols
|
||||||
)
|
)
|
||||||
@ -220,8 +256,15 @@ class TypeDocumenter(autodoc.ClassDocumenter):
|
|||||||
self.add_line(line, u'<wsme.sphinxext')
|
self.add_line(line, u'<wsme.sphinxext')
|
||||||
|
|
||||||
self.add_line(u'', '<wsme.sphinxext>')
|
self.add_line(u'', '<wsme.sphinxext>')
|
||||||
super(TypeDocumenter, self).add_content(
|
|
||||||
more_content, no_docstring)
|
if samples_slot == 'after-docstring':
|
||||||
|
add_docstring()
|
||||||
|
add_samples()
|
||||||
|
elif samples_slot == 'before-docstring':
|
||||||
|
add_samples()
|
||||||
|
add_docstring()
|
||||||
|
else:
|
||||||
|
add_docstring()
|
||||||
|
|
||||||
|
|
||||||
class AttributeDocumenter(autodoc.AttributeDocumenter):
|
class AttributeDocumenter(autodoc.AttributeDocumenter):
|
||||||
@ -341,13 +384,14 @@ class FunctionDocumenter(autodoc.MethodDocumenter):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_document_member(cls, member, membername, isattr, parent):
|
def can_document_member(cls, member, membername, isattr, parent):
|
||||||
return wsme.api.iswsmefunction(member)
|
return (isinstance(parent, ServiceDocumenter)
|
||||||
|
and wsme.api.iswsmefunction(member))
|
||||||
|
|
||||||
def import_object(self):
|
def import_object(self):
|
||||||
ret = super(FunctionDocumenter, self).import_object()
|
ret = super(FunctionDocumenter, self).import_object()
|
||||||
self.directivetype = 'function'
|
self.directivetype = 'function'
|
||||||
self.wsme_fd = wsme.api.FunctionDefinition.get(self.object)
|
self.wsme_fd = wsme.api.FunctionDefinition.get(self.object)
|
||||||
self.retann = self.wsme_fd.return_type.__name__
|
self.retann = datatypename(self.wsme_fd.return_type)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def format_args(self):
|
def format_args(self):
|
||||||
@ -360,6 +404,10 @@ class FunctionDocumenter(autodoc.MethodDocumenter):
|
|||||||
"""Inject the type and param fields into the docstrings so that the
|
"""Inject the type and param fields into the docstrings so that the
|
||||||
user can add its own param fields to document the parameters"""
|
user can add its own param fields to document the parameters"""
|
||||||
docstrings = super(FunctionDocumenter, self).get_doc(encoding)
|
docstrings = super(FunctionDocumenter, self).get_doc(encoding)
|
||||||
|
# If the function doesn't have a docstring, add an empty list
|
||||||
|
# so the default behaviors below work correctly.
|
||||||
|
if not docstrings:
|
||||||
|
docstrings.append([])
|
||||||
found_params = set()
|
found_params = set()
|
||||||
|
|
||||||
protocols = get_protocols(
|
protocols = get_protocols(
|
||||||
@ -390,14 +438,13 @@ class FunctionDocumenter(autodoc.MethodDocumenter):
|
|||||||
and m.group('name') == arg.name:
|
and m.group('name') == arg.name:
|
||||||
pos = (si, i + 1)
|
pos = (si, i + 1)
|
||||||
break
|
break
|
||||||
break
|
|
||||||
docstring = docstrings[pos[0]]
|
docstring = docstrings[pos[0]]
|
||||||
docstring[pos[1]:pos[1]] = content
|
docstring[pos[1]:pos[1]] = content
|
||||||
next_param_pos = (pos[0], pos[1] + len(content))
|
next_param_pos = (pos[0], pos[1] + len(content))
|
||||||
|
|
||||||
if self.wsme_fd.return_type:
|
if self.wsme_fd.return_type:
|
||||||
content = [
|
content = [
|
||||||
u':rtype: %s' % self.wsme_fd.return_type.__name__
|
u':rtype: %s' % datatypename(self.wsme_fd.return_type)
|
||||||
]
|
]
|
||||||
pos = None
|
pos = None
|
||||||
for si, docstring in enumerate(docstrings):
|
for si, docstring in enumerate(docstrings):
|
||||||
@ -406,8 +453,7 @@ class FunctionDocumenter(autodoc.MethodDocumenter):
|
|||||||
if m and m.group('field') == 'return':
|
if m and m.group('field') == 'return':
|
||||||
pos = (si, i + 1)
|
pos = (si, i + 1)
|
||||||
break
|
break
|
||||||
break
|
else:
|
||||||
if pos is None:
|
|
||||||
pos = next_param_pos
|
pos = next_param_pos
|
||||||
docstring = docstrings[pos[0]]
|
docstring = docstrings[pos[0]]
|
||||||
docstring[pos[1]:pos[1]] = content
|
docstring[pos[1]:pos[1]] = content
|
||||||
|
@ -355,3 +355,15 @@ class TestTypes(unittest.TestCase):
|
|||||||
def test_array_eq(self):
|
def test_array_eq(self):
|
||||||
l = [types.ArrayType(str)]
|
l = [types.ArrayType(str)]
|
||||||
assert types.ArrayType(str) in l
|
assert types.ArrayType(str) in l
|
||||||
|
|
||||||
|
def test_array_sample(self):
|
||||||
|
s = types.ArrayType(str).sample()
|
||||||
|
assert isinstance(s, list)
|
||||||
|
assert s
|
||||||
|
assert s[0] == ''
|
||||||
|
|
||||||
|
def test_dict_sample(self):
|
||||||
|
s = types.DictType(str, str).sample()
|
||||||
|
assert isinstance(s, dict)
|
||||||
|
assert s
|
||||||
|
assert s == {'': ''}
|
||||||
|
@ -34,6 +34,9 @@ class ArrayType(object):
|
|||||||
return isinstance(other, ArrayType) \
|
return isinstance(other, ArrayType) \
|
||||||
and self.item_type == other.item_type
|
and self.item_type == other.item_type
|
||||||
|
|
||||||
|
def sample(self):
|
||||||
|
return [getattr(self.item_type, 'sample', self.item_type)()]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def item_type(self):
|
def item_type(self):
|
||||||
if isinstance(self._item_type, weakref.ref):
|
if isinstance(self._item_type, weakref.ref):
|
||||||
@ -67,6 +70,11 @@ class DictType(object):
|
|||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash((self.key_type, self.value_type))
|
return hash((self.key_type, self.value_type))
|
||||||
|
|
||||||
|
def sample(self):
|
||||||
|
key = getattr(self.key_type, 'sample', self.key_type)()
|
||||||
|
value = getattr(self.value_type, 'sample', self.value_type)()
|
||||||
|
return {key: value}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value_type(self):
|
def value_type(self):
|
||||||
if isinstance(self._value_type, weakref.ref):
|
if isinstance(self._value_type, weakref.ref):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user