-
Notifications
You must be signed in to change notification settings - Fork 19
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
Follow up questions #381
Follow up questions #381
Conversation
README.md
Outdated
@@ -71,8 +71,7 @@ Question keys | |||
* `dynamic_field` defines the field in the filter context that will be used to generate dynamic list questions (eg when passing | |||
a brief as filter context setting `dynamic_field` to `brief.niceToHaveRequirements` will generate questions for nice-to-have | |||
requirements) (only valid for `dynamic_list` questions) | |||
* `followup` sets the name of the question that will be required/shown if the current question is answered with "Yes" (only valid | |||
for `boolean` questions) | |||
* `followup` is a dictionary where each key is the name of the question that will be required/shown and the value for the key is a list of question answers that should display the follow up (only valid for `boolean` and `radios` questions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Followups are required for checkboxes, too.
schema_generator/utils.py
Outdated
@@ -0,0 +1,16 @@ | |||
def merge_schemas(a, b): | |||
if not (isinstance(a, dict) and isinstance(b, dict)): | |||
raise ValueError("Error merging '{}' and '{}'".format( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a TypeError, and the error message could probably be more descriptive: "Unable to merge disparate types: '{}' and '{}'."
1bdb2bb
to
8863942
Compare
@samuelhwilliams added support for checkbox question with follow-ups and optional follow-up questions. The tests need a new content-loader version to get merged, which I'm adding the checkbox support to now. |
a676cdc
to
292f9d9
Compare
Probably need to add some tests around the followup schema generation. |
Adds helper methods to generate schema for flat (storing all properties in a top-level object) and nested (storing properties in a nested object) multiquestions. Adds support for 'radios' question type to the followup schema generation, and refactors it to use a `merge_schemas` helper to make it easier to join multiple follow-up schemas. Schema generation was using an older version of content-loader, which didn't have DynamicList question class. Since DynamicList constructor switches question type to 'multiquestion' when updating content-loader we need to add additional dispatch logic to `multiquestion` so it can call `dynamic_list` generator for `DynamicList` questions.
Getting a list of required fields for multiquestions is complicated by the addition of followups and the fact that dynamic list / nested multiquestions have to deal with two required fields lists: one for the main schema and one for the nested object schema. Allowing property schema functions to return an optional list of required fields allows us to move that logic closer to the followup subschema generation without having to make any changes to the `.form_field` methods on the question classes, that could potentially affect other parts of the application code.
Always listing lead-in question as required in a subschema makes the validation fail when used with `enforce_required=False` in the API. This wasn't a problem for brief responses, since both the lead-in and the followup questions are nested inside one key, which is missing in unrelated updates. But when storing them as separate top-level key we need to be able to unset the required fields using the schema required list. So instead of listing the lead-in question as required in the subschemas we add it to the main schema required list.
Allows property schema generators to return a schema addition to be merged with the main schema. This enables multiquestions to add allOf/oneOff subschemas for followup questions and modify the required list on the main schema. Changes the existing specialists anyOf/dependency additions to use merge_schemas.
Dynamic lists are serialized as an array, but other multiquestions aren't, so it makes sense to move the array part of the schema to the `_dynamic_list` function. And since we can no longer dispatch to the dynamic_list property based on the question type we need to remove it from the types mapping.
Fixes the schema accepting an answer for the follow up when the lead in question wasn't answered. Since the subschema without the follow-up doesn't list the lead-in question in required list we can still use page_questions without failing the oneOf.
Since checkboxes are answered with a list of strings some of which can have a followup we need a way to check that the question answer list contains a given value. There's no direct way to do this using JSON schema, but we can check whether the list of answers contains only the values that don't have a follow-up. So using that and the inverse of that schema we can separate answers that only have no-followup values and answers that contain something else, which we assume IS the follow-up value we wanted to check for (it could be some other invalid value, in which case the schema will still require an answer for the followup but the parent property schema will also flag the value as invalid).
This requires us to use `.get_question` on the multiquestion, but has a nice side-effect of validating that follow-up question IDs are correct and belong to the same multiquestion as the lead-in.
292f9d9
to
8d77435
Compare
@samuelhwilliams fair point, I've added a few tests |
Other than that, from local testing and reading through, looks good. 👍 |
Split multiquestion schema generation
Adds helper methods to generate schema for flat (storing all properties
in a top-level object) and nested (storing properties in a nested object)
multiquestions.
Adds support for 'radios' question type to the followup schema
generation, and refactors it to use a
merge_schemas
helper tomake it easier to join multiple follow-up schemas.
Schema generation was using an older version of content-loader, which
didn't have DynamicList question class. Since DynamicList constructor
switches question type to 'multiquestion' when updating content-loader
we need to add additional dispatch logic to
multiquestion
so it cancall
dynamic_list
generator forDynamicList
questions.Don't add lead question to the oneOf subschema required
Always listing lead-in question as required in a subschema makes the
validation fail when used with
enforce_required=False
in the API.This wasn't a problem for brief responses, since both the lead-in and
the followup questions are nested inside one key, which is missing in
unrelated updates. But when storing them as separate top-level key we
need to be able to unset the required fields using the schema required
list.
So instead of listing the lead-in question as required in the subschemas
we add it to the main schema required list.
Let multiquestions extend main schema fields
Allows property schema generators to return a schema addition to be
merged with the main schema. This enables multiquestions to add
allOf/oneOff subschemas for followup questions and modify the
required list on the main schema.
Changes the existing specialists anyOf/dependency additions to use
merge_schemas.
Splits dynamic_list from nestd_multiquestion output
Dynamic lists are serialized as an array, but other multiquestions
aren't, so it makes sense to move the array part of the schema to
the
_dynamic_list
function.And since we can no longer dispatch to the dynamic_list property
based on the question type we need to remove it from the types
mapping.