Skip to content

Commit

Permalink
Fix catalog collections script to display all available modules in a …
Browse files Browse the repository at this point in the history
…collection (#1738)

* Fix catalog collections script

* Parse examples, returndocs, metadata info

* Add test for get_doc_withast function

* Pre-commit and other logic fixes

* Improve code coverage

* Add test

* Fix test_catalog_collections.py

* More fixes in test_catalog_collections.py

* Add test_worker_with_mocked_get_docstring

* More fixes in test
  • Loading branch information
shatakshiiii authored Apr 24, 2024
1 parent cba44f8 commit d494578
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 6 deletions.
1 change: 1 addition & 0 deletions .config/dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,6 @@ usefixtures
userbase
viewcode
volmount
withast
workdir
xmss
2 changes: 1 addition & 1 deletion src/ansible_navigator/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def main() -> None:

if args.execution_environment:
pull_image(args)
cache_scripts()
cache_scripts()

run_return = run(args)
run_message = f"{run_return.message}\n"
Expand Down
45 changes: 41 additions & 4 deletions src/ansible_navigator/data/catalog_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import argparse
import ast
import hashlib
import json
import multiprocessing
Expand Down Expand Up @@ -360,6 +361,7 @@ def worker(
:param completed_queue: The queue in which extracted documentation will be placed
"""
# pylint: disable=import-outside-toplevel
# pylint: disable=too-many-locals

# load the fragment_loader _after_ the path is set
from ansible.plugins.loader import fragment_loader
Expand All @@ -383,10 +385,19 @@ def worker(
collection_name=collection_name,
)

except Exception as exc: # noqa: BLE001
err_message = f"{type(exc).__name__} (get_docstring): {exc!s}"
completed_queue.put(("error", (checksum, plugin_path, err_message)))
continue
except Exception: # noqa: BLE001
try:
with plugin_path.open(mode="r", encoding="utf-8") as f:
content = f.read()
doc, examples, returndocs, metadata = get_doc_withast(content)
doc, examples, returndocs, metadata = (
yaml.load(value, Loader=yaml.SafeLoader)
for value in (doc, examples, returndocs, metadata)
)
except Exception as exc: # noqa: BLE001
err_message = f"{type(exc).__name__} (get_docstring): {exc!s}"
completed_queue.put(("error", (checksum, plugin_path, err_message)))
continue

try:
q_message = {
Expand Down Expand Up @@ -532,6 +543,32 @@ def retrieve_docs(
stats["cache_added_errors"] += 1


def get_doc_withast(content: Any) -> tuple[Any, Any, Any, Any]:
"""Get the documentation, examples, returndocs, and metadata from the content using ast.
:param content: The content to parse using ast.
:return: A tuple containing the documentation, examples, returndocs, and metadata.
"""
doc, examples, returndocs, metadata = "", "", "", ""

# Parse the content using ast and walk through nodes
for node in ast.walk(ast.parse(content)):
if isinstance(node, ast.Assign) and isinstance(node.targets[0], ast.Name):
target_id = node.targets[0].id

# Check if node.value is an instance of ast.Constant and its value is a string
if isinstance(node.value, ast.Constant) and isinstance(node.value.value, str):
if target_id == "DOCUMENTATION":
doc = node.value.value.strip()
elif target_id == "EXAMPLES":
examples = node.value.value.strip()
elif target_id == "RETURN":
returndocs = node.value.value.strip()
elif target_id == "METADATA":
metadata = node.value.value.strip()
return doc, examples, returndocs, metadata


def run_command(cmd: list[str]) -> dict[str, str]:
"""Run a command using subprocess.
Expand Down
17 changes: 17 additions & 0 deletions tests/fixtures/common/module_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""An ansible test module."""

DOCUMENTATION = r"""
---
module: vcenter_mod
short_description: Gather info vCenter extensions
description:
- This module can be used to gather information about vCenter extension.
author:
- test
extends_documentation_fragment:
- community.vmware.vmware.documentation
"""

EXAMPLES = "Example usage here."
RETURN = "This function returns a value."
METADATA = "Author: John Doe"
54 changes: 54 additions & 0 deletions tests/unit/test_catalog_collections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Unit tests for catalog collections."""

import multiprocessing

from pathlib import Path
from typing import Any

from ansible_navigator.data.catalog_collections import worker


def test_worker_with_failed_get_docstring() -> None:
"""Test worker function when get_docstring fails and get_doc_withast method is used to parse the content."""
# Create the queues
pending_queue: multiprocessing.Queue[Any] = multiprocessing.Queue()
completed_queue: multiprocessing.Queue[Any] = multiprocessing.Queue()

plugin_path = Path("tests/fixtures/common/module_1.py")
collection_name = "microsoft.ad"
checksum = "12345"

# Add an entry to the pending queue
entry = collection_name, checksum, plugin_path
pending_queue.put(entry)

# Add a None entry to signal the end of processing
pending_queue.put(None)

worker(pending_queue, completed_queue)

plugin_path, data = completed_queue.get()
assert "vCenter" in data[1]


def test_worker_with_invalid_plugin_path() -> None:
"""Test the worker function when get_docstring has invalid plugin_path."""
pending_queue: multiprocessing.Queue[Any] = multiprocessing.Queue()
completed_queue: multiprocessing.Queue[Any] = multiprocessing.Queue()

plugin_path = Path("tests/fixtures/common/xyz.py")
collection_name = "microsoft.ad"
checksum = "12345"

# Add an entry to the pending queue
entry = collection_name, checksum, plugin_path
pending_queue.put(entry)

# Add a None entry to signal the end of processing
pending_queue.put(None)

worker(pending_queue, completed_queue)

plugin_path, data = completed_queue.get()
assert plugin_path == "error"
assert "FileNotFoundError (get_docstring)" in data[2]
27 changes: 26 additions & 1 deletion tests/unit/utils/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import pytest

from ansible_navigator.data.catalog_collections import get_doc_withast
from ansible_navigator.utils import functions


Expand Down Expand Up @@ -299,6 +300,30 @@ def test_now_iso(caplog: pytest.LogCaptureFixture, time_zone: str) -> None:
),
)
def test_unescape_moustaches(data: Any, output: Any) -> None:
"""Tests unescape_moustaches."""
"""Tests unescape_moustaches.
:param data: The input data.
:param output: The expected output.
"""
result = functions.unescape_moustaches(data)
assert result == output


def test_get_doc_withast() -> None:
"""Test for the get_doc_withast function.
This test ensures that the get_doc_withast function correctly extracts the documentation,
examples, returndocs, and metadata from the module content.
"""
module_content = """
DOCUMENTATION = "This is a test documentation."
EXAMPLES = "Example usage here."
RETURN = "This function returns a value."
METADATA = "Author: John Doe"
"""

doc, examples, returndocs, metadata = get_doc_withast(module_content)
assert doc == "This is a test documentation."
assert examples == "Example usage here."
assert returndocs == "This function returns a value."
assert metadata == "Author: John Doe"

0 comments on commit d494578

Please sign in to comment.