From 1b877ac6b3a6b911c529c12439b4c1c9b83f6691 Mon Sep 17 00:00:00 2001 From: Nyoman Ribeka Date: Thu, 3 Oct 2019 12:54:03 -0400 Subject: [PATCH 1/3] Defaulting sheet name to survey if there is only single sheet. --- pyxform/tests/example_xls/survey_no_name.xlsx | Bin 0 -> 8700 bytes pyxform/tests/xls2json_tests.py | 10 ++++++++++ pyxform/xls2json_backends.py | 7 ++++++- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 pyxform/tests/example_xls/survey_no_name.xlsx diff --git a/pyxform/tests/example_xls/survey_no_name.xlsx b/pyxform/tests/example_xls/survey_no_name.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..76097a850bc1c86fb8293c1b31f909c9b322926f GIT binary patch literal 8700 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 KRtu`1-~JEF6B_aW literal 0 HcmV?d00001 diff --git a/pyxform/tests/xls2json_tests.py b/pyxform/tests/xls2json_tests.py index de6e1114c..a81bd1a2d 100644 --- a/pyxform/tests/xls2json_tests.py +++ b/pyxform/tests/xls2json_tests.py @@ -242,3 +242,13 @@ def test_a_unicode_csv_works(self): utf_csv_path = utils.path_to_text_fixture("utf_csv.csv") dict_value = csv_to_dict(utf_csv_path) self.assertTrue("\\ud83c" in json.dumps(dict_value)) + + +class DefaultToSurveyTest(TestCase): + def test_default_sheet_name_to_survey(self): + xls_path = utils.path_to_text_fixture("survey_no_name.xlsx") + dict_value = xls_to_dict(xls_path) + print (json.dumps(dict_value)) + self.assertTrue("survey" in json.dumps(dict_value)) + self.assertTrue("state" in json.dumps(dict_value)) + self.assertTrue("The State" in json.dumps(dict_value)) diff --git a/pyxform/xls2json_backends.py b/pyxform/xls2json_backends.py index c57200902..fcb261147 100644 --- a/pyxform/xls2json_backends.py +++ b/pyxform/xls2json_backends.py @@ -209,7 +209,12 @@ def slugify(s): for sheet in workbook.sheets(): # Do not process sheets that have nothing to do with XLSForm. if sheet.name not in constants.SUPPORTED_SHEET_NAMES: - continue + if len(workbook.sheets()) == 1: + result[constants.SURVEY], result[ + "%s_header" % sheet.name + ] = xls_to_dict_normal_sheet(sheet) + else: + continue if sheet.name == constants.CASCADING_CHOICES: result[sheet.name] = _xls_to_dict_cascade_sheet(sheet) else: From c9d24cf4864c94d1d40ebddbe67528d601a2aad1 Mon Sep 17 00:00:00 2001 From: Nyoman Ribeka Date: Thu, 3 Oct 2019 13:14:12 -0400 Subject: [PATCH 2/3] Using the correct name for the header section. --- pyxform/xls2json_backends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyxform/xls2json_backends.py b/pyxform/xls2json_backends.py index fcb261147..6f4b7a543 100644 --- a/pyxform/xls2json_backends.py +++ b/pyxform/xls2json_backends.py @@ -211,7 +211,7 @@ def slugify(s): if sheet.name not in constants.SUPPORTED_SHEET_NAMES: if len(workbook.sheets()) == 1: result[constants.SURVEY], result[ - "%s_header" % sheet.name + "%s_header" % constants.SURVEY ] = xls_to_dict_normal_sheet(sheet) else: continue From eb40aabd997dd38d748ae5562b3978d86a7f2e73 Mon Sep 17 00:00:00 2001 From: Nyoman Ribeka Date: Thu, 3 Oct 2019 13:30:17 -0400 Subject: [PATCH 3/3] Adding unit tests for the xls coversion to an actual form. --- .../test_expected_output/survey_no_name.xml | 23 +++++++++++++++++++ pyxform/tests/xlsform_spec_test.py | 22 ++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 pyxform/tests/test_expected_output/survey_no_name.xml diff --git a/pyxform/tests/test_expected_output/survey_no_name.xml b/pyxform/tests/test_expected_output/survey_no_name.xml new file mode 100644 index 000000000..b37d087e6 --- /dev/null +++ b/pyxform/tests/test_expected_output/survey_no_name.xml @@ -0,0 +1,23 @@ + + + + data + + + + + + + + + + + + + + + + + + + diff --git a/pyxform/tests/xlsform_spec_test.py b/pyxform/tests/xlsform_spec_test.py index c87b98516..80b7dc7a0 100644 --- a/pyxform/tests/xlsform_spec_test.py +++ b/pyxform/tests/xlsform_spec_test.py @@ -171,5 +171,27 @@ def runTest(self): os.remove(self.output_path) +class DefaultSurveySheetTest(XFormTestCase): + maxDiff = None + + def runTest(self): + filename = "survey_no_name.xlsx" + self.get_file_path(filename) + expected_output_path = os.path.join( + DIR, "test_expected_output", self.root_filename + ".xml" + ) + + warnings = [] + json_survey = pyxform.xls2json.parse_file_to_json( + self.path_to_excel_file, warnings=warnings + ) + survey = pyxform.create_survey_element_from_dict(json_survey) + survey.print_xform_to_file(self.output_path, warnings=warnings) + + with codecs.open(expected_output_path, "rb", encoding="utf-8") as expected_file: + with codecs.open(self.output_path, "rb", encoding="utf-8") as actual_file: + self.assertXFormEqual(expected_file.read(), actual_file.read()) + + if __name__ == "__main__": unittest.main()