robotframework/PythonRemoteServer

Add `get_keyword_types` to support argument conversion

martinezlc99 opened this issue · 4 comments

Issue
When using a custom Python library via RobotRemoteServer, automatic type conversion seems to fail. All arguments are passed as str. When using the same library nominally, automatic type conversion occurs as expected.

Actual Behavior
Multiply.py

import robot.api.deco
import robotremoteserver

class Multiply:
    @robot.api.deco.keyword(name="Multiply Two Numbers", types={"x": float, "y": float})
    def multiply(self, x: float, y: float):
        """multiply 'em"""
        return x * y


if __name__ == "__main__":
    robotremoteserver.RobotRemoteServer(Multiply())

multiply.robot

*** Settings ***
Documentation    Test automatic type conversions
# Library    Multiply
Library    Remote    127.0.0.1:8270


*** Test Cases ***
Multiply Them With Type Conversion
    [Documentation]    Automatic type Conversion should occur
    ${product} =    Multiply Two Numbers    1.5    2.5
    Log    ${sum}

Executing the test with fails with TypeError: can't multiply sequence by non-int of type 'str'. Passing the arguments as named also fails.

Expected Behavior
Running the test as a normal Python library works as expected:

multiply.robot

*** Settings ***
Documentation    Test automatic type conversions
Library    Multiply
# Library    Remote    127.0.0.1:8270

*** Test Cases ***
Multiply Them With Type Conversion
    [Documentation]    Automatic Type Conversion should occur
    ${product} =    Multiply Two Numbers    1.5    2.5
    Log    ${sum}

Is this a known limitation? I could not find any relevant documentaion. If not, then this is probably a bug in the Remote library I suspect. I am glad to open an issue there and look into a PR.

System info:
python -m robot --version -> Robot Framework 6.0.2 (Python 3.10.6 on win32)

It seems RemoteServer doesn't support argument conversion. The Remote API would support get_keyword_types, but the server doesn't have that method. Adding it ought to be pretty easy.

Thanks @pekkaklarck! Would you accept a PR for this? I dont mind trying to implement.

Certainly. The general approach ought to be:

  1. Check does the keyword have robot_types attribute set by the @keyword decorator. If it does, use that.
  2. If there's not robot_types, try getting type info using typing.get_type_info.
  3. If the above fails, get info from __annotations__.
  4. Convert type info to strings for XML-RPC compatibility.
  5. If type is a Union, it needs to be returned as a tuple.

The hard part is Python 2 compatibility. It's been important that RemoteServer supports Python 2 especially when Robot Framework itself doesn't support it anymore, but it could be time to drop that support. That decision needs to be done separately and discussed with others. The #devel channel on our Slack is probably the best place.

Another issue is that parameterized types like list[int] cannot be supported. The reason is that we cannot pass actual types over XML-RPC and Robot doesn't support strings like 'list[int]' in type conversion. There's an issue about that, though, and I hope we add that support in RF 7.

We discussed this on Slack and noticed one more problem: XML-RPC supports only a limited set of types and the Remote library itself converts other types to strings. For example, if decimal.Decimal is used as a type hint and we return that to Robot, it will convert the argument to a Decimal, but Remote converts it to a string. That's actually better than converting it to a float that would be supported by XML-RPC because precision would be lost, but that doesn't change the fact that the keyword won't get a Decimal as an argument.

I don't see any other way to handle this issue than enhancing RemoteServer so that it does argument conversion itself. Because it gets values converted by the Remote library, we know the exact format and conversion ought to be pretty straightforward. Setting the conversion infrastructure in place is some work nevertheless and that requires a separate issue. This issue can concentrate on adding get_keyword_types.