diff --git a/pyxform/survey_element.py b/pyxform/survey_element.py index c09293732..6a07bfaca 100644 --- a/pyxform/survey_element.py +++ b/pyxform/survey_element.py @@ -1,10 +1,13 @@ +import re + import json from pyxform import constants -from pyxform.utils import is_valid_xml_tag, node, unicode -from pyxform.xls2json import print_pyobj_to_json -from pyxform.question_type_dictionary import QUESTION_TYPE_DICT from pyxform.errors import PyXFormError +from pyxform.question_type_dictionary import QUESTION_TYPE_DICT +from pyxform.utils import is_valid_xml_tag, node, unicode, \ + INVALID_XFORM_TAG_REGEXP +from pyxform.xls2json import print_pyobj_to_json try: from functools import lru_cache @@ -136,9 +139,12 @@ def add_children(self, children): def validate(self): if not is_valid_xml_tag(self.name): - msg = "The name '%s' is an invalid xml tag. Names must begin with" \ - " a letter, colon, or underscore, subsequent characters can" \ - " include numbers, dashes, and periods." % self.name + invalid_char = re.search(INVALID_XFORM_TAG_REGEXP, self.name) + msg = "The name '{}' is an invalid XML tag, it contains an " \ + "invalid character '{}'. Names must begin with a letter, " \ + "colon, or underscore, subsequent characters can include " \ + "numbers, dashes, and periods".format( + self.name, invalid_char.group(0)) raise PyXFormError(msg) # TODO: Make sure renaming this doesn't cause any problems diff --git a/pyxform/tests_v1/test_sheet_columns.py b/pyxform/tests_v1/test_sheet_columns.py index f3b94928e..49f5ab1c5 100644 --- a/pyxform/tests_v1/test_sheet_columns.py +++ b/pyxform/tests_v1/test_sheet_columns.py @@ -129,6 +129,25 @@ def test_missing_list_name(self): 'list name', ]) + def test_clear_filename_error_message(self): + """Test clear filename error message""" + error_message = "The name 'bad@filename' is an invalid XML tag, it " \ + "contains an invalid character '@'. Names must begin" \ + " with a letter, colon, or underscore, subsequent " \ + "characters can include numbers, dashes, and periods" + self.assertPyxformXform( + name='bad@filename', + ss_structure=self._simple_choice_ss([ + {'list_name': 'l1', + 'name': 'c1', + 'label': 'choice 1'}, + {'list_name': 'l1', + 'name': 'c2', + 'label': 'choice 2'}]), + errored=True, + error__contains=[error_message] + ) + class AliasesTests(PyxformTestCase): """ diff --git a/pyxform/utils.py b/pyxform/utils.py index 524d32136..d031974c8 100644 --- a/pyxform/utils.py +++ b/pyxform/utils.py @@ -32,6 +32,9 @@ "start": TAG_START_CHAR, "char": TAG_CHAR } + +INVALID_XFORM_TAG_REGEXP = r"[^a-zA-Z:_][^a-zA-Z:_0-9\-.]*" + NSMAP = { u"xmlns": u"http://www.w3.org/2002/xforms", u"xmlns:h": u"http://www.w3.org/1999/xhtml",