|
|
|
|
@ -9,6 +9,7 @@ import yaml
|
|
|
|
|
|
|
|
|
|
from ansible import constants as C
|
|
|
|
|
from ansible.errors import AnsibleError, AnsibleParserError
|
|
|
|
|
from ansible.module_utils.basic import COMMON_ARGUMENTS_TO_FRAGMENTS
|
|
|
|
|
from ansible.module_utils.common.text.converters import to_text, to_native
|
|
|
|
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
|
|
|
|
from ansible.utils.display import Display
|
|
|
|
|
@ -65,31 +66,44 @@ def read_docstring_from_python_file(filename, verbose=True, ignore_errors=True):
|
|
|
|
|
with open(filename, 'rb') as b_module_data:
|
|
|
|
|
M = ast.parse(b_module_data.read())
|
|
|
|
|
|
|
|
|
|
for child in M.body:
|
|
|
|
|
for child in ast.walk(M):
|
|
|
|
|
if isinstance(child, ast.Assign):
|
|
|
|
|
for t in child.targets:
|
|
|
|
|
try:
|
|
|
|
|
theid = t.id
|
|
|
|
|
except AttributeError:
|
|
|
|
|
# skip errors can happen when trying to use the normal code
|
|
|
|
|
display.warning("Building documentation, failed to assign id for %s on %s, skipping" % (t, filename))
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if theid in string_to_vars:
|
|
|
|
|
varkey = string_to_vars[theid]
|
|
|
|
|
if isinstance(child.value, ast.Dict):
|
|
|
|
|
data[varkey] = ast.literal_eval(child.value)
|
|
|
|
|
else:
|
|
|
|
|
if theid == 'EXAMPLES':
|
|
|
|
|
# examples 'can' be yaml, but even if so, we dont want to parse as such here
|
|
|
|
|
# as it can create undesired 'objects' that don't display well as docs.
|
|
|
|
|
data[varkey] = to_text(child.value.value)
|
|
|
|
|
# Find the AnsibleModule(extend_common_args=...) and extend fragments
|
|
|
|
|
if isinstance(child.value, ast.Call) and getattr(child.value.func, 'id', None) == 'AnsibleModule': # Magic string
|
|
|
|
|
for kw in child.value.keywords:
|
|
|
|
|
if kw.arg == 'extends_common_args' and isinstance(kw.value, ast.Tuple): # Magic string
|
|
|
|
|
if data['doc'] is None:
|
|
|
|
|
if 'extends_documentation_fragment' not in data['doc']:
|
|
|
|
|
data['doc']['extends_documentation_fragment'] = []
|
|
|
|
|
for arg_name_node in kw.value.elts:
|
|
|
|
|
if isinstance(arg_name_node, ast.Name):
|
|
|
|
|
fragment_name = COMMON_ARGUMENTS_TO_FRAGMENTS[arg_name_node.id]
|
|
|
|
|
data['doc']['extends_documentation_fragment'].append(fragment_name)
|
|
|
|
|
# If it's top level, find the specified docs
|
|
|
|
|
if child in M.body:
|
|
|
|
|
for t in child.targets:
|
|
|
|
|
try:
|
|
|
|
|
theid = t.id
|
|
|
|
|
except AttributeError:
|
|
|
|
|
# skip errors can happen when trying to use the normal code
|
|
|
|
|
display.warning("Building documentation, failed to assign id for %s on %s, skipping" % (t, filename))
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if theid in string_to_vars:
|
|
|
|
|
varkey = string_to_vars[theid]
|
|
|
|
|
if isinstance(child.value, ast.Dict):
|
|
|
|
|
data[varkey] = ast.literal_eval(child.value)
|
|
|
|
|
else:
|
|
|
|
|
# string should be yaml if already not a dict
|
|
|
|
|
child_value = _tags.Origin(path=filename, line_num=child.value.lineno).tag(child.value.value)
|
|
|
|
|
data[varkey] = yaml.load(child_value, Loader=AnsibleLoader)
|
|
|
|
|
|
|
|
|
|
display.debug('Documentation assigned: %s' % varkey)
|
|
|
|
|
if theid == 'EXAMPLES':
|
|
|
|
|
# examples 'can' be yaml, but even if so, we dont want to parse as such here
|
|
|
|
|
# as it can create undesired 'objects' that don't display well as docs.
|
|
|
|
|
data[varkey] = to_text(child.value.value)
|
|
|
|
|
else:
|
|
|
|
|
# string should be yaml if already not a dict
|
|
|
|
|
child_value = _tags.Origin(path=filename, line_num=child.value.lineno).tag(child.value.value)
|
|
|
|
|
data[varkey] = yaml.load(child_value, Loader=AnsibleLoader)
|
|
|
|
|
|
|
|
|
|
display.debug('Documentation assigned: %s' % varkey)
|
|
|
|
|
|
|
|
|
|
except Exception as ex:
|
|
|
|
|
msg = f"Unable to parse documentation in python file {filename!r}"
|
|
|
|
|
|