Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add public argument conversion API for libraries and other tools #4942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Snooz82 opened this issue Nov 12, 2023 · 2 comments
Closed

Add public argument conversion API for libraries and other tools #4942

Snooz82 opened this issue Nov 12, 2023 · 2 comments

Comments

@Snooz82
Copy link
Member

Snooz82 commented Nov 12, 2023

Hi @pekkaklarck ,

We are using TypeConverter class in Robot Framework Browser in multiple places, to convert arguments of *varagrs when calling internal keywords.
Unfortunately this API is no longer be able to digest real type values.

from robot.running.arguments.typeconverters import TypeConverter
TypeConverter.converter_for(int)

We need “dynamic” type conversion because of many reasons.

With dynamic i mean we do Robot type conversion inside Browser lib when Robot is not able to do.

  1. We do have situations where we deprecate positional args in favour of named only ones. In these cases we introduce a *varags argument that collects all old positional args and assigns them in the old order to the variables inside. Therefore there is no type hinting in the arguments. but we have a Catalog of the original types which can be used to convert.
  2. We do have keywords like Promise To and Wait For Condition which calls our keywords internally and has *args to take the arguments. These two keywords iterate over the called keywords interface and try to convert the arguments according to their type. Also in this case we want/need to support dynamic argument conversion.

For us it is not really important, if exactly this function converter_for() will stay compatible or if a new function will be implemented to get to get the proper converter for a Python type.
However it would be more convenient for our users to stay compatible, so they do not necessarily need to update Browser, when updating RF.

We do currently:

converter = TypeConverter.converter_for(argument_type)
                if converter is not None:
                    params[argument_name] = converter.convert(
                        argument_name, params.get(argument_name)
                    )

A Public API for this would be nice too.
Or maybe even just a convenient function for Converting value to type as a static method.
Something like TypeConverters.convert_to_type(name: str, value: Any, destination_type: type)

Cheers

@Snooz82 Snooz82 added this to the v7.0 milestone Nov 12, 2023
@pekkaklarck
Copy link
Member

pekkaklarck commented Nov 13, 2023

TypeConverter.converter_for() was changed to accept a TypeInfo object instead of a concrete types or their string aliases as part of #4711 that added support for specifying types as strings like 'list[int]' and 'int | float'. It would have been strange if TypeConnverter would handle parsing such strings in addition to doing actual conversion. Instead of that, we moved all logic related to parsing and validating types to the TypeInfo class that was earlier used only by Libdoc. Now responsibilities are clear and TypeConverter only needs to care about actual type conversion.

The TypeConverter isn't part of the public API, but it's nevertheless bad that the change breaks Browser and apparently also the RobotCode plugin. Because conversion functionality clearly is used also externally, the real fix is exposing it as a public, stable API. I think it's best to do it via the TypeInfo class that already has a convert method and can be used like this:

>>> from robot.running import TypeInfo
>>> info = TypeInfo.from_type_hint(int)
>>> info.convert('42')
42
>>> info = TypeInfo.from_type_hint('int | float')
>>> info.convert('3.14')

Making this a public API basically requires the following:

  • Expose TypeInfo via robot.api.
  • Go trough its public methods to see is there anything to be changed before making it public (easier now than afterwards).
  • Add docstrings.
  • Add unit tests for the exposed functionality.
  • Mention TypeInfo.convert in the User Guide.

We could also consider changing TypeConverter.converter_for so that it would handle plain types as earlier. Due to cyclic module dependencies that would be a bit annoying, though, and there seem to be some other changes to TypeConverter that would also need to be reverted or worked around. I'm not sure is that worth the effort, because affected libraries and tools should nevertheless switch to the public API at some point.

@pekkaklarck pekkaklarck self-assigned this Nov 13, 2023
@pekkaklarck pekkaklarck changed the title TypeConverter internal API backwards incompatible with real types in RF 7.0a1 Add public argument conversion API for libraries and other tools Nov 13, 2023
pekkaklarck added a commit that referenced this issue Nov 13, 2023
- Expose via `robot.api`.
- Add docstrings.
- Enhance `from_dict` now that also it is public.
- Small error reporting enhancement.

This is the core part of #4942.
pekkaklarck added a commit that referenced this issue Nov 13, 2023
It used to work only with `Languages` instances but it was supposed to
work also with strings. To some extend related to #4942.
pekkaklarck added a commit that referenced this issue Nov 14, 2023
Add also tests for using `TypeInfo.convert` in libraries. They work
also as usage examples.

Part of #4942.
@pekkaklarck
Copy link
Member

TypeInfo has now been exposed via robot.api, its documentation has been enhanced, and some bugs with it fixed. Commit 383d432 contains tests that can be used as examples how the API works also in a bit more advanced cases.

Changing TypeConverter so that it would be compatible with RF < 7 would be somewhat big task and would also require changing some of its functions so that they wouldn't be as convenient to use internally as nowadays. Now that we have the public API available, I don't consider that worth the effort. We we can return to that later if needed, but now I consider this issue done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants