You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RobotFramework incorrectly calls cached_property when importing a Python library using the cached_property method.
I found a previous issue on this topic, #4838, and it seems that the issue has been solved in 6.1.1. But in fact, the issue still exists. Please check the following steps, explanations, and suggestions.
Steps:
Python version 3.11.6
RobotFramework version is 6.1.1.
Create a python file named test.py as below, two methods decorated by cached_property, one will print some message, and the other will raise a RuntimeError.
fromfunctoolsimportcached_propertyclassTestCached:
@cached_propertydefcached_property_with_print(self):
print(f"This is in cached_property_with_print")
@cached_propertydefcached_property_with_error(self):
raiseRuntimeError("This is in cached_property_with_error")
Create a robot file named test.robot as below, using the Import Library to import test.TestCached class.
*** Settings ***Documentation demo cached_property issue*** Test Cases ***1: import library with cached_property
Import Library test.TestCached
Run the test.robot and the console output is shown as below.
Check the source code of RobotFramework, file robot.running.testlibraries, line 340-354:
class_ClassLibrary(_BaseTestLibrary):
def_get_handler_method(self, libinst, name):
foritemin (libinst,) +inspect.getmro(libinst.__class__):
# `isroutine` is used before `getattr` to avoid calling properties.if (nameingetattr(item, '__dict__', ())
andinspect.isroutine(item.__dict__[name])):
try:
method=getattr(libinst, name)
exceptException:
message, traceback=get_error_details()
raiseDataError(f'Getting handler method failed: {message}',
traceback)
returnself._validate_handler_method(method)
raiseDataError('Not a method or function.')
The condition if (name in getattr(item, '__dict__', ()) and inspect.isroutine(item.__dict__[name])) cannot filter out the cached_property method. The inspect.isroutine will give True for the cached_property instance. So the cached_property method will be called by line method = getattr(libinst, name). When this line met error, a DataError will be raised to it caller.
Check the source code of RobotFramework, file robot.running.testlibraries, line 271-276:
When the error is raised from line return self._get_handler_method(libcode, name), then the line self._adding_keyword_failed(name, err, self.get_handler_error_level) will be executed. The _adding_keyword_failed will add error message to the syslog file (refer the syslog as below). So there is no error message shown in console output or log file. This is why issue #4838 is considered resolved. In that case, no error raised to console output mislead us.
check syslog:
20231027 22:53:04.080 | DEBUG | Started keyword 'BuiltIn.Import Library'.
20231027 22:53:04.087 | INFO | Imported library class 'test.TestCached' from 'test.py'.
20231027 22:53:04.090 | INFO | In library 'test.TestCached': Adding keyword 'cached_property_with_error' failed: Getting handler method failed: This is in cached_property_with_error
20231027 22:53:04.090 | DEBUG | Details:
Traceback (most recent call last):
File "...functools.py", line 1001, in __get__
val = self.func(instance)
^^^^^^^^^^^^^^^^^^^
File "...test.py", line 11, in cached_property_with_error
raise RuntimeError("This is in cached_property_with_error")
RuntimeError: This is in cached_property_with_error
20231027 22:53:04.090 | INFO | In library 'test.TestCached': Adding keyword 'cached_property_with_print' failed: Not a method or function.
20231027 22:53:04.090 | INFO | In library 'test.TestCached': Adding keyword 'property_with_print' failed: Not a method or function.
Suggestions:
For the file robot.running.testlibraries, line 346, and inspect.isroutine(item.__dict__[name])):, add one more condition and callable(item.__dict__[name]). This property and cached_property instance are not callable, so this condition can filter out them. Then the if condition would look like:
if (nameingetattr(item, '__dict__', ())
andinspect.isroutine(item.__dict__[name])
andcallable(item.__dict__[name])):
Hope this issue can be solved and help someone.
The text was updated successfully, but these errors were encountered:
pekkaklarck
changed the title
cached_property method was called during RobotFramework import librarycached_property is called when importing library
Nov 1, 2023
Thanks for a report and good example. I should have investigated #4838 in more detail and create a test for cached_property instead of trusting it to be a standard non-data descriptor that we already have tests for. More precisely, the problem is that our tests for non-data descriptors validate that possible errors accessing them are handled properly, when we shouldn't access cached_property at all. I don't know can we avoid accessing non-data descriptors in general, but cached_property is easy to special case.
RobotFramework incorrectly calls cached_property when importing a Python library using the cached_property method.
I found a previous issue on this topic, #4838, and it seems that the issue has been solved in 6.1.1. But in fact, the issue still exists. Please check the following steps, explanations, and suggestions.
Steps:
Explantions:
The condition
if (name in getattr(item, '__dict__', ()) and inspect.isroutine(item.__dict__[name]))
cannot filter out the cached_property method. The inspect.isroutine will give True for the cached_property instance. So the cached_property method will be called by linemethod = getattr(libinst, name)
. When this line met error, a DataError will be raised to it caller.When the error is raised from line
return self._get_handler_method(libcode, name)
, then the lineself._adding_keyword_failed(name, err, self.get_handler_error_level)
will be executed. The_adding_keyword_failed
will add error message to the syslog file (refer the syslog as below). So there is no error message shown in console output or log file. This is why issue #4838 is considered resolved. In that case, no error raised to console output mislead us.Suggestions:
For the file robot.running.testlibraries, line 346,
and inspect.isroutine(item.__dict__[name])):
, add one more conditionand callable(item.__dict__[name])
. This property and cached_property instance are not callable, so this condition can filter out them. Then the if condition would look like:Hope this issue can be solved and help someone.
The text was updated successfully, but these errors were encountered: