Test whether abstract syntax trees match between the student and solution code. ``has_equal_ast()`` can be used in two ways: * As a robust version of ``has_code()``. By setting ``code``, you can look for the AST representation of ``code`` in the student's submission. But be aware tha
(state, incorrect_msg=None, code=None, exact=True, append=None)
| 108 | |
| 109 | |
| 110 | def has_equal_ast(state, incorrect_msg=None, code=None, exact=True, append=None): |
| 111 | """Test whether abstract syntax trees match between the student and solution code. |
| 112 | |
| 113 | ``has_equal_ast()`` can be used in two ways: |
| 114 | |
| 115 | * As a robust version of ``has_code()``. By setting ``code``, you can look for the AST representation of ``code`` in the student's submission. |
| 116 | But be aware that ``a`` and ``a = 1`` won't match, as reading and assigning are not the same in an AST. |
| 117 | Use ``ast.dump(ast.parse(code))`` to see an AST representation of ``code``. |
| 118 | * As an expression-based check when using more advanced SCT chain, e.g. to compare the equality of expressions to set function arguments. |
| 119 | |
| 120 | Args: |
| 121 | incorrect_msg: message displayed when ASTs mismatch. When you specify ``code`` yourself, you have to specify this. |
| 122 | code: optional code to use instead of the solution AST. |
| 123 | exact: whether the representations must match exactly. If false, the solution AST |
| 124 | only needs to be contained within the student AST (similar to using test student typed). |
| 125 | Defaults to ``True``, unless the ``code`` argument has been specified. |
| 126 | |
| 127 | :Example: |
| 128 | |
| 129 | Student and Solution Code:: |
| 130 | |
| 131 | dict(a = 'value').keys() |
| 132 | |
| 133 | SCT:: |
| 134 | |
| 135 | # all pass |
| 136 | Ex().has_equal_ast() |
| 137 | Ex().has_equal_ast(code = "dict(a = 'value').keys()") |
| 138 | Ex().has_equal_ast(code = "dict(a = 'value')", exact = False) |
| 139 | |
| 140 | Student and Solution Code:: |
| 141 | |
| 142 | import numpy as np |
| 143 | arr = np.array([1, 2, 3, 4, 5]) |
| 144 | np.mean(arr) |
| 145 | |
| 146 | SCT:: |
| 147 | |
| 148 | # Check underlying value of arugment a of np.mean: |
| 149 | Ex().check_function('numpy.mean').check_args('a').has_equal_ast() |
| 150 | |
| 151 | # Only check AST equality of expression used to specify argument a: |
| 152 | Ex().check_function('numpy.mean').check_args('a').has_equal_ast() |
| 153 | |
| 154 | """ |
| 155 | if utils.v2_only(): |
| 156 | state.assert_is_not(["object_assignments"], "has_equal_ast", ["check_object"]) |
| 157 | state.assert_is_not(["function_calls"], "has_equal_ast", ["check_function"]) |
| 158 | |
| 159 | if code and incorrect_msg is None: |
| 160 | raise InstructorError.from_message( |
| 161 | "If you manually specify the code to match inside has_equal_ast(), " |
| 162 | "you have to explicitly set the `incorrect_msg` argument." |
| 163 | ) |
| 164 | |
| 165 | if ( |
| 166 | append is None |
| 167 | ): # if not specified, set to False if incorrect_msg was manually specified |