From e14ebdc53a9cf32b13824e9125fda492f9e08184 Mon Sep 17 00:00:00 2001 From: RuthShryock Date: Tue, 23 Jul 2024 16:30:37 -0400 Subject: [PATCH 1/4] check if the value is a dictionary to avoid type errors with duplicate submissions --- kobo/apps/subsequences/utils/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kobo/apps/subsequences/utils/__init__.py b/kobo/apps/subsequences/utils/__init__.py index 7703fc1905..ec56798435 100644 --- a/kobo/apps/subsequences/utils/__init__.py +++ b/kobo/apps/subsequences/utils/__init__.py @@ -176,6 +176,8 @@ def stream_with_extras(submission_stream, asset): val = [val] val_expanded = [] for v in val: + if isinstance(v, dict): + v = v['uuid'] try: v_ex = qual_choices_per_question_by_uuid[ qual_q['uuid'] From 38b2a6470011ce1e28e7a931fffa2fb901977a26 Mon Sep 17 00:00:00 2001 From: RuthShryock Date: Thu, 25 Jul 2024 15:55:12 -0400 Subject: [PATCH 2/4] add test for duplicated submission uuids --- .../tests/test_submission_stream.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/kobo/apps/subsequences/tests/test_submission_stream.py b/kobo/apps/subsequences/tests/test_submission_stream.py index 689ece4c0f..1becdb3751 100644 --- a/kobo/apps/subsequences/tests/test_submission_stream.py +++ b/kobo/apps/subsequences/tests/test_submission_stream.py @@ -241,3 +241,38 @@ def mock_submission_stream(): assert '_supplementalDetails' in output[0] assert '_supplementalDetails' in output[1] # test other things? + + def test_stream_with_extras_handles_duplicated_submission_uuids(self): + # Define submission data with duplicated UUIDs + submissions = [ + { + 'What_s_your_name': 'Ed', + 'Tell_me_a_story': 'ed-18_6_24.ogg', + 'meta/instanceID': 'uuid:1c05898e-b43c-491d-814c-79595eb84e81', + '_uuid': '1c05898e-b43c-491d-814c-79595eb84e81', + }, + { + 'What_s_your_name': 'Ed', + 'Tell_me_a_story': 'ed-18_6_44.ogg', + 'meta/instanceID': 'uuid:1c05898e-b43c-491d-814c-79595eb84e81', + '_uuid': '1c05898e-b43c-491d-814c-79595eb84e81', + }, + ] + self.asset.deployment.mock_submissions(submissions) + + # Process submissions with extras + try: + output = list( + stream_with_extras( + self.asset.deployment.get_submissions( + user=self.asset.owner + ), + self.asset, + ) + ) + except TypeError as e: + self.fail(f"TypeError occurred: {e}") + self.assertTrue(True) + + # Clear all mocked submissions to avoid duplicate submission errors + self.asset.deployment.mock_submissions([]) From d6e5e98aa5dd9b3fe2bb2ecc038638ba61bd09a9 Mon Sep 17 00:00:00 2001 From: RuthShryock Date: Fri, 26 Jul 2024 14:05:10 -0400 Subject: [PATCH 3/4] revise fix for duplicate submission uuids to instead use deepcopy so that uuids are not directly mutated --- kobo/apps/subsequences/tests/test_submission_stream.py | 2 +- kobo/apps/subsequences/utils/__init__.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/kobo/apps/subsequences/tests/test_submission_stream.py b/kobo/apps/subsequences/tests/test_submission_stream.py index 1becdb3751..a31021506b 100644 --- a/kobo/apps/subsequences/tests/test_submission_stream.py +++ b/kobo/apps/subsequences/tests/test_submission_stream.py @@ -262,7 +262,7 @@ def test_stream_with_extras_handles_duplicated_submission_uuids(self): # Process submissions with extras try: - output = list( + _ = list( stream_with_extras( self.asset.deployment.get_submissions( user=self.asset.owner diff --git a/kobo/apps/subsequences/utils/__init__.py b/kobo/apps/subsequences/utils/__init__.py index ec56798435..bddf773004 100644 --- a/kobo/apps/subsequences/utils/__init__.py +++ b/kobo/apps/subsequences/utils/__init__.py @@ -150,7 +150,7 @@ def stream_with_extras(submission_stream, asset): uuid = submission[SUBMISSION_UUID_FIELD] else: uuid = submission['_uuid'] - all_supplemental_details = extras.get(uuid, {}) + all_supplemental_details = deepcopy(extras.get(uuid, {})) for qpath, supplemental_details in all_supplemental_details.items(): try: all_qual_responses = supplemental_details['qual'] @@ -176,8 +176,6 @@ def stream_with_extras(submission_stream, asset): val = [val] val_expanded = [] for v in val: - if isinstance(v, dict): - v = v['uuid'] try: v_ex = qual_choices_per_question_by_uuid[ qual_q['uuid'] From 762fd9e408b7ab4e74ceff68be158ccea4658953 Mon Sep 17 00:00:00 2001 From: RuthShryock Date: Mon, 29 Jul 2024 10:47:03 -0400 Subject: [PATCH 4/4] revising test to check that uuids are string values --- .../tests/test_submission_stream.py | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/kobo/apps/subsequences/tests/test_submission_stream.py b/kobo/apps/subsequences/tests/test_submission_stream.py index a31021506b..4542d603e1 100644 --- a/kobo/apps/subsequences/tests/test_submission_stream.py +++ b/kobo/apps/subsequences/tests/test_submission_stream.py @@ -261,18 +261,27 @@ def test_stream_with_extras_handles_duplicated_submission_uuids(self): self.asset.deployment.mock_submissions(submissions) # Process submissions with extras - try: - _ = list( - stream_with_extras( - self.asset.deployment.get_submissions( - user=self.asset.owner - ), - self.asset, - ) + output = list( + stream_with_extras( + self.asset.deployment.get_submissions(user=self.asset.owner), + self.asset, ) - except TypeError as e: - self.fail(f"TypeError occurred: {e}") - self.assertTrue(True) + ) + + # Make sure that uuid values for single or multiple choice qualitative + # analysis questions are kept as strings and not mutated + for submission in output: + supplemental_details = submission['_supplementalDetails'] + for qual_response in supplemental_details['Tell_me_a_story']['qual']: + if qual_response['type'] not in [ + 'qual_select_one', + 'qual_select_multiple', + ]: + # question is not a single or multiple choice one + continue + + for v in qual_response['val']: + assert isinstance(v['uuid'], str) # Clear all mocked submissions to avoid duplicate submission errors self.asset.deployment.mock_submissions([])