diff --git a/edtf/parser/grammar.py b/edtf/parser/grammar.py index 0624a92..7f392eb 100644 --- a/edtf/parser/grammar.py +++ b/edtf/parser/grammar.py @@ -284,8 +284,10 @@ def f(toks): # (* ** Inclusive list and choice list** *) consecutives = ( - (yearMonthDay("lower") + ".." + yearMonthDay("upper")) - ^ (yearMonth("lower") + ".." + yearMonth("upper")) + # Combine so each bound reaches Consecutives as one string, e.g. "1912-03", + # rather than as the list of its parts. + (Combine(yearMonthDay)("lower") + ".." + Combine(yearMonthDay)("upper")) + ^ (Combine(yearMonth)("lower") + ".." + Combine(yearMonth)("upper")) ^ ( year_basic("lower") + ".." + year_basic("upper") ) # using year_basic because some tests were throwing `'list' object has no attribute 'expandtabs'` - somewhere, pyparsing.parse_string() was being passed a list diff --git a/edtf/parser/parser_classes.py b/edtf/parser/parser_classes.py index 67dd8ee..c519413 100644 --- a/edtf/parser/parser_classes.py +++ b/edtf/parser/parser_classes.py @@ -7,6 +7,7 @@ from typing import Optional from dateutil.relativedelta import relativedelta +from pyparsing import ParseResults from edtf import appsettings from edtf.convert import ( @@ -1021,6 +1022,17 @@ class PartialUnspecified(Unspecified): class Consecutives(Interval): # Treating Consecutive ranges as intervals where one bound is optional + @classmethod + def parse_action(cls, toks): + # Only the two bounds, each as its string. A month or day bound keeps + # the results names of its parts (year, month, day), so it arrives as + # a ParseResults holding the combined string, and those names are not + # arguments of __init__ (#79). + def bound(value): + return value[0] if isinstance(value, ParseResults) else value + + return cls(lower=bound(toks.get("lower")), upper=bound(toks.get("upper"))) + def __init__(self, lower=None, upper=None): # noqa if lower and not isinstance(lower, EDTFObject): self.lower = Date.parse(lower) diff --git a/tests/test_parser.py b/tests/test_parser.py index 8b3c1d9..7d12818 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -179,11 +179,19 @@ ("[1760-01, 1760-02, 1760-12..]", ("1760-01-01", "inf")), # Either the year 1667 or the month December of 1760. ("[1667, 1760-12]", ("1667-01-01", "1760-12-31")), + # November or December 1774 (consecutive months, #79) + ("[1774-11..1774-12]", ("1774-11-01", "1774-12-31")), + # One of the days from 30 July to 6 August 1785 (consecutive days, #79) + ("[1785-07-30..1785-08-06]", ("1785-07-30", "1785-08-06")), + # The year 1667 or one of the months March to May 1912 + ("[1667, 1912-03..1912-05]", ("1667-01-01", "1912-05-31")), # Multiple Dates # All of the years 1667, 1668, 1670, 1671, 1672 ("{1667,1668, 1670..1672}", ("1667-01-01", "1672-12-31")), # The year 1960 and the month December of 1961. ("{1960, 1961-12}", ("1960-01-01", "1961-12-31")), + # All of the months March to May 1912 (consecutive months, #79) + ("{1912-03..1912-05}", ("1912-03-01", "1912-05-31")), # Previously tested masked precision, now eliminated from the spec # A date during the 1960s ("196X", ("1960-01-01", "1969-12-31")),