Skip to content

Commit 425fc12

Browse files
authored
Merge pull request #845 from simonLeary42/literal-eval-syntax-error
catch SyntaxError from literal_eval
2 parents 8a138c3 + 309e582 commit 425fc12

File tree

2 files changed

+71
-12
lines changed

2 files changed

+71
-12
lines changed

coldfront/core/allocation/models.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -478,18 +478,24 @@ def clean(self):
478478

479479
expected_value_type = self.allocation_attribute_type.attribute_type.name.strip()
480480

481-
if expected_value_type == "Int" and not isinstance(literal_eval(self.value), int):
482-
raise ValidationError(
483-
'Invalid Value "%s" for "%s". Value must be an integer.'
484-
% (self.value, self.allocation_attribute_type.name)
485-
)
486-
elif expected_value_type == "Float" and not (
487-
isinstance(literal_eval(self.value), float) or isinstance(literal_eval(self.value), int)
488-
):
489-
raise ValidationError(
490-
'Invalid Value "%s" for "%s". Value must be a float.'
491-
% (self.value, self.allocation_attribute_type.name)
492-
)
481+
if expected_value_type == "Int":
482+
try:
483+
if not isinstance(literal_eval(self.value), int):
484+
raise TypeError
485+
except (ValueError, TypeError, SyntaxError, MemoryError, RecursionError) as e:
486+
raise ValidationError(
487+
'Invalid Value "%s" for "%s". Value must be an integer.'
488+
% (self.value, self.allocation_attribute_type.name)
489+
) from e
490+
elif expected_value_type == "Float":
491+
try:
492+
if not (isinstance(literal_eval(self.value), int) or isinstance(literal_eval(self.value), float)):
493+
raise TypeError
494+
except (ValueError, TypeError, SyntaxError, MemoryError, RecursionError) as e:
495+
raise ValidationError(
496+
'Invalid Value "%s" for "%s". Value must be a float.'
497+
% (self.value, self.allocation_attribute_type.name)
498+
) from e
493499
elif expected_value_type == "Yes/No" and self.value not in ["Yes", "No"]:
494500
raise ValidationError(
495501
'Invalid Value "%s" for "%s". Allowed inputs are "Yes" or "No".'

coldfront/core/allocation/tests/test_models.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""Unit tests for the allocation models"""
66

77
import datetime
8+
import sys
89
from unittest.mock import patch
910

1011
from django.contrib.auth.models import User
@@ -18,6 +19,9 @@
1819
)
1920
from coldfront.core.project.models import Project
2021
from coldfront.core.test_helpers.factories import (
22+
AAttributeTypeFactory,
23+
AllocationAttributeFactory,
24+
AllocationAttributeTypeFactory,
2125
AllocationFactory,
2226
AllocationStatusChoiceFactory,
2327
ProjectFactory,
@@ -145,6 +149,55 @@ def test_status_is_active_and_start_date_equals_end_date_no_error(self):
145149
actual_allocation.full_clean()
146150

147151

152+
class AllocationAttributeModelCleanMethodTests(TestCase):
153+
def _test_clean(
154+
self, allocation_attribute_type_name: str, allocation_attribute_values: list, expect_validation_error: bool
155+
):
156+
attribute_type = AAttributeTypeFactory(name=allocation_attribute_type_name)
157+
allocation_attribute_type = AllocationAttributeTypeFactory(attribute_type=attribute_type)
158+
allocation_attribute = AllocationAttributeFactory(allocation_attribute_type=allocation_attribute_type)
159+
for value in allocation_attribute_values:
160+
with self.subTest(value=value):
161+
if not isinstance(value, str):
162+
raise TypeError("allocation attribute value must be a string")
163+
allocation_attribute.value = value
164+
if expect_validation_error:
165+
with self.assertRaises(ValidationError):
166+
allocation_attribute.clean()
167+
else:
168+
allocation_attribute.clean()
169+
170+
def test_expect_int_given_int(self):
171+
self._test_clean("Int", ["-1", "0", "1", str(sys.maxsize)], False)
172+
173+
def test_expect_int_given_float(self):
174+
self._test_clean("Int", ["-1.0", "0.0", "1.0", "2e30"], True)
175+
176+
def test_expect_int_given_garbage(self):
177+
self._test_clean("Int", ["foobar", "", " ", "\0", "1j"], True)
178+
179+
def test_expect_float_given_int(self):
180+
self._test_clean("Float", ["-1", "0", "1", str(sys.maxsize)], False)
181+
182+
def test_expect_float_given_float(self):
183+
self._test_clean("Float", ["-1.0", "0.0", "1.0", "2e30"], False)
184+
185+
def test_expect_float_given_garbage(self):
186+
self._test_clean("Float", ["foobar", "", " ", "\0", "1j"], True)
187+
188+
def test_expect_yes_no_given_yes_no(self):
189+
self._test_clean("Yes/No", ["Yes", "No"], False)
190+
191+
def test_expect_yes_no_given_garbage(self):
192+
self._test_clean("Yes/No", ["foobar", "", " ", "\0", "1", "1.0", "2e30", "1j", "yes", "no", "YES", "NO"], True)
193+
194+
def test_expect_date_given_date(self):
195+
self._test_clean("Date", ["1970-01-01"], False)
196+
197+
def test_expect_date_given_garbage(self):
198+
self._test_clean("Date", ["foobar", "", " ", "\0", "1", "1.0", "2e30", "1j"], True)
199+
200+
148201
class AllocationModelStrTests(TestCase):
149202
"""Tests for Allocation.__str__"""
150203

0 commit comments

Comments
 (0)