diff --git a/pyproject.toml b/pyproject.toml index 1c5cd1c..137a0ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" name = "invoice-extraction" version = "0.1.0" description = "A workflow that, given an invoice, extracts several key details using LlamaExtract" -requires-python = ">=3.10" +requires-python = ">=3.12" readme = "README.md" dependencies = [ "llama-index-workflows>=2.16.0,<3.0.0", @@ -18,10 +18,17 @@ dev = [ "hatch>=1.14.2", "pytest>=8.4.2", "pytest-asyncio>=1.3.0", + "pytest-timeout>=2.3.1", + "llama-cloud-fake>=0.1,<0.2", "ruff>=0.13.2", "ty>=0.0.2", ] +[tool.pytest.ini_options] +timeout = 120 +timeout_method = "thread" +asyncio_mode = "auto" + [tool.hatch.envs.default.scripts] format = "ruff format ." format-check = "ruff format --check ." diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..881adaa --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,20 @@ +"""Pytest configuration: install the LlamaCloud fake server for all tests.""" + +import logging +import sys + +import pytest +from llama_cloud_fake import FakeLlamaCloudServer + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + handlers=[logging.StreamHandler(sys.stdout)], +) + +_fake = FakeLlamaCloudServer().install() + + +@pytest.fixture +def fake() -> FakeLlamaCloudServer: + return _fake diff --git a/tests/files/test.pdf b/tests/files/test.pdf new file mode 100644 index 0000000..c01805e Binary files /dev/null and b/tests/files/test.pdf differ diff --git a/tests/test_placeholder.py b/tests/test_placeholder.py deleted file mode 100644 index 3384ea0..0000000 --- a/tests/test_placeholder.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Placeholder test file. - -Replace this with actual tests for your project. -""" - - -def test_placeholder() -> None: - """Placeholder test that always passes. - - Remove this test once you add real tests to your project. - """ - assert True diff --git a/tests/test_workflow.py b/tests/test_workflow.py new file mode 100644 index 0000000..c87534f --- /dev/null +++ b/tests/test_workflow.py @@ -0,0 +1,32 @@ +import pytest +from invoice_extraction.workflow import ( + FeedbackRequiredEvent, + HumanFeedbackEvent, + workflow, +) +from llama_cloud_fake import FakeLlamaCloudServer + + +@pytest.mark.parametrize("extraction_mode", ["base", "advanced", "premium"]) +async def test_invoice_extraction_workflow( + monkeypatch: pytest.MonkeyPatch, + fake: FakeLlamaCloudServer, + extraction_mode: str, +) -> None: + """Exercise files.create + extract.create + wait_for_completion via the fake, + then approve through the human-in-the-loop step.""" + monkeypatch.setenv("LLAMA_CLOUD_API_KEY", "fake-api-key") + handler = workflow.run( + path="tests/files/test.pdf", + extraction_mode=extraction_mode, + ) + feedback_event: FeedbackRequiredEvent | None = None + async for ev in handler.stream_events(): + if isinstance(ev, FeedbackRequiredEvent): + feedback_event = ev + handler.ctx.send_event(HumanFeedbackEvent(approved=True)) + break + result = await handler + assert feedback_event is not None + assert isinstance(feedback_event.extraction_result, str) + assert result == feedback_event.extraction_result