Start using pydocstyle for Python doc generation

pull/78/head
Eric Holscher 8 years ago
parent 7f50c62e35
commit b24293e545

@ -1,15 +1,9 @@
from collections import defaultdict from collections import defaultdict
import sys
from .base import PythonMapperBase, SphinxMapperBase from .base import PythonMapperBase, SphinxMapperBase
from ..utils import slugify
if sys.version_info < (3,): from pydocstyle import parse
from epyparse import parsed
else:
# Don't raise exception on module level because it would
# break all backends on Python 3
def parsed(path):
raise Exception('Python 3 not supported')
class PythonSphinxMapper(SphinxMapperBase): class PythonSphinxMapper(SphinxMapperBase):
@ -28,7 +22,7 @@ class PythonSphinxMapper(SphinxMapperBase):
''' '''
try: try:
parsed_data = parsed(path) parsed_data = parse(open(path), path)
return parsed_data return parsed_data
except IOError: except IOError:
self.app.warn('Error reading file: {0}'.format(path)) self.app.warn('Error reading file: {0}'.format(path))
@ -39,32 +33,23 @@ class PythonSphinxMapper(SphinxMapperBase):
return None return None
def create_class(self, data, options=None, **kwargs): def create_class(self, data, options=None, **kwargs):
'''Return instance of class based on Roslyn type property '''
Create a class from the passed in data
Data keys handled here:
type
Set the object class
items
Recurse into :py:meth:`create_class` to create child object
instances
:param data: dictionary data of epydoc output :param data: dictionary data of pydocstyle output
''' '''
obj_map = dict((cls.type, cls) for cls obj_map = dict((cls.type, cls) for cls
in [PythonClass, PythonFunction, PythonModule]) in [PythonClass, PythonFunction, PythonModule, PythonMethod])
try: try:
cls = obj_map[data['type']] cls = obj_map[data.kind]
except KeyError: except KeyError:
self.app.warn("Unknown Type: %s" % data['type']) self.app.warn("Unknown Type: %s" % data.kind)
else: else:
obj = cls(data, jinja_env=self.jinja_env, options=self.app.config.autoapi_options) obj = cls(data, jinja_env=self.jinja_env, options=self.app.config.autoapi_options)
if 'children' in data: for child_data in data.children:
for child_data in data['children']: for child_obj in self.create_class(child_data, options=options):
for child_obj in self.create_class(child_data, options=options): obj.children.append(child_obj)
obj.children.append(child_obj) self.add_object(child_obj)
self.add_object(child_obj)
yield obj yield obj
@ -76,17 +61,25 @@ class PythonPythonMapper(PythonMapperBase):
super(PythonPythonMapper, self).__init__(obj, **kwargs) super(PythonPythonMapper, self).__init__(obj, **kwargs)
# Always exist # Always exist
self.id = obj['fullname'] name = obj.name.split('/')[-1]
self.name = self.obj.get('fullname', self.id) self.id = slugify(name)
self.name = name
# Optional # Optional
self.imports = obj.get('imports', [])
self.children = [] self.children = []
self.args = obj.get('args', []) try:
self.params = obj.get('params', []) args = obj.source.split('\n')[0]
self.docstring = obj.get('docstring', '') args = args.split('(')[1]
self.methods = obj.get('methods', []) args = args.split(')')[0]
self.inheritance = obj.get('bases', []) self.args = args.split(',')
except:
args = ''
self.docstring = obj.docstring or ''
self.docstring = self.docstring.replace("'''", '').replace('"""', '')
if getattr(obj, 'parent'):
self.inheritance = [obj.parent.name]
else:
self.inheritance = ''
# For later # For later
self.item_map = defaultdict(list) self.item_map = defaultdict(list)
@ -118,6 +111,10 @@ class PythonFunction(PythonPythonMapper):
type = 'function' type = 'function'
class PythonMethod(PythonPythonMapper):
type = 'method'
class PythonModule(PythonPythonMapper): class PythonModule(PythonPythonMapper):
type = 'module' type = 'module'
top_level_object = True top_level_object = True

@ -1,18 +1,10 @@
{% if not 'nested' in obj._human %}
{{ obj.short_name }} {{ obj.short_name }}
{{ "-" * obj.short_name|length }} {{ "-" * obj.short_name|length }}
{% endif %}
.. py:class:: {{ obj.short_name }}{% if obj.args %}({{ obj.args|join(',') }}){% endif %} .. py:class:: {{ obj.short_name }}{% if obj.args %}({{ obj.args|join(',') }}){% endif %}
{%- if obj.inheritance %}
.. rubric:: Imports
{% for import in obj.inheritance %}
* {{ import }}
{% endfor %}
{% endif %}
{%- if obj.docstring %} {%- if obj.docstring %}
.. rubric:: Summary .. rubric:: Summary

@ -1,13 +1,8 @@
{%- if obj.display %} {%- if obj.display %}
{%- if is_method %}
{# Slice self off #}
.. method:: {{ obj.name.split('.')[-1] }}({{ obj.args[1:]|join(',') }})
{% else %}
.. function:: {{ obj.name.split('.')[-1] }}({{ obj.args|join(',') }}) .. function:: {{ obj.name.split('.')[-1] }}({{ obj.args|join(',') }})
{% endif %}
{%- if obj.docstring %} {% if obj.docstring %}
{{ obj.docstring.strip()|indent(3) }} {{ obj.docstring.strip()|indent(3) }}
{% endif %} {% endif %}

@ -0,0 +1,9 @@
{%- if obj.display %}
.. method:: {{ obj.name.split('.')[-1] }}({{ obj.args[1:]|join(',') }})
{% if obj.docstring %}
{{ obj.docstring.strip()|indent(3) }}
{% endif %}
{% endif %}

@ -0,0 +1,14 @@
import unicodedata
import re
# From Django
def slugify(value):
"""
Converts to lowercase, removes non-word characters (alphanumerics and
underscores) and converts spaces to hyphens. Also strips leading and
trailing whitespace.
"""
value = re.sub('[^\w\s-]', '', value).strip()
return re.sub('[-\s]+', '-', value)

@ -1,9 +1,8 @@
epydoc==3.0.1 pydocstyle==1.0.0
epyparse==0.2.5
PyYAML==3.11 PyYAML==3.11
wheel==0.24.0 wheel==0.24.0
sphinx==1.3.1 sphinx
sphinxcontrib-golangdomain #sphinxcontrib-golangdomain
sphinxcontrib-dotnetdomain sphinxcontrib-dotnetdomain
pytest pytest
mock mock

@ -4,10 +4,8 @@ try:
extra_setup = dict( extra_setup = dict(
install_requires=[ install_requires=[
'PyYAML', 'PyYAML',
'epyparse',
'epydoc',
'sphinx', 'sphinx',
'sphinxcontrib-golangdomain', #'sphinxcontrib-golangdomain',
'sphinxcontrib-dotnetdomain', 'sphinxcontrib-dotnetdomain',
'unidecode', 'unidecode',
], ],

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save