Skip to content

fix(qual): fix format for qualitative multiple select questions DEV-2233 - #347

Merged
Guitlle merged 13 commits into
mainfrom
dev-2233-export-qual-qs
Jun 11, 2026
Merged

fix(qual): fix format for qualitative multiple select questions DEV-2233#347
Guitlle merged 13 commits into
mainfrom
dev-2233-export-qual-qs

Conversation

@Guitlle

@Guitlle Guitlle commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Refactor QualSelectMultipleField to export ordinal columns containing text values

Description

  • Replaced the legacy behavior in QualSelectMultipleField where selected qualitative multiple-select responses were aggregated into a single, comma-separated string
  • Implemented get_labels() and get_value_names() to dynamically yield a fixed number of ordinal positional columns (e.g., Option 1, Option 2, ... Option N). The number of columns generated matches the maximum possible number of choices mapped in the field schema
  • Modified get_value_from_entry() to return an ordered list of the specific text labels (choices) the user selected
  • Implemented a new format() method that maps the textual values into different columns for each option
  • Updated the test_additional_field_exports_advanced unit tests in tests/test_additional_field_exports.py

Preview steps

Run pytest, this is covered by unit tests.

@Guitlle
Guitlle requested a review from noliveleger June 8, 2026 23:28
@coveralls

coveralls commented Jun 8, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 86.834% (-0.02%) from 86.852% — dev-2233-export-qual-qs into main

@Guitlle Guitlle changed the title fix(qual): Fix format for qualitative multiple select questions DEV-2233 fix(qual): fix format for qualitative multiple select questions DEV-2233 Jun 9, 2026
@noliveleger

Copy link
Copy Markdown
Contributor

@greptileai review

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown

Greptile Summary

This PR refactors QualSelectMultipleField to emit one column per choice (like FormChoiceFieldWithMultipleSelect) instead of a single comma-separated summary column, and updates the corresponding tests to match the new format.

  • Adds get_labels(), get_value_names(), and format() overrides that follow the same multiple_select='both'/'summary'/'details' pattern as the non-qual multiple-select field; choice columns use internal UUIDs as keys while human-readable labels are returned by get_labels() for column headers.
  • get_value_from_entry() now returns a list of UUID strings instead of a pre-formatted CSV string, and format() maps those UUIDs to per-choice '0'/'1' values while building a space-joined summary string for the summary column.

Confidence Score: 5/5

The change is safe to merge. It correctly replaces a single-column CSV representation with the standard multi-column 0/1 detail pattern, all three export modes are tested, and the row-cache key alignment between get_value_names() and format() is consistent.

All three multiple_select modes are covered by explicit test assertions. The previously raised concerns about unknown UUIDs creating spurious row-cache keys, list objects written to the summary cell, and raw UUIDs leaking into the summary are each handled correctly in the new implementation. No new edge-case gaps were found.

No files require special attention.

Reviews (9): Last reviewed commit: "add comment to the format function" | Re-trigger Greptile

Comment thread src/formpack/schema/fields.py Outdated
Comment thread src/formpack/schema/fields.py
Comment thread src/formpack/schema/fields.py
@noliveleger

Copy link
Copy Markdown
Contributor

@greptileai review

Comment thread src/formpack/schema/fields.py Outdated
@Guitlle

Guitlle commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai
Silently dropping stale UUIDs is acceptable for this case. Data from KPI can contain deleted choices so it will be very rare to find a dataset that contains stale UUIDs.

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown

Looking at the actual code in the diff, the implementation already handles this correctly — unrecognized UUIDs are silently dropped because res.append(label) only executes inside the if choice['uuid'] == v: branch, and the loop simply moves on when no match is found. My P1 comment was incorrect; there's no raw UUID leaking into the output.

You're right, and the behavior is both correct and intentional given that KPI data can include choices deleted after collection. The silent drop is the right call here.

Shall I remember this as a rule: "In formpack, silently dropping unrecognized/stale UUIDs from qualitative field responses is acceptable and intentional — KPI data may reference deleted choices"?

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@noliveleger noliveleger left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Guitlle
Guitlle merged commit 7e92685 into main Jun 11, 2026
3 checks passed
Guitlle added a commit to kobotoolbox/kpi that referenced this pull request Jun 11, 2026
### 📣 Summary
Fixes the qualitative manual multiple select data export

### 📖 Description
The one hot data export for manual qualitative multiple select data was
[fixed on formpack](kobotoolbox/formpack#347).
In `import_export_task.py`, the
`SubmissionExportTaskBase.get_export_object` we pass for_output=True
down to `get_submissions` in order to resolve the choice UUIDs into
their corresponding human-readable labels. We have also added `_uuid`
and `meta/rootUuid` to the additional_fields list in
`_get_fields_and_groups()` to retrieve the qualitative payload
correctly.

### 👀 Preview steps
1. Create a project with an active qualSelectMultiple question and
ensure there are submissions with multiple tags/options selected (You
can achieve this by having an audio question, then clicking on "Open",
in the Data view, in the audio cell, and then in the "Analysis" tab you
can add a multiple choice question and select a few options)
3. Go to the project's Data > Downloads
4. Select an export format (e.g., XLS) and check the "Single and
separate columns" advanced option
5. Generate and download the export
6. Open the export file and verify that the Qual multiple-choice field
has successfully expanded into multiple binary columns, and that the
single column version displays the selected labels separated by spaces
instead of commas
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants