Restrict yaml loading in evaluate_parameters#33
Conversation
|
Mind adding a test here to show what this is correcting? |
I will add tests tomorrow. |
|
I second @sloretz request. Just for the record though, code seems to be precluding nested parameter arrays and verifying that arrays evaluated from substitutions have a single element type. |
|
Same, a test would be nice, it would also help convey what's being changed here. |
|
Sorry for the unclear PR yesterday. I updated the PR with a clearer description. |
wjwwood
left a comment
There was a problem hiding this comment.
Thanks for adding the tests, it makes the expected change in behavior clearer. I find the logic difficult to follow, but that's not uncommon when parsing schema-less data like this, so in general I think this is looking good. I had only a few comments.
test_launch_ros/test/test_launch_ros/test_normalize_parameters.py
Outdated
Show resolved
Hide resolved
| yaml_evaluated_value: Union[List[str], List[int], List[float], List[bool]] = [ | ||
| yaml.safe_load(item) for item in evaluated_value | ||
| ] | ||
| if check_sequence_type_is_allowed(yaml_evaluated_value): |
There was a problem hiding this comment.
| if check_sequence_type_is_allowed(yaml_evaluated_value): | |
| if not check_sequence_type_is_allowed(yaml_evaluated_value): | |
| raise TypeError( | |
| 'Expected a non-empty sequence, with items of uniform type. ' | |
| 'Allowed sequence item types are bool, int, float, str.' | |
| ) | |
| evaluated_value = tuple(yaml_evaluated_value) |
That change will also raise an error in:
launch_ros/test_launch_ros/test/test_launch_ros/test_normalize_parameters.py
Lines 214 to 239 in 4efbfe5
launch_ros/test_launch_ros/test/test_launch_ros/test_normalize_parameters.py
Lines 283 to 293 in 4efbfe5
I can add complicated logic for allowing interpreting some dissimilar arrays as arrays of strings, and some others not.
But, what's that useful for?
I think that in all the cases in test_dictionary_with_dissimilar_array, the user could write easily the parameters in other wat for getting an array of strings (if they want that). I wouldn't be so flexible as we are being now.
If we want that change, I could later simplify normalize_parameters logic in a follow-up PR.
There was a problem hiding this comment.
That sounds fine to me. It's better to be strict and relax it later if someone makes a case for it, than to make it stricter later.
There was a problem hiding this comment.
To be clear, +1 to ratcheting up the exception more if all the cases don't throw yet, whether or not that's just this change or something additional.
| expected = ({'foo': 1, 'fiz': ('True', '2.0', '3')},) | ||
| # assert evaluate_parameters(LaunchContext(), norm) == expected | ||
| with pytest.raises(TypeError) as exc: | ||
| orig = [{'foo': 1, 'fiz': [True, 2.0, 3]}] |
There was a problem hiding this comment.
What happens if orig is [{'foo': 1, 'fiz': ['True', '2.0', '3']}] ? Does that get correcly interpreted as a list of strings, or does it raise TypeError?
There was a problem hiding this comment.
There was a problem hiding this comment.
How so? Are plain dictionary values evaluated as YAML too? It doesn't look like it.
There was a problem hiding this comment.
Strings are converted to TextSubstitution in normalize_parameters before.
I don't have a better solution in mind, for avoiding the extra quotes.
There was a problem hiding this comment.
How so? Are plain dictionary values evaluated as YAML too? It doesn't look like it.
Thinking about this again, I stopped converting raw strings (str) and TextSubstitution like yaml.
The second one is needed, as str are converted to TextSubstitution in normalize_parameters.
I'm happy with how the test looks now, but I have to recognize that both normalize_parameters and evaluate_parameters need a refactor. But I think that's ok for a follow-up.
|
@sloretz do you think this is ready? (after having green CI) |
| make_mypy_happy_float = cast(List[Union[int, float]], value) | ||
| return tuple(float(e) for e in make_mypy_happy_float) | ||
| elif Substitution in has_types and has_types.issubset({str, Substitution, tuple}): | ||
| elif Substitution in has_types and has_types.issubset({str, Substitution}): |
There was a problem hiding this comment.
It doesn't have sense, normalize_to_list_of_substitutions can't handle that and fails:
launch_ros/launch_ros/launch_ros/utilities/normalize_parameters.py
Lines 77 to 79 in 78469a9
I added a test case for that:
Without removing
tuple, it was failing.The old test cases are passing with the removal.
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
821395a to
2672750
Compare
Follow up of #31.
The idea of this PR is to restrict what conversions from yaml are allowed, and what conversions are precluded. Also, substitutions that are later loaded as a list (from yaml), are converted to tuples (as it was done in the other cases).
I didn't want to raise an error in the conversions that aren't allowed, but I think it would be a good idea.