nodes: 0, module; 1, function_definition; 2, function_name:has_code; 3, parameters; 4, block; 5, identifier:state; 6, identifier:text; 7, default_parameter; 8, default_parameter; 9, expression_statement; 10, expression_statement; 11, comment:# either simple text matching or regex test; 12, expression_statement; 13, if_statement; 14, return_statement; 15, identifier:incorrect_msg; 16, string:"The checker expected to find `{{text}}` in your command."; 17, identifier:fixed; 18, False; 19, comment:"""Check whether the student code contains text.
  
      This function is a simpler override of the `has_code` function in protowhat,
      because ``ast_node._get_text()`` is not implemented in the OSH parser
  
      Using ``has_code()`` should be a last resort. It is always better to look at the result of code
      or the side effects they had on the state of your program.
  
      Args:
          state: State instance describing student and solution code. Can be omitted if used with Ex().
          text : text that student code must contain. Can be a regex pattern or a simple string.
          incorrect_msg: if specified, this overrides the automatically generated feedback message
                         in case ``text`` is not found in the student code.
          fixed: whether to match ``text`` exactly, rather than using regular expressions.
  
      :Example:
  
          Suppose the solution requires you to do: ::
  
              git push origin master
  
          The following SCT can be written: ::
  
              Ex().has_code(r'git\\s+push\\s+origin\\s+master')
  
          Submissions that would pass: ::
  
              git push origin master
              git   push    origin    master
  
          Submissions that would fail: ::
  
              git push --force origin master
      """; 20, assignment; 21, assignment; 22, not_operator; 23, block; 24, identifier:state; 25, identifier:stu_code; 26, attribute; 27, identifier:res; 28, conditional_expression:text in stu_code if fixed else re.search(text, stu_code); 29, identifier:res; 30, expression_statement; 31, expression_statement; 32, identifier:state; 33, identifier:student_code; 34, comparison_operator:text in stu_code; 35, identifier:fixed; 36, call; 37, assignment; 38, call; 39, identifier:text; 40, identifier:stu_code; 41, attribute; 42, argument_list; 43, identifier:_msg; 44, call; 45, attribute; 46, argument_list; 47, identifier:re; 48, identifier:search; 49, identifier:text; 50, identifier:stu_code; 51, attribute; 52, argument_list; 53, identifier:state; 54, identifier:do_test; 55, identifier:_msg; 56, identifier:state; 57, identifier:build_message; 58, identifier:incorrect_msg; 59, keyword_argument; 60, identifier:fmt_kwargs; 61, dictionary; 62, pair; 63, string; 64, identifier:text; 65, string_content:text
code: def has_code(state, text, incorrect_msg="The checker expected to find `{{text}}` in your command.", fixed=False):
      """Check whether the student code contains text.
  
      This function is a simpler override of the `has_code` function in protowhat,
      because ``ast_node._get_text()`` is not implemented in the OSH parser
  
      Using ``has_code()`` should be a last resort. It is always better to look at the result of code
      or the side effects they had on the state of your program.
  
      Args:
          state: State instance describing student and solution code. Can be omitted if used with Ex().
          text : text that student code must contain. Can be a regex pattern or a simple string.
          incorrect_msg: if specified, this overrides the automatically generated feedback message
                         in case ``text`` is not found in the student code.
          fixed: whether to match ``text`` exactly, rather than using regular expressions.
  
      :Example:
  
          Suppose the solution requires you to do: ::
  
              git push origin master
  
          The following SCT can be written: ::
  
              Ex().has_code(r'git\\s+push\\s+origin\\s+master')
  
          Submissions that would pass: ::
  
              git push origin master
              git   push    origin    master
  
          Submissions that would fail: ::
  
              git push --force origin master
      """
  
      stu_code = state.student_code
  
      # either simple text matching or regex test
      res = text in stu_code if fixed else re.search(text, stu_code)
  
      if not res:
          _msg = state.build_message(incorrect_msg, fmt_kwargs={ 'text': text })
          state.do_test(_msg)
  
      return state