Skip to content

Commit

Permalink
clean up some TimestampField validation
Browse files Browse the repository at this point in the history
  • Loading branch information
uraniumanchor committed Dec 4, 2023
1 parent 510231a commit 3371ed6
Showing 1 changed file with 17 additions and 9 deletions.
26 changes: 17 additions & 9 deletions tracker/models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
# http://stackoverflow.com/questions/3955093/django-return-none-from-onetoonefield-if-related-object-doesnt-exist


timestamp_regex = re.compile(r'(?:(?:(\d{1,3}):)?(\d{1,3}):)?(\d{1,3})(?:\.(\d{1,3}))?')


class SingleRelatedObjectDescriptorReturnsNone(
models.fields.related.ReverseOneToOneDescriptor
):
Expand All @@ -32,11 +35,11 @@ class OneToOneOrNoneField(models.OneToOneField):


class TimestampValidator(validators.RegexValidator):
regex = r'(?:(?:(\d+):)?(?:(\d+):))?(\d+)(?:\.(\d{1,3}))?$'
regex = timestamp_regex

def __call__(self, value):
super(TimestampValidator, self).__call__(value)
h, m, s, ms = re.match(self.regex, str(value)).groups()
h, m, s, ms = timestamp_regex.match(str(value)).groups()
if h is not None and int(m) >= 60:
raise ValidationError(
'Minutes cannot be 60 or higher if the hour part is specified'
Expand All @@ -47,12 +50,13 @@ def __call__(self, value):
)


# TODO: give this a proper unit test and maybe pull it into its own library? or maybe just find an already existing duration field that does what we want
# TODO: give this a proper unit test and maybe pull it into its own library? or maybe just find an already
# existing duration field that does what we want


class TimestampField(models.Field):
default_validators = [TimestampValidator()]
match_string = re.compile(r'(?:(?:(\d+):)?(?:(\d+):))?(\d+)(?:\.(\d{1,3}))?')
match_string = timestamp_regex

def __init__(
self,
Expand Down Expand Up @@ -103,10 +107,14 @@ def to_python(self, value):
@staticmethod
def time_string_to_int(value: Union[int, float, datetime.timedelta, str]):
if isinstance(value, datetime.timedelta):
assert value.total_seconds() >= 0, f'Value was negative: {value}'
if value.total_seconds() < 0:
raise ValueError(
f'Value was negative: timedelta(seconds={value.total_seconds()})'
)
return int(value.total_seconds() * 1000)
if isinstance(value, (int, float)):
assert value >= 0, f'Value was negative: {value}'
if value < 0:
raise ValueError(f'Value was negative: {value}')
return int(value)
if not isinstance(value, str):
raise TypeError(
Expand All @@ -116,7 +124,7 @@ def time_string_to_int(value: Union[int, float, datetime.timedelta, str]):
return 0
match = TimestampField.match_string.match(value)
if not match:
raise ValueError('Not a valid timestamp: ' + value)
raise ValueError(f'Not a valid timestamp: {value}')
h, m, s, ms = match.groups()
s = int(s)
m = int(m or s / 60)
Expand All @@ -143,5 +151,5 @@ def validate(self, value, model_instance):
super(TimestampField, self).validate(value, model_instance)
try:
TimestampField.time_string_to_int(value)
except ValueError:
raise ValidationError('Not a valid timestamp')
except ValueError as e:
raise ValidationError(str(e))

0 comments on commit 3371ed6

Please sign in to comment.