handle group objects in sphinxext
Update the sphinxext code to handle OptGroup instances as well as simple strings coming back from list_opts(). Change-Id: I14d19c43a1d119f2f49bc638505f232c0938015d Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
@@ -85,7 +85,7 @@ def _get_choice_text(choice):
|
||||
return six.text_type(choice)
|
||||
|
||||
|
||||
def _format_group(app, namespace, group_name, opt_list):
|
||||
def _format_group(app, namespace, group_name, group_obj, opt_list):
|
||||
group_name = group_name or 'DEFAULT'
|
||||
app.info('[oslo.config] %s %s' % (namespace, group_name))
|
||||
|
||||
@@ -94,6 +94,10 @@ def _format_group(app, namespace, group_name, opt_list):
|
||||
yield ' :namespace: %s' % namespace
|
||||
yield ''
|
||||
|
||||
if group_obj and group_obj.help:
|
||||
yield _indent(group_obj.help.rstrip())
|
||||
yield ''
|
||||
|
||||
for opt in opt_list:
|
||||
opt_type = _TYPE_DESCRIPTIONS.get(type(opt),
|
||||
'unknown type')
|
||||
@@ -155,16 +159,45 @@ def _format_option_help(app, namespaces, split_namespaces):
|
||||
|
||||
if split_namespaces:
|
||||
for namespace, opt_list in opts:
|
||||
for group_name, opts in opt_list:
|
||||
for line in _format_group(app, namespace, group_name, opts):
|
||||
for group, opts in opt_list:
|
||||
if isinstance(group, cfg.OptGroup):
|
||||
group_name = group.name
|
||||
else:
|
||||
group_name = group
|
||||
group = None
|
||||
lines = _format_group(
|
||||
app=app,
|
||||
namespace=namespace,
|
||||
group_name=group_name,
|
||||
group_obj=group,
|
||||
opt_list=opts,
|
||||
)
|
||||
for line in lines:
|
||||
yield line
|
||||
else:
|
||||
# Merge the options from different namespaces that belong to
|
||||
# the same group together and format them without the
|
||||
# namespace.
|
||||
by_section = {}
|
||||
group_objs = {}
|
||||
for ignore, opt_list in opts:
|
||||
for group_name, group_opts in opt_list:
|
||||
for group, group_opts in opt_list:
|
||||
if isinstance(group, cfg.OptGroup):
|
||||
group_name = group.name
|
||||
else:
|
||||
group_name = group
|
||||
group = None
|
||||
group_objs.setdefault(group_name, group)
|
||||
by_section.setdefault(group_name, []).extend(group_opts)
|
||||
for group_name, group_opts in sorted(by_section.items()):
|
||||
for line in _format_group(app, None, group_name, group_opts):
|
||||
lines = _format_group(
|
||||
app=app,
|
||||
namespace=None,
|
||||
group_name=group_name,
|
||||
group_obj=group_objs.get(group_name),
|
||||
opt_list=group_opts,
|
||||
)
|
||||
for line in lines:
|
||||
yield line
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ class FormatGroupTest(base.BaseTestCase):
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=[
|
||||
cfg.StrOpt('opt_name',
|
||||
help='this appears in the default group'),
|
||||
@@ -49,6 +50,7 @@ class FormatGroupTest(base.BaseTestCase):
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=[
|
||||
cfg.StrOpt('opt_name',
|
||||
default='this is the default',
|
||||
@@ -72,6 +74,7 @@ class FormatGroupTest(base.BaseTestCase):
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=[
|
||||
cfg.IntOpt('opt_name',
|
||||
min=1),
|
||||
@@ -93,6 +96,7 @@ class FormatGroupTest(base.BaseTestCase):
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=[
|
||||
cfg.IntOpt('opt_name',
|
||||
max=1),
|
||||
@@ -114,6 +118,7 @@ class FormatGroupTest(base.BaseTestCase):
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=[
|
||||
cfg.StrOpt('opt_name',
|
||||
choices=['a', 'b', 'c', None, '']),
|
||||
@@ -130,11 +135,52 @@ class FormatGroupTest(base.BaseTestCase):
|
||||
|
||||
''').lstrip(), results)
|
||||
|
||||
def test_group_obj_without_help(self):
|
||||
# option with None group placed in DEFAULT
|
||||
results = '\n'.join(list(sphinxext._format_group(
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name='group',
|
||||
group_obj=cfg.OptGroup('group'),
|
||||
opt_list=[cfg.StrOpt('opt_name')],
|
||||
)))
|
||||
self.assertEqual(textwrap.dedent('''
|
||||
.. oslo.config:group:: group
|
||||
|
||||
.. oslo.config:option:: opt_name
|
||||
|
||||
:Type: string
|
||||
:Default: ``<None>``
|
||||
|
||||
''').lstrip(), results)
|
||||
|
||||
def test_group_obj_with_help(self):
|
||||
# option with None group placed in DEFAULT
|
||||
results = '\n'.join(list(sphinxext._format_group(
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name='group',
|
||||
group_obj=cfg.OptGroup('group', help='group help'),
|
||||
opt_list=[cfg.StrOpt('opt_name')],
|
||||
)))
|
||||
self.assertEqual(textwrap.dedent('''
|
||||
.. oslo.config:group:: group
|
||||
|
||||
group help
|
||||
|
||||
.. oslo.config:option:: opt_name
|
||||
|
||||
:Type: string
|
||||
:Default: ``<None>``
|
||||
|
||||
''').lstrip(), results)
|
||||
|
||||
def test_deprecated_opts(self):
|
||||
results = '\n'.join(list(sphinxext._format_group(
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=[
|
||||
cfg.StrOpt('opt_name',
|
||||
deprecated_name='deprecated_name',
|
||||
@@ -164,6 +210,7 @@ class FormatGroupTest(base.BaseTestCase):
|
||||
app=mock.Mock(),
|
||||
namespace=None,
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=[
|
||||
cfg.StrOpt('opt_name',
|
||||
deprecated_for_removal=True,
|
||||
@@ -189,10 +236,18 @@ class FormatOptionHelpTest(base.BaseTestCase):
|
||||
namespaces=['namespace1', 'namespace2'],
|
||||
split_namespaces=True))
|
||||
_format_group.assert_any_call(
|
||||
None, 'namespace1', None, ['opt1'],
|
||||
app=None,
|
||||
namespace='namespace1',
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=['opt1'],
|
||||
)
|
||||
_format_group.assert_any_call(
|
||||
None, 'namespace2', None, ['opt2'],
|
||||
app=None,
|
||||
namespace='namespace2',
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=['opt2'],
|
||||
)
|
||||
|
||||
@mock.patch('oslo_config.generator._list_opts')
|
||||
@@ -207,5 +262,57 @@ class FormatOptionHelpTest(base.BaseTestCase):
|
||||
namespaces=['namespace1', 'namespace2'],
|
||||
split_namespaces=False))
|
||||
_format_group.assert_called_once_with(
|
||||
None, None, None, ['opt1', 'opt2'],
|
||||
app=None,
|
||||
namespace=None,
|
||||
group_name=None,
|
||||
group_obj=None,
|
||||
opt_list=['opt1', 'opt2'],
|
||||
)
|
||||
|
||||
@mock.patch('oslo_config.generator._list_opts')
|
||||
@mock.patch('oslo_config.sphinxext._format_group')
|
||||
def test_dont_split_namespaces_with_group(self, _format_group, _list_opts):
|
||||
grp_obj = cfg.OptGroup('grp1')
|
||||
_list_opts.return_value = [
|
||||
('namespace1', [(grp_obj, ['opt1'])]),
|
||||
('namespace2', [('grp1', ['opt2'])]),
|
||||
]
|
||||
list(sphinxext._format_option_help(
|
||||
app=None,
|
||||
namespaces=['namespace1', 'namespace2'],
|
||||
split_namespaces=False))
|
||||
_format_group.assert_any_call(
|
||||
app=None,
|
||||
namespace=None,
|
||||
group_name='grp1',
|
||||
group_obj=grp_obj,
|
||||
opt_list=['opt1', 'opt2'],
|
||||
)
|
||||
|
||||
@mock.patch('oslo_config.generator._list_opts')
|
||||
@mock.patch('oslo_config.sphinxext._format_group')
|
||||
def test_split_namespaces_with_group(self, _format_group, _list_opts):
|
||||
grp_obj = cfg.OptGroup('grp1')
|
||||
_list_opts.return_value = [
|
||||
('namespace1', [(grp_obj, ['opt1'])]),
|
||||
('namespace2', [('grp1', ['opt2'])]),
|
||||
]
|
||||
list(sphinxext._format_option_help(
|
||||
app=None,
|
||||
namespaces=['namespace1', 'namespace2'],
|
||||
split_namespaces=True))
|
||||
print(_format_group.call_args_list)
|
||||
_format_group.assert_any_call(
|
||||
app=None,
|
||||
namespace='namespace1',
|
||||
group_name='grp1',
|
||||
group_obj=grp_obj,
|
||||
opt_list=['opt1'],
|
||||
)
|
||||
_format_group.assert_any_call(
|
||||
app=None,
|
||||
namespace='namespace2',
|
||||
group_name='grp1',
|
||||
group_obj=None,
|
||||
opt_list=['opt2'],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user