@@ -276,13 +276,9 @@ def generate_validator_testcases(valid):
276276 (cycler (mew = [2 , 5 ]),
277277 cycler ('markeredgewidth' , [2 , 5 ])),
278278 ),
279- # This is *so* incredibly important: validate_cycler() eval's
280- # an arbitrary string! I think I have it locked down enough,
281- # and that is what this is testing.
282- # TODO: Note that these tests are actually insufficient, as it may
283- # be that they raised errors, but still did an action prior to
284- # raising the exception. We should devise some additional tests
285- # for that...
279+ # validate_cycler() parses an arbitrary string using a safe
280+ # AST-based parser (no eval). These tests verify that only valid
281+ # cycler expressions are accepted.
286282 'fail' : ((4 , ValueError ), # Gotta be a string or Cycler object
287283 ('cycler("bleh, [])' , ValueError ), # syntax error
288284 ('Cycler("linewidth", [1, 2, 3])' ,
@@ -464,6 +460,14 @@ def test_validate_cycler_bad_color_string():
464460 validate_cycler ("cycler('color', 'foo')" )
465461
466462
463+ def test_validate_cycler_no_code_execution ():
464+ # List comprehensions are arbitrary code. The old eval()-based parser
465+ # would execute this successfully, but the AST-based parser rejects it
466+ # because only literal values are allowed in cycler arguments.
467+ with pytest .raises (ValueError ):
468+ validate_cycler ("cycler('color', [x for x in ['r', 'g', 'b']])" )
469+
470+
467471@pytest .mark .parametrize ('weight, parsed_weight' , [
468472 ('bold' , 'bold' ),
469473 ('BOLD' , ValueError ), # weight is case-sensitive
0 commit comments