Skip to content
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

Fix GeoJSON choice labels #271

Merged
merged 8 commits into from Apr 12, 2022
41 changes: 15 additions & 26 deletions src/formpack/reporting/export.py
Expand Up @@ -635,6 +635,11 @@ def to_geojson(
}
"""

# Force to text otherwise might fail JSON serializing
self.xls_types_as_text = True
# Format as summary for multiple select question types
self.multiple_select = 'summary'

# Consider the first section only (discard repeating groups)
first_section_name = get_first_occurrence(self.sections.keys())
labels = self.labels[first_section_name]
Expand Down Expand Up @@ -684,6 +689,10 @@ def to_geojson(
]
all_geo_field_names = [f.name for f in all_geo_fields]

all_geo_field_labels = []
for field in all_geo_fields:
all_geo_field_labels += field.get_labels(lang=self.lang)

# Iterate through all geo questions and format only those that have
# been answered
first_geo = True
Expand Down Expand Up @@ -719,37 +728,17 @@ def to_geojson(

feature_properties = OrderedDict()
for name, label, row_value in zip(sections, labels, row):
# Grab the `Field` object since it holds precious info
# that we need to format the response correctly
filtered_fields = [
f for f in all_fields if f.name == name
]
if not filtered_fields:
continue
field = filtered_fields[0]

# Skip all geo fields, including the current one, as
# it's unnecessary to repeat in the Feature's
# properties. Also skip over fields that are blank
if label in all_geo_field_names or not row_value:
if (
label in all_geo_field_names
or label in all_geo_field_labels
or not row_value
):
continue

# Grab the translated label for choice questions if it's
# available.
if hasattr(field, 'choice'):
value_or_none = field.choice.options[row_value][
'labels'
].get(self.lang)
if value_or_none is None:
value = list(
field.choice.options[row_value][
'labels'
].values()
)[0]
else:
value = row_value

feature_properties.update({label: value})
feature_properties.update({label: row_value})

feature = {
'type': 'Feature',
Expand Down
15 changes: 15 additions & 0 deletions tests/fixtures/geojson_and_selects/__init__.py
@@ -0,0 +1,15 @@
# coding: utf-8

"""
geojson_and_selects
"""

from ..load_fixture_json import load_fixture_json

DATA = {
'title': 'Geo and selects',
'id_string': 'geojson_and_selects',
'versions': [
load_fixture_json('geojson_and_selects/v1'),
],
}
61 changes: 61 additions & 0 deletions tests/fixtures/geojson_and_selects/v1.json
@@ -0,0 +1,61 @@
{
"version": "v1",
"content": {
"survey": [
{
"type": "select_one locations",
"name": "current_location",
"label": [
"Where are you?"
]
joshuaberetta marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +8 to +10
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 I do not see the benefit of moving this on 3 lines instead of one since a fixture and chances are pretty small we need to add another some line to the list. We may want to create a v2 instead.

},
{
"type": "geopoint",
"name": "geo_location",
"label": [
"Point out where you are"
]
},
{
"type": "image",
"name": "an_image",
"label": [
"Take a photo of the location"
]
}
],
"choices": [
{
"list_name": "locations",
"name": "outside",
"label": [
"Outside"
]
},
{
"list_name": "locations",
"name": "inside",
"label": [
"Inside"
]
}
]
},
"submissions": [
{
"current_location": "inside",
"geo_location": "39.306938 -76.60869 11 22",
"an_image": "location.jpeg",
"_geolocation": [
39.306938,
-76.60869
],
"_attachments": [
{
"download_url": "https://kc.kobo.org/media/original?media_file=/path/to/location.jpeg",
"filename": "/path/to/location.jpeg"
}
]
}
]
}
78 changes: 77 additions & 1 deletion tests/test_exports.py
Expand Up @@ -372,7 +372,9 @@ def test_submissions_of_group_exports(self):
)

def test_translations_labels_mismatch(self):
title, schemas, submissions = build_fixture('translations_labels_mismatch')
title, schemas, submissions = build_fixture(
'translations_labels_mismatch'
)
with self.assertRaises(TranslationError) as e:
fp = FormPack(schemas, title)

Expand Down Expand Up @@ -2816,6 +2818,80 @@ def test_select_multiple_with_different_options_in_multiple_versions(self):
['american british', '0', '0', '1', '1', 'Keurig'],
)

def test_geojson_with_select_xml_label(self):
title, schemas, submissions = build_fixture('geojson_and_selects')
fp = FormPack(schemas, title)

options = {'versions': 'v1', 'lang': '_xml', 'include_media_url': True}
export = fp.export(**options)
geojson_gen = export.to_geojson(
submissions, geo_question_name='geo_location'
)
geojson_str = ''.join(geojson_gen)
geojson_obj = json.loads(geojson_str)

assert geojson_obj == {
'type': 'FeatureCollection',
'name': 'Geo and selects',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [
-76.60869,
39.306938,
11.0,
],
},
'properties': {
'an_image': 'location.jpeg',
'an_image_URL': 'https://kc.kobo.org/media/original?media_file=/path/to/location.jpeg',
'current_location': 'inside',
},
},
],
}

def test_geojson_with_select_label(self):
title, schemas, submissions = build_fixture('geojson_and_selects')
fp = FormPack(schemas, title)

options = {
'versions': 'v1',
'lang': UNTRANSLATED,
'include_media_url': True,
}
export = fp.export(**options)
geojson_gen = export.to_geojson(
submissions, geo_question_name='geo_location'
)
geojson_str = ''.join(geojson_gen)
geojson_obj = json.loads(geojson_str)

assert geojson_obj == {
'type': 'FeatureCollection',
'name': 'Geo and selects',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [
-76.60869,
39.306938,
11.0,
],
},
'properties': {
'Take a photo of the location': 'location.jpeg',
'Take a photo of the location_URL': 'https://kc.kobo.org/media/original?media_file=/path/to/location.jpeg',
'Where are you?': 'Inside',
},
},
],
}

def test_geojson_point(self):
title, schemas, submissions = build_fixture('all_geo_types')
fp = FormPack(schemas, title)
Expand Down
17 changes: 7 additions & 10 deletions tests/test_utils_flatten_content.py
Expand Up @@ -495,16 +495,13 @@ def test_flatten_tags():


def test_col_order():
assert (
_order_cols(
[
'label',
'type',
'name',
]
)
== ['type', 'name', 'label']
)
assert _order_cols(
[
'label',
'type',
'name',
]
) == ['type', 'name', 'label']


def test_flatten_translated_label_with_xpath():
Expand Down