XLSForm / pyxform

A Python package to create XForms for ODK Collect.
BSD 2-Clause "Simplified" License
77 stars 134 forks source link

Detection of multilanguage choices only works if first choice list is multilanguage #653

Closed lognaturel closed 6 months ago

lognaturel commented 10 months ago

Identified when verifying https://github.com/XLSForm/pyxform/pull/650 but it's on master too. I think in general we try to identify columns by using the first few rows and run into issues like this. It's the same as https://github.com/XLSForm/pyxform/issues/637 but on the choices sheet.

    def test_detects_multilanguage(self):
        md = """
        | survey  |                        |       |            |            |
        |         | type                   | name  | label      | label::eng |
        |         | select_one c0          | f     | f          |            |
        |         | select_one c1  | q1    | Question 1 | Question A |
        | choices |           |      |       |            |           |
        |         | list name | name | label | label::eng | label::fr |
        |         | c0        | n    | l     |        | 
        |         | c1        | na   | la    | la-e       | la-f      |
        |         | c1        | nb   | lb    | lb-e       |           |
        """
        self.assertPyxformXform(
            md=md
        )

Error:

./test_translations.py::TestTranslationsChoices::test_detects_multilanguage Failed with Error: expected string or bytes-like object
  File "`~/.pyenv/versions/3.8.1/lib/python3.8/unittest/case.py", line 60, in testPartExecutor
    yield
  File "~/.pyenv/versions/3.8.1/lib/python3.8/unittest/case.py", line 676, in run
    self._callTestMethod(testMethod)
  File "~/.pyenv/versions/3.8.1/lib/python3.8/unittest/case.py", line 633, in _callTestMethod
    method()
  File "~/pyxform/tests/test_translations.py", line 1465, in test_detects_multilanguage
    self.assertPyxformXform(
  File "~pyxform/tests/pyxform_test_case.py", line 223, in assertPyxformXform
    xml = survey._to_pretty_xml()
  File "~/pyxform/pyxform/survey.py", line 872, in _to_pretty_xml
    xml_with_linebreaks = self.xml().toprettyxml(indent="  ")
  File "~/pyxform/pyxform/survey.py", line 259, in xml
    node("h:body", *self.xml_control(), **body_kwargs),
  File "~/pyxform/section.py", line 91, in xml_control
    control = e.xml_control()
  File "~/pyxform/pyxform/question.py", line 59, in xml_control
    xml_node = self.build_xml()
  File "~/pyxform/pyxform/question.py", line 238, in build_xml
    has_dyn_label = has_dynamic_label(choices[itemset], multi_language)
  File "~/pyxform/pyxform/utils.py", line 287, in has_dynamic_label
    and re.search(BRACKETED_TAG_REGEX, choice_list[i].get("label"))
  File "~/.pyenv/versions/3.8.1/lib/python3.8/re.py", line 199, in search
    return _compile(pattern, flags).search(string)
TypeError: expected string or bytes-like object
lindsay-stevens commented 9 months ago

I think this error is avoidable, but the underlying issue of using the first row should be addressed since it doesn't account for questions/choices specifying different languages in different rows. If this error is a high priority / blocker please let me know and I could try a quick fix.

lognaturel commented 9 months ago

I don't think it's a blocker but I do think looking at the issue list that this and #637 would be good next ones to look into.

I don't have any great ideas at the moment so I'm hoping you'll feel more creative!

lindsay-stevens commented 9 months ago

Looking at putting in a consistent language check where pyxform is already iterating through the XLSForm. Translations info needed during XLSX->internal transform for behaviour/warnings, and JSON->internal transform for behaviour.