# Path: pyxform/constants.py
# TYPE = "type"
# TITLE = "title"
# NAME = "name"
# ID_STRING = "id_string"
# SMS_KEYWORD = "sms_keyword"
# SMS_FIELD = "sms_field"
# SMS_OPTION = "sms_option"
# SMS_SEPARATOR = "sms_separator"
# SMS_ALLOW_MEDIA = "sms_allow_media"
# SMS_DATE_FORMAT = "sms_date_format"
# SMS_DATETIME_FORMAT = "sms_datetime_format"
# SMS_RESPONSE = "sms_response"
# COMPACT_PREFIX = "prefix"
# COMPACT_DELIMITER = "delimiter"
# COMPACT_TAG = "compact_tag"
# VERSION = "version"
# PUBLIC_KEY = "public_key"
# SUBMISSION_URL = "submission_url"
# AUTO_SEND = "auto_send"
# AUTO_DELETE = "auto_delete"
# DEFAULT_LANGUAGE_KEY = "default_language"
# DEFAULT_LANGUAGE_VALUE = "default"
# LABEL = "label"
# HINT = "hint"
# STYLE = "style"
# ATTRIBUTE = "attribute"
# ALLOW_CHOICE_DUPLICATES = "allow_choice_duplicates"
# BIND = (
#     "bind"  # TODO: What should I do with the nested types? (readonly and relevant) # noqa
# )
# MEDIA = "media"
# CONTROL = "control"
# APPEARANCE = "appearance"
# LOOP = "loop"
# COLUMNS = "columns"
# REPEAT = "repeat"
# GROUP = "group"
# CHILDREN = "children"
# SELECT_ONE = "select one"
# SELECT_ALL_THAT_APPLY = "select all that apply"
# RANK = "rank"
# CHOICES = "choices"
# LIST_NAME = "list name"
# CASCADING_SELECT = "cascading_select"
# TABLE_LIST = "table-list"  # hyphenated because it goes in appearance, and convention for appearance column is dashes # noqa
# FIELD_LIST = "field-list"
# SURVEY = "survey"
# SETTINGS = "settings"
# EXTERNAL_CHOICES = "external_choices"
# OSM = "osm"
# OSM_TYPE = "binary"
# NAMESPACES = "namespaces"
# SUPPORTED_SHEET_NAMES = [
#     SURVEY,
#     CHOICES,
#     SETTINGS,
#     EXTERNAL_CHOICES,
#     OSM,
# ]
# XLS_EXTENSIONS = [".xls"]
# XLSX_EXTENSIONS = [".xlsx", ".xlsm"]
# SUPPORTED_FILE_EXTENSIONS = XLS_EXTENSIONS + XLSX_EXTENSIONS
# LOCATION_PRIORITY = "location-priority"
# LOCATION_MIN_INTERVAL = "location-min-interval"
# LOCATION_MAX_AGE = "location-max-age"
# TRACK_CHANGES = "track-changes"
# IDENTIFY_USER = "identify-user"
# TRACK_CHANGES_REASONS = "track-changes-reasons"
# EXTERNAL_INSTANCES = ["calculate", "constraint", "readonly", "required", "relevant"]
# CURRENT_XFORMS_VERSION = "1.0.0"
# DEPRECATED_DEVICE_ID_METADATA_FIELDS = ["subscriberid", "simserial"]
# AUDIO_QUALITY_VOICE_ONLY = "voice-only"
# AUDIO_QUALITY_LOW = "low"
# AUDIO_QUALITY_NORMAL = "normal"
# AUDIO_QUALITY_EXTERNAL = "external"
# EXTERNAL_CHOICES_ITEMSET_REF_LABEL = "label"
# EXTERNAL_CHOICES_ITEMSET_REF_VALUE = "name"
# ROW_FORMAT_STRING: str = "[row : %s]"
# 
# Path: pyxform/errors.py
# class PyXFormError(Exception):
#     """Common base class for pyxform exceptions."""
# 
#     pass


import csv
import datetime
import re
import openpyxl
import xlrd
from collections import OrderedDict
from functools import reduce
from io import StringIO
from zipfile import BadZipFile
from xlrd import XLRDError
from xlrd.xldate import XLDateAmbiguous
from pyxform import constants
from pyxform.errors import PyXFormError
                        try:
                            row_dict[key] = xls_value_to_unicode(
                                value, value_type, workbook.datemode
                            )
                        except XLDateAmbiguous:
                            raise PyXFormError(
                                XL_DATE_AMBIGOUS_MSG % (sheet.name, column_header, row)
                            )
                # Taking this condition out so I can get accurate row numbers.
                # TODO: Do the same for csvs
                # if row_dict != {}:
            result.append(row_dict)
        return result, _list_to_dict_list(column_header_list)

    def xls_value_from_sheet(sheet, row, column):
        value = sheet.cell_value(row, column)
        value_type = sheet.cell_type(row, column)
        if value is not None and value != "":
            try:
                return xls_value_to_unicode(value, value_type, workbook.datemode)
            except XLDateAmbiguous:
                raise PyXFormError(XL_DATE_AMBIGOUS_MSG % (sheet.name, column, row))
        else:
            raise PyXFormError("Empty Value")

    result = OrderedDict()
    for sheet in workbook.sheets():
        # Note that the sheet exists but do no further processing here.
        result[sheet.name] = []
        # Do not process sheets that have nothing to do with XLSForm.

