diff --git a/src/dayamlchecker/yaml_structure.py b/src/dayamlchecker/yaml_structure.py index a85baac..ad1ca1e 100644 --- a/src/dayamlchecker/yaml_structure.py +++ b/src/dayamlchecker/yaml_structure.py @@ -203,7 +203,34 @@ class PythonBool: def __init__(self, x): self.errors = [] - pass + if isinstance(x, bool): + return + # number like 10 or 0 - not valid, even though Python treats them as truthy/falsy + if isinstance(x, (int, float)): + self.errors = [ + (f"expected True, False, or a Python expression, got number: {x}", 1) + ] + return + # must be a string at this point + if not isinstance(x, str): + self.errors = [ + ( + f"expected True, False, or a Python expression, got: {type(x).__name__}", + 1, + ) + ] + return + # try parsing it as a Python expression - covers things like "user_age > 18" + try: + ast.parse(x) + except SyntaxError as ex: + msg = ex.msg or str(ex) + self.errors = [ + ( + f"expected True, False, or a valid Python expression, got: {x!r} (Python syntax error: {msg})", + 1, + ) + ] class JavascriptText: @@ -754,7 +781,7 @@ def _variable_candidates(self, var_expr): "scan for variables": {}, "if": {}, "sets": {}, - "initial": {}, + "initial": {"type": PythonBool}, "event": {}, "comment": {}, "generic object": {"type": DAPythonVar}, diff --git a/tests/test_yaml_structure.py b/tests/test_yaml_structure.py index 0a9922a..125cf28 100644 --- a/tests/test_yaml_structure.py +++ b/tests/test_yaml_structure.py @@ -1732,6 +1732,103 @@ def test_show_hide_nesting_depth_two_no_warning(self): f"Did not expect nesting warning, got: {errs}", ) + def test_mandatory_number_errors(self): + """Error: mandatory with a number should be flagged""" + invalid = """ +mandatory: 10 +question: | + Hello +field: user_name +""" + errs = find_errors_from_string(invalid, input_file="") + self.assertTrue( + any("got number: 10" in e.err_str for e in errs), + f"Expected mandatory number error, got: {errs}", + ) + + def test_mandatory_bool_true_valid(self): + """Valid: mandatory: True should pass""" + valid = """ +mandatory: True +question: | + Hello +field: user_name +""" + errs = find_errors_from_string(valid, input_file="") + self.assertFalse( + any("expected True, False" in e.err_str for e in errs), + f"Did not expect mandatory error for True, got: {errs}", + ) + + def test_mandatory_bool_false_valid(self): + """Valid: mandatory: False should pass""" + valid = """ +mandatory: False +question: | + Hello +field: user_name +""" + errs = find_errors_from_string(valid, input_file="") + self.assertFalse( + any("expected True, False" in e.err_str for e in errs), + f"Did not expect mandatory error for False, got: {errs}", + ) + + def test_mandatory_python_expression_valid(self): + """Valid: mandatory with a Python expression should pass""" + valid = """ +mandatory: user_age > 18 +question: | + Hello +field: user_name +""" + errs = find_errors_from_string(valid, input_file="") + self.assertFalse( + any("expected True, False" in e.err_str for e in errs), + f"Did not expect mandatory error for Python expression, got: {errs}", + ) + + def test_mandatory_invalid_string_errors(self): + """Error: mandatory with a non-Python string should be flagged""" + invalid = """ +mandatory: yes please +question: | + Hello +field: user_name +""" + errs = find_errors_from_string(invalid, input_file="") + self.assertTrue( + any("expected True, False" in e.err_str for e in errs), + f"Expected mandatory invalid string error, got: {errs}", + ) + + def test_initial_number_errors(self): + """Error: initial with a number should be flagged""" + invalid = """ +initial: 10 +code: | + x = 1 +""" + errs = find_errors_from_string(invalid, input_file="") + self.assertTrue( + any("got number: 10" in e.err_str for e in errs), + f"Expected initial number error, got: {errs}", + ) + + def test_mandatory_null_errors(self): + """Error: mandatory: null should be flagged""" + invalid = """ +mandatory: null +question: | + Hello +field: user_name +""" + errs = find_errors_from_string(invalid, input_file="") + self.assertTrue( + any("expected True, False" in e.err_str for e in errs), + f"Expected mandatory null error, got: {errs}", + ) + if __name__ == "__main__": unittest.main()