Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions src/askui/reporting.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import base64
import io
import json
import platform
import random
Expand Down Expand Up @@ -347,3 +348,80 @@ def generate(self) -> None:
f"{random.randint(0, 1000):03}.html"
)
report_path.write_text(html)


class AllureReporter(Reporter):
"""A reporter that integrates with Allure Framework for test reporting.

This reporter creates Allure test reports by recording agent interactions as test steps
and attaching screenshots. It requires one of the allure Python packages to be installed.

The AllureReporter uses eager loading - it immediately checks for the allure dependency
during initialization and raises an ImportError if not found.

Raises:
ImportError: If none of the required allure packages are installed during initialization.

Example:
```python
from askui import VisionAgent
from askui.reporting import AllureReporter

with VisionAgent(reporter=[AllureReporter()]) as agent:
agent.act("Click the login button")
# Each action becomes an allure step with screenshots attached
```

Note:
This reporter requires one of the following packages to be installed:
- allure-python-commons
- allure-pytest
- allure-behave

Install via: `pip install allure-python-commons`
"""

def __init__(self) -> None:
"""Initialize the AllureReporter and import the allure module.

Performs eager loading of the allure module. If the module is not available,
raises ImportError immediately during initialization.

Raises:
ImportError: If the allure module cannot be imported. The error message
provides installation instructions.
"""
try:
import allure # type: ignore
except ImportError:
msg = (
"AllureReporter requires the allure-python-commons', 'allure-pytest' or 'allure-behave' package. "
"Please install it via 'pip install allure-python-commons'."
)
raise ImportError(msg) from None

self.allure = allure

@override
def add_message(
self,
role: str,
content: Union[str, dict[str, Any], list[Any]],
image: Optional[Image.Image | list[Image.Image]] = None,
) -> None:
"""Add a message as an Allure step with optional screenshots."""
with self.allure.step(f"{role}: {str(content)}"):
if image:
images = image if isinstance(image, list) else [image]
for img in images:
img_bytes = io.BytesIO()
img.save(img_bytes, format="PNG")
self.allure.attach(
img_bytes.getvalue(),
name="screenshot",
attachment_type=self.allure.attachment_type.PNG,
)

@override
def generate(self) -> None:
"""No-op for AllureReporter as reports are generated in real-time."""