def get_nsmap(self): """Add additional namespaces""" namespaces = getattr(self, constants.NAMESPACES, None) if namespaces and isinstance(namespaces, basestring): nslist = [ ns.split("=") for ns in namespaces.split() if len(ns.split("=")) == 2 and ns.split("=")[0] != "" ] xmlns = "xmlns:" nsmap = NSMAP.copy() nsmap.update( dict([(xmlns + k, v.replace('"', "").replace("'", "")) for k, v in nslist if xmlns + k not in nsmap])) return nsmap return NSMAP
def get_nsmap(self): """Add additional namespaces""" namespaces = getattr(self, constants.NAMESPACES, None) if namespaces and isinstance(namespaces, basestring): nslist = [ ns.split('=') for ns in namespaces.split() if len(ns.split('=')) == 2 and ns.split('=')[0] != '' ] xmlns = u'xmlns:' nsmap = NSMAP.copy() nsmap.update(dict([ (xmlns + k, v.replace('"', '').replace("'", "")) for k, v in nslist if xmlns + k not in nsmap ])) return nsmap else: return NSMAP
def register_nsmap(): """Function to register NSMAP namespaces with ETree""" for prefix, uri in NSMAP.items(): prefix_no_xmlns = prefix.replace("xmlns", "").replace(":", "") ETree.register_namespace(prefix_no_xmlns, uri)
def get_dict(self): json_str = json.dumps(self._dict) for uri in NSMAP.values(): json_str = json_str.replace("{%s}" % uri, "") return json.loads(json_str)
def assertPyxformXform(self, **kwargs): """ PyxformTestCase.assertPyxformXform() named arguments: ----------------------------------------------------- one of these possible survey input types * md: (str) a markdown formatted xlsform (easy to read in code) [consider a plugin to help with formatting md tables, e.g. https://github.com/vkocubinsky/SublimeTableEditor] * ss_structure: (dict) a python dictionary with sheets and their contents. best used in cases where testing whitespace and cells' type is important * survey: (pyxform.survey.Survey) easy for reuse within a test # Note: XLS is not implemented at this time. You can use builder to create a pyxform Survey object one or many of these string "matchers": * xml__contains: an array of strings which exist in the resulting xml. [xml|model|instance|itext]_excludes are also supported. * error__contains: a list of strings which should exist in the error * error__not_contains: a list of strings which should not exist in the error * odk_validate_error__contains: list of strings; run_odk_validate must be set * warning__contains: a list of strings which should exist in the warnings * warning__not_contains: a list of strings which should not exist in the warnings * warnings_count: the number of expected warning messages * xml__excludes: an array of strings which should not exist in the resulting xml. [xml|model|instance|itext]_excludes are also supported. optional other parameters passed to pyxform: * errored: (bool) if the xlsform is not supposed to compile, this must be True * name: (str) a valid xml tag to be used as the form name * id_string: (str) * title: (str) * run_odk_validate: (bool) when True, runs ODK Validate process Default value = False because it slows down tests * warnings: (list) a list to use for storing warnings for inspection. """ debug = kwargs.get("debug", False) expecting_invalid_survey = kwargs.get("errored", False) errors = [] warnings = kwargs.get("warnings", []) xml_nodes = {} run_odk_validate = kwargs.get("run_odk_validate", False) odk_validate_error__contains = kwargs.get("odk_validate_error__contains", []) try: if "md" in kwargs.keys(): kwargs = self._autoname_inputs(kwargs) survey = self.md_to_pyxform_survey( kwargs.get("md"), kwargs, warnings=warnings ) elif "ss_structure" in kwargs.keys(): kwargs = self._autoname_inputs(kwargs) survey = self._ss_structure_to_pyxform_survey( kwargs.get("ss_structure"), kwargs, warnings=warnings, ) else: survey = kwargs.get("survey") xml = survey._to_pretty_xml() root = ETree.fromstring(xml.encode("utf-8")) # Ensure all namespaces are present, even if unused final_nsmap = NSMAP.copy() final_nsmap.update(survey.get_nsmap()) root.attrib.update(final_nsmap) xml_nodes["xml"] = root def _pull_xml_node_from_root(element_selector): _r = root.findall( ".//n:%s" % element_selector, namespaces={"n": "http://www.w3.org/2002/xforms"}, ) if _r: return _r[0] return False for _n in ["model", "instance", "itext"]: xml_nodes[_n] = _pull_xml_node_from_root(_n) if debug: logger.debug(xml) if run_odk_validate: self._run_odk_validate(xml=xml) if odk_validate_error__contains: raise PyxformTestError("ODKValidateError was not raised") except PyXFormError as e: survey = False errors = [unicode(e)] if debug: logger.debug("<xml unavailable />") logger.debug("ERROR: '%s'", errors[0]) except ODKValidateError as e: if not odk_validate_error__contains: raise PyxformTestError( "ODK Validate error was thrown but " + "'odk_validate_error__contains'" + " was empty:" + unicode(e) ) for v_err in odk_validate_error__contains: self.assertContains( e.args[0], v_err, msg_prefix="odk_validate_error__contains" ) else: survey = True if survey: def _check(keyword, verb): verb_str = "%s__%s" % (keyword, verb) bad_kwarg = "%s_%s" % (code, verb) if bad_kwarg in kwargs: good_kwarg = "%s__%s" % (code, verb) raise SyntaxError( ( "'%s' is not a valid parameter. " "Use double underscores: '%s'" ) % (bad_kwarg, good_kwarg) ) def check_content(content): text_arr = kwargs[verb_str] for i in text_arr: if verb == "contains": self.assertContains(content, i, msg_prefix=keyword) else: self.assertNotContains(content, i, msg_prefix=keyword) return verb_str, check_content if "body_contains" in kwargs or "body__contains" in kwargs: raise SyntaxError( "Invalid parameter: 'body__contains'." "Use 'xml__contains' instead" ) # guarantee that strings contain alphanumerically sorted attributes across Python versions reorder_attributes(root) for code in ["xml", "instance", "model", "itext"]: for verb in ["contains", "excludes"]: (code__str, checker) = _check(code, verb) if kwargs.get(code__str): checker( ETree.tostring(xml_nodes[code], encoding="utf-8").decode( "utf-8" ) ) if survey is False and expecting_invalid_survey is False: raise PyxformTestError( "Expected valid survey but compilation failed. " "Try correcting the error with 'debug=True', " "setting 'errored=True', " "and or optionally 'error__contains=[...]'" "\nError(s): " + "\n".join(errors) ) elif survey and expecting_invalid_survey: raise PyxformTestError("Expected survey to be invalid.") search_test_kwargs = ( "error__contains", "error__not_contains", "warnings__contains", "warnings__not_contains", ) for k in search_test_kwargs: if k not in kwargs: continue if k.endswith("__contains"): assertion = self.assertContains elif k.endswith("__not_contains"): assertion = self.assertNotContains else: raise PyxformTestError("Unexpected search test kwarg: {}".format(k)) if k.startswith("error"): joined = "\n".join(errors) elif k.startswith("warnings"): joined = "\n".join(warnings) else: raise PyxformTestError("Unexpected search test kwarg: {}".format(k)) for text in kwargs[k]: assertion(joined, text, msg_prefix=k) if "warnings_count" in kwargs: c = kwargs.get("warnings_count") if not isinstance(c, int): PyxformTestError("warnings_count must be an integer.") self.assertEqual(c, len(warnings))
def assertPyxformXform(self, **kwargs): """ PyxformTestCase.assertPyxformXform() named arguments: ----------------------------------------------------- one of these possible survey input types * md: (str) a markdown formatted xlsform (easy to read in code) [consider a plugin to help with formatting md tables, e.g. https://github.com/vkocubinsky/SublimeTableEditor] * ss_structure: (dict) a python dictionary with sheets and their contents. best used in cases where testing whitespace and cells' type is important * survey: (pyxform.survey.Survey) easy for reuse within a test # Note: XLS is not implemented at this time. You can use builder to create a pyxform Survey object one or many of these string "matchers": * xml__contains: an array of strings which exist in the resulting xml * error__contains: a list of strings which should exist in the error * odk_validate_error__contains: list of strings; run_odk_validate must be set optional other parameters passed to pyxform: * errored: (bool) if the xlsform is not supposed to compile, this must be True * name: (str) a valid xml tag to be used as the form name * id_string: (str) * title: (str) * run_odk_validate: (bool) when True, runs ODK Validate process Default value = False because it slows down tests """ debug = kwargs.get('debug', False) expecting_invalid_survey = kwargs.get('errored', False) errors = [] xml_nodes = {} run_odk_validate = kwargs.get('run_odk_validate', False) odk_validate_error__contains = \ kwargs.get('odk_validate_error__contains', []) try: if 'md' in kwargs.keys(): kwargs = self._autoname_inputs(kwargs) survey = self.md_to_pyxform_survey(kwargs.get('md'), kwargs) elif 'ss_structure' in kwargs.keys(): kwargs = self._autoname_inputs(kwargs) survey = self._ss_structure_to_pyxform_survey( kwargs.get('ss_structure'), kwargs) else: survey = kwargs.get("survey") xml = survey._to_pretty_xml() root = ETree.fromstring(xml.encode('utf-8')) # Ensure all namespaces are present, even if unused final_nsmap = NSMAP.copy() final_nsmap.update(survey.get_nsmap()) root.attrib.update(final_nsmap) xml_nodes['xml'] = root def _pull_xml_node_from_root(element_selector): ns = 'http://www.w3.org/2002/xforms' _r = root.findall('.//n:%s' % element_selector, namespaces={'n': ns}) if len(_r) == 0: return False else: return _r[0] for _n in ['model', 'instance', 'itext']: xml_nodes[_n] = _pull_xml_node_from_root(_n) if debug: print(xml) if run_odk_validate: self._run_odk_validate(xml=xml) if len(odk_validate_error__contains) > 0: raise PyxformTestError("ODKValidateError was not raised") except PyXFormError as e: survey = False errors = [unicode(e)] if debug: print("<xml unavailable />") print("ERROR: '%s'" % errors[0]) except ODKValidateError as e: if len(odk_validate_error__contains) is 0: raise PyxformTestError("ODK Validate error was thrown but " + "'odk_validate_error__contains'" + " was empty:" + unicode(e)) for v_err in odk_validate_error__contains: self.assertContains(e.args[0].decode('utf-8'), v_err, msg_prefix='odk_validate_error__contains') else: survey = True if survey: def _check_contains(keyword): contains_str = '%s__contains' % keyword def check_content(content): text_arr = kwargs[contains_str] for i in text_arr: self.assertContains(content, i, msg_prefix=keyword) return contains_str, check_content if 'body_contains' in kwargs or 'body__contains' in kwargs: raise SyntaxError("Invalid parameter: 'body__contains'." "Use 'xml__contains' instead") for code in ['xml', 'instance', 'model', 'itext']: (code__str, checker) = _check_contains(code) if kwargs.get(code__str): checker(ETree.tostring( xml_nodes[code], encoding='utf-8').decode('utf-8')) bad_kwarg = '%s_contains' % code if bad_kwarg in kwargs: good_kwarg = '%s__contains' % code raise SyntaxError(("'%s' is not a valid parameter. " "Use double underscores: '%s'") % (bad_kwarg, good_kwarg)) if survey is False and expecting_invalid_survey is False: raise PyxformTestError( "Expected valid survey but compilation failed. " "Try correcting the error with 'debug=True', " "setting 'errored=True', " "and or optionally 'error__contains=[...]'" "\nError(s): " + "\n".join(errors) ) elif survey and expecting_invalid_survey: raise PyxformTestError("Expected survey to be invalid.") if 'error__contains' in kwargs: joined_error = '\n'.join(errors) for text in kwargs['error__contains']: self.assertContains(joined_error, text, msg_prefix="error__contains")
def register_nsmap(): for prefix, uri in NSMAP.items(): prefix_no_xmlns = prefix.replace("xmlns", "").replace(":", "") ETree.register_namespace(prefix_no_xmlns, uri)
def assertPyxformXform(self, **kwargs): """ PyxformTestCase.assertPyxformXform() named arguments: ----------------------------------------------------- one of these possible survey input types * md: (str) a markdown formatted xlsform (easy to read in code) [consider a plugin to help with formatting md tables, e.g. https://github.com/vkocubinsky/SublimeTableEditor]. Escape a literal pipe value with a single back-slash. * ss_structure: (dict) a python dictionary with sheets and their contents. best used in cases where testing whitespace and cells' type is important * survey: (pyxform.survey.Survey) easy for reuse within a test # Note: XLS is not implemented at this time. You can use builder to create a pyxform Survey object one or many of these string "matchers": * xml__contains: an array of strings which exist in the resulting xml. [xml|model|instance|itext]_excludes are also supported. * error__contains: a list of strings which should exist in the error * error__not_contains: a list of strings which should not exist in the error * odk_validate_error__contains: list of strings; run_odk_validate must be set * warnings__contains: a list of strings which should exist in the warnings * warnings__not_contains: a list of strings which should not exist in the warnings * warnings_count: the number of expected warning messages * xml__excludes: an array of strings which should not exist in the resulting xml. [xml|model|instance|itext]_excludes are also supported. * xml__xpath_exact: A list of tuples where the first tuple element is an XPath expression and the second tuple element is a set of exact string match results that are expected. * xml__xpath_count: A list of tuples where the first tuple element is an XPath expression and the second tuple element is the integer number of match results that are expected. * xml__xpath_match: A list of XPath expression strings for which exactly one match result each is expected. Effectively a shortcut for xml__xpath_count with a count of 1. For each of the xpath_* matchers above, if the XPath expression is looking for an element in the 'default' namespace (xforms) then use an 'x' namespace prefix for the element. For example to find input nodes in the body: ".//h:body/x:input". This 'x' prefix is not required for attributes. When writing a xpath_* test, use debug=True to show the XPath match results. optional other parameters passed to pyxform: * errored: (bool) if the xlsform is not supposed to compile, this must be True * name: (str) a valid xml tag to be used as the form name * id_string: (str) * title: (str) * run_odk_validate: (bool) when True, runs ODK Validate process Default value = False because it slows down tests * warnings: (list) a list to use for storing warnings for inspection. * debug: (bool) when True, log details of the test to stdout. Details include the input survey markdown, the XML document, XPath match strings. """ debug = kwargs.get("debug", False) expecting_invalid_survey = kwargs.get("errored", False) errors = [] warnings = kwargs.get("warnings", []) xml_nodes = {} run_odk_validate = kwargs.get("run_odk_validate", False) odk_validate_error__contains = kwargs.get( "odk_validate_error__contains", []) survey_valid = True try: if "md" in kwargs.keys(): kwargs = self._autoname_inputs(kwargs) survey = self.md_to_pyxform_survey(kwargs.get("md"), kwargs, warnings=warnings) elif "ss_structure" in kwargs.keys(): kwargs = self._autoname_inputs(kwargs) survey = self._ss_structure_to_pyxform_survey( kwargs.get("ss_structure"), kwargs, warnings=warnings, ) else: survey = kwargs.get("survey") xml = survey._to_pretty_xml() root = etree.fromstring(xml.encode("utf-8")) # Ensure all namespaces are present, even if unused survey_nsmap = survey.get_nsmap() final_nsmap = NSMAP.copy() final_nsmap.update(survey_nsmap) root.nsmap.update(final_nsmap) final_nsmap_xpath = { "x": final_nsmap["xmlns"], **{ k.split(":")[1]: v for k, v in final_nsmap.items() if k != "xmlns" }, } final_nsmap_subs = [(f' {k}="{v}"', "") for k, v in final_nsmap.items()] # guarantee that strings contain alphanumerically sorted attributes across # Python versions reorder_attributes(root) xml_nodes["xml"] = root def _pull_xml_node_from_root(element_selector): _r = root.findall( ".//n:%s" % element_selector, namespaces={"n": "http://www.w3.org/2002/xforms"}, ) if _r: return _r[0] return False for _n in ["model", "instance", "itext"]: xml_nodes[_n] = _pull_xml_node_from_root(_n) if debug: logger.debug(xml) if run_odk_validate: self._run_odk_validate(xml=xml) if odk_validate_error__contains: raise PyxformTestError("ODKValidateError was not raised") except PyXFormError as e: survey_valid = False errors = [str(e)] if debug: logger.debug("<xml unavailable />") logger.debug("ERROR: '%s'", errors[0]) except ODKValidateError as e: if not odk_validate_error__contains: raise PyxformTestError("ODK Validate error was thrown but " + "'odk_validate_error__contains'" + " was empty:" + str(e)) for v_err in odk_validate_error__contains: self.assertContains(e.args[0], v_err, msg_prefix="odk_validate_error__contains") if survey_valid: def _check(keyword, verb): verb_str = "%s__%s" % (keyword, verb) bad_kwarg = "%s_%s" % (code, verb) if bad_kwarg in kwargs: good_kwarg = "%s__%s" % (code, verb) raise SyntaxError(("'%s' is not a valid parameter. " "Use double underscores: '%s'") % (bad_kwarg, good_kwarg)) def check_content(content, expected): if content is None: self.fail( msg="No '{}' found in document.".format(keyword)) cstr = etree.tostring(content, encoding=str, pretty_print=True) matcher_context = MatcherContext( debug=debug, nsmap_xpath=final_nsmap_xpath, nsmap_subs=final_nsmap_subs, content_str=cstr, ) for i in expected: if verb == "contains": self.assertContains(cstr, i, msg_prefix=keyword) elif verb == "excludes": self.assertNotContains(cstr, i, msg_prefix=keyword) elif verb == "xpath_exact": self.assert_xpath_exact( matcher_context=matcher_context, content=content, xpath=i[0], expected=i[1], ) elif verb == "xpath_count": self.assert_xpath_count( matcher_context=matcher_context, content=content, xpath=i[0], expected=i[1], ) elif verb == "xpath_match": self.assert_xpath_count( matcher_context=matcher_context, content=content, xpath=i, expected=1, ) return verb_str, check_content if "body_contains" in kwargs or "body__contains" in kwargs: raise SyntaxError("Invalid parameter: 'body__contains'." "Use 'xml__contains' instead") for code in ["xml", "instance", "model", "itext"]: for _verb in ["contains", "excludes"]: (code__str, checker) = _check(code, _verb) if kwargs.get(code__str): checker(xml_nodes[code], kwargs[code__str]) for xpath_verb in ("xpath_exact", "xpath_count", "xpath_match"): code__str, checker = _check("xml", xpath_verb) if kwargs.get(code__str) is not None: checker(xml_nodes["xml"], kwargs[code__str]) if not survey_valid and not expecting_invalid_survey: raise PyxformTestError( "Expected valid survey but compilation failed. " "Try correcting the error with 'debug=True', " "setting 'errored=True', " "and or optionally 'error__contains=[...]'" "\nError(s): " + "\n".join(errors)) elif survey_valid and expecting_invalid_survey: raise PyxformTestError("Expected survey to be invalid.") search_test_kwargs = ( "error__contains", "error__not_contains", "warnings__contains", "warnings__not_contains", ) for k in search_test_kwargs: if k not in kwargs: continue if k.endswith("__contains"): assertion = self.assertContains elif k.endswith("__not_contains"): assertion = self.assertNotContains else: raise PyxformTestError( "Unexpected search test kwarg: {}".format(k)) if k.startswith("error"): joined = "\n".join(errors) elif k.startswith("warnings"): joined = "\n".join(warnings) else: raise PyxformTestError( "Unexpected search test kwarg: {}".format(k)) for text in kwargs[k]: assertion(joined, text, msg_prefix=k) if "warnings_count" in kwargs: c = kwargs.get("warnings_count") if not isinstance(c, int): PyxformTestError("warnings_count must be an integer.") self.assertEqual(c, len(warnings))
def assertPyxformXform(self, **kwargs): """ PyxformTestCase.assertPyxformXform() named arguments: ----------------------------------------------------- one of these possible survey input types * md: (str) a markdown formatted xlsform (easy to read in code) [consider a plugin to help with formatting md tables, e.g. https://github.com/vkocubinsky/SublimeTableEditor] * ss_structure: (dict) a python dictionary with sheets and their contents. best used in cases where testing whitespace and cells' type is important * survey: (pyxform.survey.Survey) easy for reuse within a test # Note: XLS is not implemented at this time. You can use builder to create a pyxform Survey object one or many of these string "matchers": * xml__contains: an array of strings which exist in the resulting xml * error__contains: a list of strings which should exist in the error * odk_validate_error__contains: list of strings; run_odk_validate must be set optional other parameters passed to pyxform: * errored: (bool) if the xlsform is not supposed to compile, this must be True * name: (str) a valid xml tag to be used as the form name * id_string: (str) * title: (str) * run_odk_validate: (bool) when True, runs ODK Validate process Default value = False because it slows down tests """ debug = kwargs.get('debug', False) expecting_invalid_survey = kwargs.get('errored', False) errors = [] xml_nodes = {} run_odk_validate = kwargs.get('run_odk_validate', False) odk_validate_error__contains = \ kwargs.get('odk_validate_error__contains', []) try: if 'md' in kwargs.keys(): kwargs = self._autoname_inputs(kwargs) survey = self.md_to_pyxform_survey(kwargs.get('md'), kwargs) elif 'ss_structure' in kwargs.keys(): kwargs = self._autoname_inputs(kwargs) survey = self._ss_structure_to_pyxform_survey( kwargs.get('ss_structure'), kwargs) else: survey = kwargs.get("survey") xml = survey._to_pretty_xml() root = ETree.fromstring(xml.encode('utf-8')) # Ensure all namespaces are present, even if unused final_nsmap = NSMAP.copy() final_nsmap.update(survey.get_nsmap()) root.attrib.update(final_nsmap) xml_nodes['xml'] = root def _pull_xml_node_from_root(element_selector): ns = 'http://www.w3.org/2002/xforms' _r = root.findall('.//n:%s' % element_selector, namespaces={'n': ns}) if len(_r) == 0: return False else: return _r[0] for _n in ['model', 'instance', 'itext']: xml_nodes[_n] = _pull_xml_node_from_root(_n) if debug: print(xml) if run_odk_validate: self._run_odk_validate(xml=xml) if len(odk_validate_error__contains) > 0: raise PyxformTestError("ODKValidateError was not raised") except PyXFormError as e: survey = False errors = [unicode(e)] if debug: print("<xml unavailable />") print("ERROR: '%s'" % errors[0]) except ODKValidateError as e: if len(odk_validate_error__contains) is 0: raise PyxformTestError("ODK Validate error was thrown but " + "'odk_validate_error__contains'" + " was empty:" + unicode(e)) for v_err in odk_validate_error__contains: self.assertContains(unicode(e), v_err, msg_prefix='odk_validate_error__contains') else: survey = True if survey: def _check_contains(keyword): contains_str = '%s__contains' % keyword def check_content(content): text_arr = kwargs[contains_str] for i in text_arr: self.assertContains(content, i, msg_prefix=keyword) return contains_str, check_content if 'body_contains' in kwargs or 'body__contains' in kwargs: raise SyntaxError("Invalid parameter: 'body__contains'." "Use 'xml__contains' instead") for code in ['xml', 'instance', 'model', 'itext']: (code__str, checker) = _check_contains(code) if kwargs.get(code__str): checker(ETree.tostring( xml_nodes[code], encoding='utf-8').decode('utf-8')) bad_kwarg = '%s_contains' % code if bad_kwarg in kwargs: good_kwarg = '%s__contains' % code raise SyntaxError(("'%s' is not a valid parameter. " "Use double underscores: '%s'") % (bad_kwarg, good_kwarg)) if survey is False and expecting_invalid_survey is False: raise PyxformTestError( "Expected valid survey but compilation failed. " "Try correcting the error with 'debug=True', " "setting 'errored=True', " "and or optionally 'error__contains=[...]'" "\nError(s): " + "\n".join(errors) ) elif survey and expecting_invalid_survey: raise PyxformTestError("Expected survey to be invalid.") if 'error__contains' in kwargs: joined_error = '\n'.join(errors) for text in kwargs['error__contains']: self.assertContains(joined_error, text, msg_prefix="error__contains")