Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"--skip_validate" arg for xls2xform.py #63

Merged
merged 3 commits into from
May 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified pyxform/odk_validate/ODK_Validate.jar
Binary file not shown.
23 changes: 20 additions & 3 deletions pyxform/odk_validate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,14 @@ def _kill_process_after_a_timeout(pid):
return (p.returncode, timeout, stdout, stderr)

def _java_installed():
p = Popen(["which","java"], stdout=PIPE)
return len(p.stdout.readlines()) != 0
# This alternative allows for java detection on Windows.
try:
p = Popen(["which", "java"], stdout=PIPE).stdout.readlines()
found = len(p) != 0
except WindowsError:
p = Popen('java -version', stderr=PIPE, stdout=PIPE).stderr.read()
found = p.startswith('java version')
return found

def _cleanup_errors(error_message):
def get_last_item(xpathStr):
Expand Down Expand Up @@ -106,7 +112,18 @@ def check_xform(path_to_xform):
returncode, timeout, stdout, stderr = run_popen_with_timeout(
["java", "-jar", ODK_VALIDATE_JAR, path_to_xform], 100)
warnings = []
stderr = stderr.decode('utf-8')
# On Windows, stderr may be latin-1; in which case utf-8 decode will fail.
# If both utf-8 and latin-1 decoding fail then raise all as IOError.
# If the above validate jar call fails, add make sure that the java path
# is set, e.g. PATH=C:\Program Files (x86)\Java\jre1.8.0_71\bin
try:
stderr = stderr.decode('utf-8')
except UnicodeDecodeError as ude:
try:
stderr = stderr.decode('latin-1')
except BaseException as be:
msg = "Failed to decode validate stderr as utf-8 or latin-1."
raise IOError(msg, ude, be)

if timeout:
return ["XForm took to long to completely validate."]
Expand Down
17 changes: 12 additions & 5 deletions pyxform/survey.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from survey_element import SurveyElement
from errors import PyXFormError
import constants
import os


nsmap = {
Expand Down Expand Up @@ -466,16 +467,22 @@ def print_xform_to_file(self, path=None, validate=True, warnings=None):
warnings = []
if not path:
path = self._print_name + ".xml"
fp = codecs.open(path, mode="w", encoding="utf-8")
fp.write(self._to_pretty_xml())
fp.close()
with codecs.open(path, mode="w", encoding="utf-8") as fp:
fp.write(self._to_pretty_xml())
if validate:
warnings.extend(check_xform(path))

def to_xml(self, validate=True, warnings=None):
with tempfile.NamedTemporaryFile() as tmp:
# On Windows, NamedTemporaryFile must be opened exclusively.
# So it must be explicitly created, opened, closed, and removed.
tmp = tempfile.NamedTemporaryFile(delete=False)
tmp.close()
try:
# this will throw an exception if the xml is not valid
self.print_xform_to_file(tmp.name, validate=validate, warnings=warnings)
self.print_xform_to_file(tmp.name, validate=validate,
warnings=warnings)
finally:
os.remove(tmp.name)
return self._to_pretty_xml()

def instantiate(self):
Expand Down
37 changes: 36 additions & 1 deletion pyxform/tests/xls2xform_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from unittest import TestCase
import pyxform
from pyxform.xls2xform import _create_parser


class XLS2XFormTests(TestCase):
Expand All @@ -24,4 +25,38 @@ class XLS2XFormTests(TestCase):
},
'title': u'test'
}
survey = pyxform.create_survey(**survey_package)
survey = pyxform.create_survey(**survey_package)

def test_create_parser_without_args(self):
"""Should exit when no args provided."""
with self.assertRaises(SystemExit):
_create_parser().parse_args([])

def test_create_parser_with_args(self):
"""Should parse the provided arguments."""
arg_xlsform = 'xlsform.xlsx'
arg_output = '.'
arg_json = '--json'
arg_skip_validate = '--skip_validate'
arg_list = [arg_json, arg_skip_validate, arg_xlsform, arg_output]
args = _create_parser().parse_args(arg_list)
self.assertEqual(arg_xlsform, args.path_to_XLSForm)
self.assertEqual(arg_output, args.output_path)
self.assertEqual(True, args.json)
self.assertEqual(False, args.skip_validate)

def test_create_parser_json_default_false(self):
"""Should have json=False if not specified."""
arg_xlsform = 'xlsform.xlsx'
arg_output = '.'
arg_list = [arg_xlsform, arg_output]
args = _create_parser().parse_args(arg_list)
self.assertEqual(False, args.json)

