# Copyright (c) "Neo4j" # Neo4j Sweden AB [https://neo4j.com] # # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # # https://www.apache.org/licenses/LICENSE-2.0 # # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from unittest.mock import AsyncMock import pytest from neo4j_graphrag.experimental.pipeline import Component from neo4j_graphrag.experimental.pipeline.types.context import RunContext from .components import ComponentMultiply, ComponentMultiplyWithContext, IntResultModel def test_component_inputs() -> None: inputs = ComponentMultiply.component_inputs assert "number1" in inputs assert inputs["number1"]["has_default"] is False assert "number2" in inputs assert inputs["number2"]["has_default"] is True def test_component_outputs() -> None: outputs = ComponentMultiply.component_outputs assert "result" in outputs assert outputs["result"]["has_default"] is True assert outputs["result"]["annotation"] == int @pytest.mark.asyncio async def test_component_run() -> None: c = ComponentMultiply() result = await c.run(number1=1, number2=2) assert isinstance(result, IntResultModel) assert isinstance( result.result, # we know this is a type and not a bool or str: ComponentMultiply.component_outputs["result"]["annotation"], # type: ignore ) @pytest.mark.asyncio async def test_component_run_with_context_default_implementation() -> None: c = ComponentMultiply() result = await c.run_with_context( # context can not be null in the function signature, # but it's ignored in this case None, # type: ignore number1=1, number2=2, ) # the type checker doesn't know about the type # because the method is not re-declared assert result.result == 2 # type: ignore @pytest.mark.asyncio async def test_component_run_with_context() -> None: c = ComponentMultiplyWithContext() notifier_mock = AsyncMock() result = await c.run_with_context( RunContext(run_id="run_id", task_name="task_name", notifier=notifier_mock), number1=1, number2=2, ) assert result.result == 2 notifier_mock.assert_awaited_once() def test_component_missing_method() -> None: with pytest.raises(RuntimeError) as e: class WrongComponent(Component): # we must have either run or run_with_context pass assert ( "You must implement either `run` or `run_with_context` in Component 'WrongComponent'" in str(e) )