Use pydoc for formatting docstrings
pydoc is part of the standard library and is much more robust at formatting docstings than any trivial hand-rolled munger could be. For example, it correctly preserves indentation within the docstring. Use it when generating descriptions from docstrings for the API. Change-Id: Ib565a64d990a45c652a9475255c37805f86070b4
This commit is contained in:
parent
d42ce99218
commit
331df3abe8
|
@ -625,10 +625,3 @@ def format_snapshot(snapshot):
|
|||
heat_timeutils.isotime(snapshot.created_at),
|
||||
}
|
||||
return result
|
||||
|
||||
|
||||
def build_resource_description(docstring):
|
||||
if docstring is not None:
|
||||
return '\n'.join(map(lambda x: x.strip(), docstring.split('\n')))
|
||||
else:
|
||||
return _('No description given')
|
||||
|
|
|
@ -636,18 +636,18 @@ class ResourceRegistry(object):
|
|||
return (version is None or
|
||||
cls.get_class().support_status.version == version)
|
||||
|
||||
def resource_description(name, cls, with_description):
|
||||
import heat.engine.resource
|
||||
|
||||
def resource_description(name, info, with_description):
|
||||
if not with_description:
|
||||
return name
|
||||
if cls.description == 'Plugin':
|
||||
rsrc = cls.value
|
||||
elif cls.description == 'Template':
|
||||
rsrc = cls.get_class()
|
||||
else:
|
||||
rsrc = None
|
||||
rsrc_cls = info.get_class()
|
||||
if rsrc_cls is None:
|
||||
rsrc_cls = heat.engine.resource.Resource
|
||||
return {
|
||||
'resource_type': name,
|
||||
'description': rsrc.__doc__}
|
||||
'description': rsrc_cls.getdoc(),
|
||||
}
|
||||
|
||||
return [resource_description(name, cls, with_description)
|
||||
for name, cls in six.iteritems(self._registry)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
import base64
|
||||
import contextlib
|
||||
import datetime as dt
|
||||
import pydoc
|
||||
import weakref
|
||||
|
||||
from oslo_config import cfg
|
||||
|
@ -310,6 +311,12 @@ class Resource(object):
|
|||
def external_id(self):
|
||||
return self.t.external_id()
|
||||
|
||||
@classmethod
|
||||
def getdoc(cls):
|
||||
if cls.__doc__ is None:
|
||||
return _('No description available')
|
||||
return pydoc.getdoc(cls)
|
||||
|
||||
@property
|
||||
def stack(self):
|
||||
stack = self._stackref()
|
||||
|
|
|
@ -16,6 +16,7 @@ import datetime
|
|||
import functools
|
||||
import itertools
|
||||
import os
|
||||
import pydoc
|
||||
import socket
|
||||
|
||||
import eventlet
|
||||
|
@ -1533,10 +1534,6 @@ class EngineService(service.ServiceBase):
|
|||
type_name=type_name,
|
||||
version=heat_version,
|
||||
with_description=with_description)
|
||||
if with_description:
|
||||
for resource_type in result:
|
||||
resource_type['description'] = api.build_resource_description(
|
||||
resource_type['description'])
|
||||
return result
|
||||
|
||||
def list_template_versions(self, cnxt):
|
||||
|
@ -1591,10 +1588,7 @@ class EngineService(service.ServiceBase):
|
|||
functions = []
|
||||
for func_name, func in six.iteritems(supported_funcs):
|
||||
if func is not hot_functions.Removed:
|
||||
if func.__doc__.split('\n')[0]:
|
||||
desc = func.__doc__.split('\n')[0].strip()
|
||||
else:
|
||||
desc = func.__doc__.split('\n')[1].strip()
|
||||
desc = pydoc.splitdoc(pydoc.getdoc(func))[0]
|
||||
functions.append(
|
||||
{'functions': func_name,
|
||||
'description': desc}
|
||||
|
@ -1617,6 +1611,8 @@ class EngineService(service.ServiceBase):
|
|||
type_name)
|
||||
raise exception.InvalidGlobalResource(type_name=type_name)
|
||||
|
||||
assert resource_class is not None
|
||||
|
||||
if resource_class.support_status.status == support.HIDDEN:
|
||||
raise exception.NotSupported(feature=type_name)
|
||||
|
||||
|
@ -1657,9 +1653,7 @@ class EngineService(service.ServiceBase):
|
|||
resource_class.support_status.to_dict()
|
||||
}
|
||||
if with_description:
|
||||
docstring = resource_class.__doc__
|
||||
description = api.build_resource_description(docstring)
|
||||
result[rpc_api.RES_SCHEMA_DESCRIPTION] = description
|
||||
result[rpc_api.RES_SCHEMA_DESCRIPTION] = resource_class.getdoc()
|
||||
return result
|
||||
|
||||
def generate_template(self, cnxt, type_name, template_type='cfn'):
|
||||
|
|
|
@ -76,14 +76,14 @@ class ResourceTypeTest(common.HeatTestCase):
|
|||
description = ("Heat Template Resource for Designate Domain.\n\n"
|
||||
"Designate provides DNS-as-a-Service services for "
|
||||
"OpenStack. So, domain\nis a realm with an "
|
||||
"identification string, unique in DNS.\n")
|
||||
"identification string, unique in DNS.")
|
||||
self.assertIn({'resource_type': 'OS::Designate::Domain',
|
||||
'description': description}, resources)
|
||||
self.assertIn({'resource_type': 'AWS::RDS::DBInstance',
|
||||
'description': 'Builtin AWS::RDS::DBInstance'},
|
||||
resources)
|
||||
self.assertIn({'resource_type': 'AWS::EC2::Instance',
|
||||
'description': 'No description given'},
|
||||
'description': 'No description available'},
|
||||
resources)
|
||||
|
||||
def test_resource_schema(self):
|
||||
|
@ -117,7 +117,7 @@ class ResourceTypeTest(common.HeatTestCase):
|
|||
'message': None,
|
||||
'previous_status': None
|
||||
},
|
||||
'description': 'No description given'
|
||||
'description': 'No description available'
|
||||
}
|
||||
|
||||
schema = self.eng.resource_schema(self.ctx, type_name=type_name,
|
||||
|
|
Loading…
Reference in New Issue