Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "uipath"
version = "2.7.5"
version = "2.7.6"
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
Expand Down
26 changes: 16 additions & 10 deletions src/uipath/_cli/_evals/mocks/mockito_mocker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from typing import Any, Callable

from mockito import ( # type: ignore[import-untyped]
ARGS,
KWARGS,
invocation,
mocking,
)
Expand Down Expand Up @@ -72,16 +74,20 @@ def __init__(self, context: MockingContext):
mock_obj = mocking.Mock(self.stub)

for behavior in self.context.strategy.behaviors:
resolved_args = _resolve_value(behavior.arguments.args)
resolved_kwargs = _resolve_value(behavior.arguments.kwargs)

args = resolved_args if resolved_args is not None else []
kwargs = resolved_kwargs if resolved_kwargs is not None else {}

stubbed = invocation.StubbedInvocation(mock_obj, behavior.function)(
*args,
**kwargs,
)
# If arguments is omitted (None), match any call signature
if behavior.arguments is None:
stubbed = invocation.StubbedInvocation(mock_obj, behavior.function)(
*ARGS, **KWARGS
)
else:
resolved_args = _resolve_value(behavior.arguments.args)
resolved_kwargs = _resolve_value(behavior.arguments.kwargs)
args = resolved_args if resolved_args is not None else []
kwargs = resolved_kwargs if resolved_kwargs is not None else {}
stubbed = invocation.StubbedInvocation(mock_obj, behavior.function)(
*args,
**kwargs,
)

for answer in behavior.then:
answer_dict = answer.model_dump()
Expand Down
2 changes: 1 addition & 1 deletion src/uipath/_cli/_evals/mocks/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class MockingAnswer(BaseModel):

class MockingBehavior(BaseModel):
function: str = Field(..., alias="function")
arguments: MockingArgument = Field(..., alias="arguments")
arguments: MockingArgument | None = Field(default=None, alias="arguments")
then: list[MockingAnswer] = Field(..., alias="then")


Expand Down
52 changes: 52 additions & 0 deletions tests/cli/eval/mocks/test_mocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ def foofoo(*args, **kwargs):
with pytest.raises(NotImplementedError):
assert foofoo()

assert evaluation.mocking_strategy.behaviors[0].arguments is not None
evaluation.mocking_strategy.behaviors[0].arguments.kwargs = {"x": 1}
set_execution_context(
MockingContext(
Expand Down Expand Up @@ -378,6 +379,56 @@ def foofoo(*args, **kwargs):
assert foo(x=2) == "bar1"


def test_mockito_mockable_sync_arguments_omitted():
"""Test that omitting 'arguments' entirely matches any call"""

# Arrange
@mockable()
def bar(*args, **kwargs):
raise NotImplementedError()

evaluation_item: dict[str, Any] = {
"id": "evaluation-id",
"name": "Mock bar",
"inputs": {},
"evaluationCriterias": {
"ExactMatchEvaluator": None,
},
"mockingStrategy": {
"type": "mockito",
"behaviors": [
{
"function": "bar",
# No "arguments" field - should match any call
"then": [{"type": "return", "value": "mocked"}],
}
],
},
}
evaluation = EvaluationItem(**evaluation_item)
assert isinstance(evaluation.mocking_strategy, MockitoMockingStrategy)
# Verify arguments is None when omitted
assert evaluation.mocking_strategy.behaviors[0].arguments is None

# Act & Assert
set_execution_context(
MockingContext(
strategy=evaluation.mocking_strategy,
name=evaluation.name,
inputs=evaluation.inputs,
),
_mock_span_collector,
"test-execution-id",
)

# All these should work - match any call signature
assert bar() == "mocked"
assert bar(x=1) == "mocked"
assert bar("positional") == "mocked"
assert bar(a=1, b=2, c=3) == "mocked"
assert bar("pos1", "pos2", key="value") == "mocked"


@pytest.mark.asyncio
async def test_mockito_mockable_async():
# Arrange
Expand Down Expand Up @@ -433,6 +484,7 @@ async def foofoo(*args, **kwargs):
with pytest.raises(NotImplementedError):
assert await foofoo()

assert evaluation.mocking_strategy.behaviors[0].arguments is not None
evaluation.mocking_strategy.behaviors[0].arguments.kwargs = {"x": 1}
set_execution_context(
MockingContext(
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.