Skip to content

Commit 04c146f

Browse files
authored
bugfixes (#1019)
* specify the quoting for csv exports this fixes an issue where numbers that should be treated as strings are not quoted and strings that contain other characters that could be delimiters are not quoted properly. * added an extra check for registered voters if it is a form field to confirm that the value is not a null value.
1 parent e78ed97 commit 04c146f

File tree

6 files changed

+38
-26
lines changed

6 files changed

+38
-26
lines changed

apollo/locations/services.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def export_list(self, query):
7474

7575
output = StringIO()
7676
output.write(constants.BOM_UTF8_STR)
77-
writer = csv.writer(output)
77+
writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
7878
writer.writerow(headers)
7979
yield output.getvalue()
8080
output.close()
@@ -121,7 +121,7 @@ def export_list(self, query):
121121
record.append(row[index])
122122

123123
output = StringIO()
124-
writer = csv.writer(output)
124+
writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
125125
writer.writerow(record)
126126
yield output.getvalue()
127127
output.close()

apollo/messaging/services.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
class MessageService(Service):
1414
__model__ = Message
1515

16-
def log_message(self, event, direction, text, recipient='', sender='',
17-
timestamp=None, message_type='SMS'):
16+
def log_message(self, event, direction, text, recipient="", sender="", timestamp=None, message_type="SMS"):
1817
if timestamp:
1918
try:
2019
msg_time = datetime.utcfromtimestamp(timestamp)
@@ -24,38 +23,38 @@ def log_message(self, event, direction, text, recipient='', sender='',
2423
msg_time = datetime.utcnow()
2524

2625
return self.create(
27-
direction=direction, recipient=recipient, sender=sender, text=text,
28-
deployment_id=event.deployment_id, event=event, received=msg_time,
29-
message_type=message_type)
26+
direction=direction,
27+
recipient=recipient,
28+
sender=sender,
29+
text=text,
30+
deployment_id=event.deployment_id,
31+
event=event,
32+
received=msg_time,
33+
message_type=message_type,
34+
)
3035

3136
def export_list(self, query):
32-
headers = [
33-
_('Mobile'), _('Text'), _('Direction'), _('Created'),
34-
_('Delivered'), _('Type')
35-
]
37+
headers = [_("Mobile"), _("Text"), _("Direction"), _("Created"), _("Delivered"), _("Type")]
3638
output = StringIO()
3739
output.write(constants.BOM_UTF8_STR)
38-
writer = csv.writer(output)
40+
writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
3941
writer.writerow([str(i) for i in headers])
4042
yield output.getvalue()
4143
output.close()
4244

4345
for message in query:
4446
# limit to three numbers for export and pad if less than three
4547
record = [
46-
message.sender if message.direction == 'IN'
47-
else message.recipient,
48+
message.sender if message.direction == "IN" else message.recipient,
4849
message.text,
4950
message.direction.code,
50-
message.received.strftime('%Y-%m-%d %H:%M:%S')
51-
if message.received else '',
52-
message.delivered.strftime('%Y-%m-%d %H:%M:%S')
53-
if message.delivered else '',
54-
message.message_type.value
51+
message.received.strftime("%Y-%m-%d %H:%M:%S") if message.received else "",
52+
message.delivered.strftime("%Y-%m-%d %H:%M:%S") if message.delivered else "",
53+
message.message_type.value,
5554
]
5655

5756
output = StringIO()
58-
writer = csv.writer(output)
57+
writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
5958
writer.writerow([str(i) for i in record])
6059
yield output.getvalue()
6160
output.close()

apollo/participants/services.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def export_list(self, query):
5353
# TODO: extra fields missing
5454
output_buffer = StringIO()
5555
output_buffer.write(constants.BOM_UTF8_STR)
56-
writer = csv.writer(output_buffer)
56+
writer = csv.writer(output_buffer, quoting=csv.QUOTE_NONNUMERIC)
5757

5858
writer.writerow(headers)
5959
yield output_buffer.getvalue()
@@ -97,7 +97,7 @@ def export_list(self, query):
9797

9898
# TODO: process extra fields here
9999
output_buffer = StringIO()
100-
writer = csv.writer(output_buffer)
100+
writer = csv.writer(output_buffer, quoting=csv.QUOTE_NONNUMERIC)
101101
writer.writerow(record)
102102
yield output_buffer.getvalue()
103103
output_buffer.close()

apollo/result_analysis/results.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def _margin_of_error(dataframe, numerator, denominator, cv=1.96):
6161
return moe
6262

6363

64+
# TODO: use proper field terminology for the variable names in this function (field, field_label, etc.)
6465
def voting_results(form_id, location_id=None):
6566
"""Compute voting results."""
6667
event = g.event
@@ -131,6 +132,7 @@ def voting_results(form_id, location_id=None):
131132

132133
dataset = make_submission_dataframe(filter_set.qs, form, excluded_tags=excluded_fields)
133134

135+
# Check to replace records that have the configured null value with nan
134136
for result_field in result_fields:
135137
null_value_orig = result_field.get("null_value")
136138
if null_value_orig is None:
@@ -142,6 +144,17 @@ def voting_results(form_id, location_id=None):
142144

143145
dataset[result_field["tag"]] = dataset[result_field["tag"]].replace(null_value, np.nan)
144146

147+
# Check to replace records that have the configured null value for registered voters
148+
# (if the column is derived from a reported field) with nan
149+
if form.registered_voters_tag:
150+
try:
151+
_null_value = form.get_field_by_tag(form.registered_voters_tag).get("null_value")
152+
if null_value is not None:
153+
null_value = int(_null_value)
154+
dataset[registered_voters_field] = dataset[registered_voters_field].replace(null_value, np.nan)
155+
except (TypeError, ValueError):
156+
pass
157+
145158
if not dataset.empty:
146159
# compute and store reporting status
147160
dataset["reported"] = (

apollo/submissions/aggregation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def aggregate_dataset(query, form, stream=False):
124124
if stream:
125125
output_stream = StringIO()
126126
output_stream.write(codecs.BOM_UTF8.decode("utf-8"))
127-
writer = csv.writer(output_stream)
127+
writer = csv.writer(output_stream, quoting=csv.QUOTE_NONNUMERIC)
128128
writer.writerow(headers)
129129

130130
yield output_stream.getvalue()
@@ -179,7 +179,7 @@ def aggregate_dataset(query, form, stream=False):
179179

180180
if stream:
181181
output_stream = StringIO()
182-
writer = csv.writer(output_stream)
182+
writer = csv.writer(output_stream, quoting=csv.QUOTE_NONNUMERIC)
183183
writer.writerow(current_row)
184184

185185
yield output_stream.getvalue()

apollo/submissions/services.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def export_list(self, query, include_qa=False, include_group_timestamps=False):
113113

114114
output = StringIO()
115115
output.write(constants.BOM_UTF8_STR)
116-
writer = csv.writer(output)
116+
writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
117117
writer.writerow(dataset_headers)
118118
yield output.getvalue()
119119
output.close()
@@ -215,7 +215,7 @@ def export_list(self, query, include_qa=False, include_group_timestamps=False):
215215
]
216216

217217
output = StringIO()
218-
writer = csv.writer(output)
218+
writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
219219
writer.writerow(record)
220220
yield output.getvalue()
221221
output.close()

0 commit comments

Comments
 (0)