# Path: pyxform/constants.py
# TYPE = "type"
# TITLE = "title"
# NAME = "name"
# ID_STRING = "id_string"
# SMS_KEYWORD = "sms_keyword"
# SMS_FIELD = "sms_field"
# SMS_OPTION = "sms_option"
# SMS_SEPARATOR = "sms_separator"
# SMS_ALLOW_MEDIA = "sms_allow_media"
# SMS_DATE_FORMAT = "sms_date_format"
# SMS_DATETIME_FORMAT = "sms_datetime_format"
# SMS_RESPONSE = "sms_response"
# COMPACT_PREFIX = "prefix"
# COMPACT_DELIMITER = "delimiter"
# COMPACT_TAG = "compact_tag"
# VERSION = "version"
# PUBLIC_KEY = "public_key"
# SUBMISSION_URL = "submission_url"
# AUTO_SEND = "auto_send"
# AUTO_DELETE = "auto_delete"
# DEFAULT_LANGUAGE_KEY = "default_language"
# DEFAULT_LANGUAGE_VALUE = "default"
# LABEL = "label"
# HINT = "hint"
# STYLE = "style"
# ATTRIBUTE = "attribute"
# ALLOW_CHOICE_DUPLICATES = "allow_choice_duplicates"
# BIND = (
#     "bind"  # TODO: What should I do with the nested types? (readonly and relevant) # noqa
# )
# MEDIA = "media"
# CONTROL = "control"
# APPEARANCE = "appearance"
# LOOP = "loop"
# COLUMNS = "columns"
# REPEAT = "repeat"
# GROUP = "group"
# CHILDREN = "children"
# SELECT_ONE = "select one"
# SELECT_ALL_THAT_APPLY = "select all that apply"
# RANK = "rank"
# CHOICES = "choices"
# LIST_NAME = "list name"
# CASCADING_SELECT = "cascading_select"
# TABLE_LIST = "table-list"  # hyphenated because it goes in appearance, and convention for appearance column is dashes # noqa
# FIELD_LIST = "field-list"
# SURVEY = "survey"
# SETTINGS = "settings"
# EXTERNAL_CHOICES = "external_choices"
# OSM = "osm"
# OSM_TYPE = "binary"
# NAMESPACES = "namespaces"
# SUPPORTED_SHEET_NAMES = [
#     SURVEY,
#     CHOICES,
#     SETTINGS,
#     EXTERNAL_CHOICES,
#     OSM,
# ]
# XLS_EXTENSIONS = [".xls"]
# XLSX_EXTENSIONS = [".xlsx", ".xlsm"]
# SUPPORTED_FILE_EXTENSIONS = XLS_EXTENSIONS + XLSX_EXTENSIONS
# LOCATION_PRIORITY = "location-priority"
# LOCATION_MIN_INTERVAL = "location-min-interval"
# LOCATION_MAX_AGE = "location-max-age"
# TRACK_CHANGES = "track-changes"
# IDENTIFY_USER = "identify-user"
# TRACK_CHANGES_REASONS = "track-changes-reasons"
# EXTERNAL_INSTANCES = ["calculate", "constraint", "readonly", "required", "relevant"]
# CURRENT_XFORMS_VERSION = "1.0.0"
# DEPRECATED_DEVICE_ID_METADATA_FIELDS = ["subscriberid", "simserial"]
# AUDIO_QUALITY_VOICE_ONLY = "voice-only"
# AUDIO_QUALITY_LOW = "low"
# AUDIO_QUALITY_NORMAL = "normal"
# AUDIO_QUALITY_EXTERNAL = "external"
# EXTERNAL_CHOICES_ITEMSET_REF_LABEL = "label"
# EXTERNAL_CHOICES_ITEMSET_REF_VALUE = "name"
# ROW_FORMAT_STRING: str = "[row : %s]"
# 
# Path: pyxform/errors.py
# class PyXFormError(Exception):
#     """Common base class for pyxform exceptions."""
# 
#     pass


# Path: pyxform/xls2json_backends.py
import csv
import datetime
import re
import openpyxl
import xlrd
from collections import OrderedDict
from functools import reduce
from io import StringIO
from zipfile import BadZipFile
from xlrd import XLRDError
from xlrd.xldate import XLDateAmbiguous
from pyxform import constants
from pyxform.errors import PyXFormError

                        try:
                            row_dict[key] = xls_value_to_unicode(
                                value, value_type, workbook.datemode
                            )
                        except XLDateAmbiguous:
                            raise PyXFormError(
                                XL_DATE_AMBIGOUS_MSG % (sheet.name, column_header, row)
                            )
                # Taking this condition out so I can get accurate row numbers.
                # TODO: Do the same for csvs
                # if row_dict != {}:
            result.append(row_dict)
        return result, _list_to_dict_list(column_header_list)

    def xls_value_from_sheet(sheet, row, column):
        value = sheet.cell_value(row, column)
        value_type = sheet.cell_type(row, column)
        if value is not None and value != "":
            try:
                return xls_value_to_unicode(value, value_type, workbook.datemode)
            except XLDateAmbiguous:
                raise PyXFormError(XL_DATE_AMBIGOUS_MSG % (sheet.name, column, row))
        else:
            raise PyXFormError("Empty Value")

    result = OrderedDict()
    for sheet in workbook.sheets():
        # Note that the sheet exists but do no further processing here.
        result[sheet.name] = []
        # Do not process sheets that have nothing to do with XLSForm.

        if sheet.name not in constants.SUPPORTED_SHEET_NAMES: