Skip to content

Commit adb9801

Browse files
committed
Document that automatic module does not work with list comprehensions
Fixes robotframework#3593.
1 parent 6adb7fa commit adb9801

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

doc/userguide/src/Appendices/EvaluatingExpressions.rst

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ can only be used if the root module automatically imports the submodule. That is
7070
not always the case and using such modules is not possible. An concrete example
7171
that is relevant in the automation context is the `selenium` module that is
7272
implemented, at least at the time of this writing, so that just importing
73-
`selenium` does not import the `selenium.webdriver` submodule. A workaround is
74-
using the :name:`Evaluate` keyword that accepts modules to be imported
73+
`selenium` does not import the `selenium.webdriver` submodule.
74+
Another limitation is that modules cannot be used in the expression part of
75+
a list comprehension when using Python 3. A workaround to both of these problems
76+
is using the BuiltIn_ keyword :name:`Evaluate` that accepts modules to be imported
7577
and added to the evaluation namespace as an argument:
7678

7779
.. sourcecode:: robotframework
@@ -80,12 +82,19 @@ and added to the evaluation namespace as an argument:
8082
Does not work due to nested module structure
8183
Log ${{selenium.webdriver.ChromeOptions()}}
8284

83-
Evaluate keyword to the rescue
85+
Evaluate keyword with nested module
8486
${options} = Evaluate selenium.webdriver.ChromeOptions() modules=selenium.webdriver
8587
Log ${options}
8688

87-
The :name:`Evaluate` keyword also supports custom evaluation namespaces.
88-
See its documentation in the BuiltIn_ library for more details.
89+
Does not work due to list comprehension
90+
Log ${{[json.loads(item) for item in ('1', '"b"')]}}
91+
92+
Evaluate keyword with list comprehension
93+
${items} = Evaluate [json.loads(item) for item in ('1', '"b"')] modules=json
94+
Log ${items}
95+
96+
The :name:`Evaluate` keyword also supports custom evaluation namespaces if further
97+
customization is needed. See its documentation in the BuiltIn_ library for more details.
8998

9099
__ http://docs.python.org/library/functions.html#eval
91100

src/robot/libraries/BuiltIn.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3024,28 +3024,35 @@ def evaluate(self, expression, modules=None, namespace=None):
30243024
namespace as a dictionary. Possible ``modules`` are added to this
30253025
namespace.
30263026
3027-
Starting from Robot Framework 3.2, modules used in the expression are
3028-
imported automatically. ``modules`` argument is still needed with
3029-
nested modules like ``rootmod.submod`` that are implemented so that
3030-
the root module does not automatically import sub modules. This is
3031-
illustrated by the ``selenium.webdriver`` example below.
3032-
30333027
Variables used like ``${variable}`` are replaced in the expression
30343028
before evaluation. Variables are also available in the evaluation
30353029
namespace and can be accessed using the special ``$variable`` syntax
30363030
as explained in the `Evaluating expressions` section.
30373031
3032+
Starting from Robot Framework 3.2, modules used in the expression are
3033+
imported automatically. There are, however, two cases where they need to
3034+
be explicitly specified using the ``modules`` argument:
3035+
3036+
- When nested modules like ``rootmod.submod`` are implemented so that
3037+
the root module does not automatically import sub modules. This is
3038+
illustrated by the ``selenium.webdriver`` example below.
3039+
3040+
- When using a module in the expression part of a list comprehension.
3041+
This is illustrated by the ``json`` example below.
3042+
30383043
Examples (expecting ``${result}`` is number 3.14):
30393044
| ${status} = | Evaluate | 0 < ${result} < 10 | # Would also work with string '3.14' |
30403045
| ${status} = | Evaluate | 0 < $result < 10 | # Using variable itself, not string representation |
30413046
| ${random} = | Evaluate | random.randint(0, sys.maxsize) |
30423047
| ${options} = | Evaluate | selenium.webdriver.ChromeOptions() | modules=selenium.webdriver |
3048+
| ${items} = | Evaluate | [json.loads(item) for item in ('1', '"b"')] | modules=json |
30433049
| ${ns} = | Create Dictionary | x=${4} | y=${2} |
30443050
| ${result} = | Evaluate | x*10 + y | namespace=${ns} |
30453051
=>
30463052
| ${status} = True
30473053
| ${random} = <random integer>
30483054
| ${options} = ChromeOptions instance
3055+
| ${items} = [1, 'b']
30493056
| ${result} = 42
30503057
30513058
*NOTE*: Prior to Robot Framework 3.2 using ``modules=rootmod.submod``
@@ -3357,10 +3364,10 @@ class BuiltIn(_Verify, _Converter, _Variables, _RunKeyword, _Control, _Misc):
33573364
33583365
`Evaluate` also allows configuring the execution namespace with a custom
33593366
namespace and with custom modules to be imported. The latter functionality
3360-
is useful when using nested modules like ``rootmod.submod`` that are
3361-
implemented so that the root module does not automatically import sub
3362-
modules. Otherwise the automatic module import mechanism described earlier
3363-
is enough to get the needed modules imported.
3367+
is useful in special cases where the automatic module import does not work
3368+
such as when using nested modules like ``rootmod.submod`` or list
3369+
comprehensions. See the documentation of the `Evaluate` keyword for mode
3370+
details.
33643371
33653372
*NOTE:* Automatic module import is a new feature in Robot Framework 3.2.
33663373
Earlier modules needed to be explicitly taken into use when using the

0 commit comments

Comments
 (0)