Skip to content

Commit d779dea

Browse files
authored
Merge pull request #59 from artshumrc/30_improve_exceptions
Improve exceptions
2 parents 8c571b0 + daf0d04 commit d779dea

7 files changed

Lines changed: 96 additions & 15 deletions

File tree

edtf/appsettings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,5 @@
9898
MULTIPLIER_IF_APPROXIMATE = EDTF.get("MULTIPLIER_IF_APPROXIMATE", 1.0)
9999
MULTIPLIER_IF_BOTH = EDTF.get("MULTIPLIER_IF_BOTH", 2.0)
100100
DELTA_IF_UNKNOWN = EDTF.get("DELTA_IF_UNKNOWN", relativedelta(years=10))
101+
102+
DEBUG_PYPARSING = False

edtf/fields.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
from django.db import models
55
from django.db.models import signals
66
from django.db.models.query_utils import DeferredAttribute
7+
from pyparsing import ParseException
78

89
from edtf import EDTFObject, parse_edtf
910
from edtf.convert import struct_time_to_date, struct_time_to_jd
1011
from edtf.natlang import text_to_edtf
12+
from edtf.parser.edtf_exceptions import EDTFParseException
1113

1214
DATE_ATTRS = (
1315
"lower_strict",
@@ -132,10 +134,12 @@ def update_values(self, instance, *args, **kwargs):
132134
if direct_input and (
133135
existing_value is None or str(existing_value) != direct_input
134136
):
135-
edtf = parse_edtf(
136-
direct_input, fail_silently=True
137-
) # ParseException if invalid; should this be raised?
138-
# TODO pyparsing.ParseExceptions are very noisy and dumps the whole grammar (see https://github.com/ixc/python-edtf/issues/46)
137+
try:
138+
edtf = parse_edtf(
139+
direct_input, fail_silently=True
140+
) # ParseException if invalid; should this be raised?
141+
except ParseException as err:
142+
raise EDTFParseException(direct_input, err) from None
139143

140144
# set the natural_text (display) field to the direct_input if it is not provided
141145
if natural_text == "":

edtf/parser/edtf_exceptions.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,28 @@
22

33

44
class EDTFParseException(ParseException):
5-
pass
5+
"""Raised when an input cannot be parsed as an EDTF string.
6+
7+
Attributes:
8+
input_string - the input string that could not be parsed
9+
err -- the original ParseException that caused this one
10+
"""
11+
12+
def __init__(self, input_string, err=None):
13+
if input_string is None:
14+
input_string = ""
15+
self.input_string = input_string
16+
if err is None:
17+
err = ParseException(input_string, 0, "Invalid input or format.")
18+
self.err = err
19+
super().__init__(str(err), err.loc if err.loc else 0, self.input_string)
20+
21+
def __str__(self):
22+
if not self.input_string:
23+
return "You must supply some input text"
24+
near_text = (
25+
self.input_string[max(self.err.loc - 10, 0) : self.err.loc + 10]
26+
if hasattr(self.err, "loc")
27+
else ""
28+
)
29+
return f"Error at position {self.err.loc}: Invalid input or format near '{near_text}'. Please provide a valid EDTF string."

edtf/parser/grammar.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# https://github.com/pyparsing/pyparsing/wiki/Performance-Tips
55

66
import pyparsing
7+
from edtf.appsettings import DEBUG_PYPARSING
78

89
pyparsing.ParserElement.enablePackrat()
910

@@ -342,14 +343,18 @@ def f(toks):
342343
)
343344

344345

345-
def parse_edtf(str, parseAll=True, fail_silently=False):
346+
def parse_edtf(input_string, parseAll=True, fail_silently=False, debug=None):
347+
if debug is None:
348+
debug = DEBUG_PYPARSING
349+
if not input_string:
350+
raise EDTFParseException(input_string)
346351
try:
347-
if not str:
348-
raise ParseException("You must supply some input text")
349-
p = edtfParser.parseString(str.strip(), parseAll)
352+
p = edtfParser.parseString(input_string.strip(), parseAll)
350353
if p:
351354
return p[0]
352355
except ParseException as err:
353356
if fail_silently:
354357
return None
355-
raise EDTFParseException(err) from err
358+
if debug:
359+
raise
360+
raise EDTFParseException(input_string, err) from None

edtf/parser/tests.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,14 @@ def test_non_parsing(bad_input):
347347
parse(bad_input)
348348

349349

350+
@pytest.mark.parametrize("bad_input", [None, ""])
351+
def test_empty_input(bad_input):
352+
"""Test that empty input raises a specific exception."""
353+
with pytest.raises(EDTFParseException) as exc_info:
354+
parse(bad_input)
355+
assert "You must supply some input text" in str(exc_info.value)
356+
357+
350358
def test_comparisons():
351359
"""Test comparisons between parsed EDTF objects and standard dates."""
352360
d1 = parse("1979-08~")
Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,43 @@
1-
# Register your models here.
1+
from django.contrib import admin
2+
3+
from .models import TestEvent
4+
5+
6+
class TestEventAdmin(admin.ModelAdmin):
7+
list_display = (
8+
"date_display",
9+
"date_edtf_direct",
10+
"date_earliest",
11+
"date_latest",
12+
"date_sort_ascending",
13+
"date_sort_descending",
14+
"date_edtf",
15+
)
16+
search_fields = ("date_display", "date_edtf_direct")
17+
list_filter = ("date_earliest", "date_latest")
18+
readonly_fields = (
19+
"date_earliest",
20+
"date_latest",
21+
"date_sort_ascending",
22+
"date_sort_descending",
23+
"date_edtf",
24+
)
25+
26+
fieldsets = (
27+
(None, {"fields": ("date_display", "date_edtf_direct", "date_edtf")}),
28+
(
29+
"Computed Dates",
30+
{
31+
"classes": ("collapse",),
32+
"fields": (
33+
"date_earliest",
34+
"date_latest",
35+
"date_sort_ascending",
36+
"date_sort_descending",
37+
),
38+
},
39+
),
40+
)
41+
42+
43+
admin.site.register(TestEvent, TestEventAdmin)

edtf_django_tests/edtf_integration/models.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,5 @@ def __str__(self) -> str:
4949
return (
5050
f"Test Event: {self.date_display=}, "
5151
f"{self.date_edtf_direct=}, "
52-
f"{self.date_earliest=}, "
53-
f"{self.date_latest=}, "
54-
f"{self.date_sort_ascending=}, "
55-
f"{self.date_sort_descending=}, "
5652
f"{self.date_edtf=}"
5753
)

0 commit comments

Comments
 (0)