def test_create_parser_no_validate_default_true(self):
"""Should have no_validate=True if not specified."""
arg_xlsform = 'xlsform.xlsx'
arg_output = '.'
arg_list = [arg_xlsform, arg_output]
args = _create_parser().parse_args(arg_list)
self.assertEqual(True, args.skip_validate)
23 changes: 17 additions & 6 deletions pyxform/tests_v1/pyxform_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from pyxform.xls2json import workbook_to_json
from pyxform.builder import create_survey_element_from_dict
from pyxform.odk_validate import check_xform, ODKValidateError
import os


class PyxformTestError(Exception):
Expand Down Expand Up @@ -88,13 +89,23 @@ def _pull_xml_node_from_root(element_selector):
if debug:
print xml
if run_odk_validate:
with tempfile.NamedTemporaryFile(suffix='.xml') as tmp:
fp = codecs.open(tmp.name, mode="w", encoding="utf-8")
if '_xml_append' in kwargs:
xml += kwargs['_xml_append']
fp.write(xml)
fp.close()
# On Windows, NamedTemporaryFile must be opened exclusively.
# So it must be explicitly created, opened, closed, and removed.
tmp = tempfile.NamedTemporaryFile(suffix='.xml', delete=False)
tmp.close()
try:
with codecs.open(
tmp.name, mode="w", encoding="utf-8") as fp:
if '_xml_append' in kwargs:
xml += kwargs['_xml_append']
fp.write(xml)
fp.close()
check_xform(tmp.name)
finally:
# Clean up the temporary file
os.remove(tmp.name)
assert not os.path.isfile(tmp.name)

if len(odk_validate_error__contains) > 0:
raise PyxformTestError(
"ODKValidateError was not raised"
Expand Down
43 changes: 34 additions & 9 deletions pyxform/xls2xform.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from utils import sheet_to_csv, has_external_choices
import os

def xls2xform_convert(xlsform_path, xform_path):

def xls2xform_convert(xlsform_path, xform_path, validate=True):
warnings = []

json_survey = xls2json.parse_file_to_json(xlsform_path, warnings=warnings)
Expand All @@ -19,7 +20,7 @@ def xls2xform_convert(xlsform_path, xform_path):
# ODK Validate.
# This may be desirable since ODK Validate requires launching a subprocess
# that runs some java code.
survey.print_xform_to_file(xform_path, validate=True, warnings=warnings)
survey.print_xform_to_file(xform_path, validate=validate, warnings=warnings)
output_dir = os.path.split(xform_path)[0]
if has_external_choices(json_survey):
itemsets_csv = os.path.join(output_dir, "itemsets.csv")
Expand All @@ -31,13 +32,31 @@ def xls2xform_convert(xlsform_path, xform_path):
return warnings


if __name__ == '__main__':
def _create_parser():
"""
Parse command line arguments.
"""
parser = argparse.ArgumentParser()
parser.add_argument('path_to_XLSForm')
parser.add_argument('output_path')
parser.add_argument('--json',
action='store_true',
parser.add_argument(
"path_to_XLSForm",
help="Path to the Excel XSLX file with the XLSForm definition.")
parser.add_argument(
"output_path",
help="Path to save the output to.")
parser.add_argument(
"--json",
action="store_true",
help="Capture everything and report in JSON format.")
parser.add_argument(
"--skip_validate",
action="store_false",
default=True,
help="Skip default running of ODK Validate on the output XForm XML.")
return parser


def main_cli():
parser = _create_parser()
args = parser.parse_args()

if args.json:
Expand All @@ -46,7 +65,8 @@ def xls2xform_convert(xlsform_path, xform_path):
response = {'code': None, 'message': None, 'warnings': []}

try:
response['warnings'] = xls2xform_convert(args.path_to_XLSForm, args.output_path)
response['warnings'] = xls2xform_convert(
args.path_to_XLSForm, args.output_path, args.skip_validate)

response['code'] = 100
response['message'] = "Ok!"
Expand All @@ -62,8 +82,13 @@ def xls2xform_convert(xlsform_path, xform_path):

print json.dumps(response)
else:
warnings = xls2xform_convert(args.path_to_XLSForm, args.output_path)
warnings = xls2xform_convert(
args.path_to_XLSForm, args.output_path, args.skip_validate)
if len(warnings) > 0: print "Warnings:"
for w in warnings:
print w
print 'Conversion complete!'


if __name__ == '__main__':
main_cli()