Skip to content

Commit

Permalink
fix crash with keyword decorator on class libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
DetachHead committed Oct 7, 2024
1 parent a393404 commit 8a97098
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,18 @@
from functools import wraps
from inspect import getdoc
from re import sub
from typing import TYPE_CHECKING, Callable, Final, Generator, Literal, Optional, Tuple, cast
from types import MethodType
from typing import (
TYPE_CHECKING,
Callable,
Final,
Generator,
Literal,
Optional,
Tuple,
TypeVar,
cast,
)

from _pytest import runner
from _pytest.python import PyobjMixin
Expand All @@ -23,7 +34,7 @@
from robot.running.librarykeywordrunner import LibraryKeywordRunner
from robot.running.model import Body
from robot.utils.error import ErrorDetails
from typing_extensions import override
from typing_extensions import Concatenate, override

from pytest_robotframework import (
_get_status_reporter_failures, # pyright:ignore[reportPrivateUsage]
Expand Down Expand Up @@ -582,6 +593,19 @@ def wrapped(*args: P.args, **kwargs: P.kwargs) -> T:
return wrapped


_R = TypeVar("_R")


def _bound_method(instance: T, fn: Callable[Concatenate[T, P], _R]) -> Callable[P, _R]:
"""if the keyword we're patching is on a class library, we need to re-bound the method to the
instance"""

def inner(*args: P.args, **kwargs: P.kwargs) -> _R:
return fn(instance, *args, **kwargs)

return inner


# the methods used in this listener were added in robot 7. in robot 6 we do this by patching
# `LibraryKeywordRunner._runner_for` instead
if robot_6:
Expand All @@ -599,13 +623,20 @@ def _runner_for( # pyright:ignore[reportUnusedFunction] # noqa: PLR0917
named: dict[str, object],
) -> Function:
"""use the original function instead of the `@keyword` wrapped one"""
handler = _hide_already_raised_exception_from_robot_log(
cast(Function, getattr(handler, _keyword_original_function_attr, handler))
original_function: Function | None = getattr(handler, _keyword_original_function_attr, None)
wrapped_function = _hide_already_raised_exception_from_robot_log(
cast(
Function,
_bound_method(handler.__self__, original_function)
if original_function is not None and isinstance(handler, MethodType)
else (original_function or handler),
)
)
return old_method(self, context, handler, positional, named)
return old_method(self, context, wrapped_function, positional, named)

else:
from robot.running.librarykeyword import StaticKeyword
from robot.running.testlibraries import ClassLibrary

@catch_errors
class KeywordUnwrapper(ListenerV3):
Expand All @@ -622,14 +653,19 @@ def start_library_keyword(
):
if not isinstance(implementation, StaticKeyword):
return
unwrapped_method: Function | None = getattr(
original_function: Function | None = getattr(
implementation.method, _keyword_original_function_attr, None
)
if unwrapped_method is None:

if original_function is None:
return

setattr(
implementation.owner.instance, # pyright:ignore[reportAny]
implementation.method_name,
_hide_already_raised_exception_from_robot_log(unwrapped_method),
_hide_already_raised_exception_from_robot_log(
_bound_method(implementation.owner.instance, original_function) # pyright:ignore[reportAny]
if isinstance(implementation.owner, ClassLibrary)
else original_function
),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# noqa: N999
# robot class libraries need to have the same name as the module
from __future__ import annotations

from robot.api import logger

from pytest_robotframework import keyword


class ClassLibrary:
def __init__(self):
pass

@keyword
def foo(self): # noqa: PLR6301
logger.info("hi")
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*** Settings ***
Library ./ClassLibrary.py


*** Test Cases ***
Asdf
Foo
6 changes: 6 additions & 0 deletions tests/test_robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,9 @@ def test_empty_setup_or_teardown(pr: PytestRobotTester):
)
assert not xml.xpath("//test[@name='Disable setup']/kw[@name='Setup']/kw[@name='Log']")
assert not xml.xpath("//test[@name='Disable teardown']/kw[@name='Teardown']/kw[@name='Log']")


def test_keyword_decorator_class_library(pr: PytestRobotTester):
pr.run_and_assert_result("--robot-loglevel", "DEBUG:INFO", passed=1)
pr.assert_log_file_exists()
assert xpath(output_xml(), "//kw[@name='Foo' and @owner='ClassLibrary']/msg[.='hi']")

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.8, ubuntu-latest, 6.1.1, 8.0)

test_keyword_decorator_class_library[xdist_off] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.8, ubuntu-latest, 6.1.1, 8.0)

test_keyword_decorator_class_library[xdist_on] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.8, ubuntu-latest, 6.1.1, from lockfile)

test_keyword_decorator_class_library[xdist_off] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.8, ubuntu-latest, 6.1.1, from lockfile)

test_keyword_decorator_class_library[xdist_on] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.8, macos-12, 6.1.1, 8.0)

test_keyword_decorator_class_library[xdist_off] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.8, macos-12, 6.1.1, 8.0)

test_keyword_decorator_class_library[xdist_on] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.8, macos-12, 6.1.1, from lockfile)

test_keyword_decorator_class_library[xdist_on] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.8, macos-12, 6.1.1, from lockfile)

test_keyword_decorator_class_library[xdist_off] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.12, ubuntu-latest, 6.1.1, 8.0)

test_keyword_decorator_class_library[xdist_off] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.12, ubuntu-latest, 6.1.1, 8.0)

test_keyword_decorator_class_library[xdist_on] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.12, ubuntu-latest, 6.1.1, from lockfile)

test_keyword_decorator_class_library[xdist_on] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.12, ubuntu-latest, 6.1.1, from lockfile)

test_keyword_decorator_class_library[xdist_off] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.12, macos-12, 6.1.1, 8.0)

test_keyword_decorator_class_library[xdist_on] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.12, macos-12, 6.1.1, 8.0)

test_keyword_decorator_class_library[xdist_off] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.12, macos-12, 6.1.1, from lockfile)

test_keyword_decorator_class_library[xdist_off] ValueError: not enough values to unpack (expected 1, got 0)

Check failure on line 334 in tests/test_robot.py

View workflow job for this annotation

GitHub Actions / test (3.12, macos-12, 6.1.1, from lockfile)

test_keyword_decorator_class_library[xdist_on] ValueError: not enough values to unpack (expected 1, got 0)

0 comments on commit 8a97098

Please sign in to comment.