Skip to content
Snippets Groups Projects
Commit a1aba2dd authored by Tulir Asokan's avatar Tulir Asokan
Browse files

Return unconsumed part instead of end index from matcher

Also removed unused regexes
parent 02b3f7d4
No related branches found
No related tags found
No related merge requests found
......@@ -53,12 +53,12 @@ if TYPE_CHECKING:
class MatcherReturn(NamedTuple):
params: 'RelativeDeltaParams'
end: int
unconsumed: str
class Matcher(ABC):
@abstractmethod
def match(self, val: str, start: int = 0) -> Optional[MatcherReturn]:
def match(self, val: str) -> Optional[MatcherReturn]:
pass
......@@ -70,45 +70,44 @@ class RegexMatcher(Matcher):
self.regex = re.compile(pattern, re.IGNORECASE)
self.value_type = value_type
def match(self, val: str, start: int = 0) -> Optional[MatcherReturn]:
match = self.regex.match(val, pos=start)
if match and match.end() > 0:
return self._convert_match(match)
def match(self, val: str) -> Optional[MatcherReturn]:
match = self.regex.match(val)
if match and match.end() > 0 and len(match.groups()) > 0:
return MatcherReturn(params=self._convert_match(match), unconsumed=val[match.end():])
return None
def _convert_match(self, match: Match) -> MatcherReturn:
return MatcherReturn(params=self._convert_groups(match.groupdict()),
end=match.end())
def _convert_match(self, match: Match) -> 'RelativeDeltaParams':
return self._convert_groups(match.groupdict())
def _convert_groups(self, groups: Dict[str, str]) -> 'RelativeDeltaParams':
return {key: self.value_type(value) for key, value in groups.items() if value}
class TimeMatcher(RegexMatcher):
def _convert_match(self, match: Match) -> MatcherReturn:
def _convert_match(self, match: Match) -> 'RelativeDeltaParams':
groups = match.groupdict()
try:
meridiem = groups.pop("meridiem").lower()
except KeyError:
except (KeyError, AttributeError):
meridiem = None
params = self._convert_groups(groups)
if meridiem == "pm":
params["hour"] += 12
elif meridiem == "am" and params["hour"] == 12:
params["hour"] = 0
return MatcherReturn(params=params, end=match.end())
return params
class ShortYearMatcher(RegexMatcher):
def _convert_match(self, match: Match) -> MatcherReturn:
rtrn = super()._convert_match(match)
if rtrn.params["year"] < 100:
def _convert_match(self, match: Match) -> 'RelativeDeltaParams':
params = super()._convert_match(match)
if params["year"] < 100:
year = datetime.now().year
current_century = year // 100
if rtrn.params["year"] < year % 100:
if params["year"] < year % 100:
current_century += 1
rtrn.params["year"] = (current_century * 100) + rtrn.params["year"]
return rtrn
params["year"] = (current_century * 100) + params["year"]
return params
class WeekdayMatcher(Matcher):
......@@ -121,13 +120,13 @@ class WeekdayMatcher(Matcher):
self.map = map
self.substr = substr
def match(self, val: str, start: int = 0) -> Optional[MatcherReturn]:
match = self.regex.match(val, pos=start)
def match(self, val: str) -> Optional[MatcherReturn]:
match = self.regex.match(val)
if match and match.end() > 0:
weekday = self.map[match.string[:self.substr].lower()]
if isinstance(weekday, int):
weekday = (datetime.now().weekday() + weekday) % 7
return MatcherReturn(params={"weekday": weekday}, end=match.end())
return MatcherReturn(params={"weekday": weekday}, unconsumed=val[match.end():])
return None
......@@ -151,26 +150,25 @@ class Locale(Matcher):
return Locale(name=name, timedelta=timedelta or self.timedelta, date=date or self.date,
weekday=weekday or self.weekday, time=time or self.time)
def match(self, val: str, start: int = 0) -> Optional[MatcherReturn]:
end = start
found_delta = self.timedelta.match(val, start=end)
def match(self, val: str) -> Optional[MatcherReturn]:
found_delta = self.timedelta.match(val)
if found_delta:
params, end = found_delta
params, val = found_delta
else:
params = {}
found_day = self.weekday.match(val, start=end)
found_day = self.weekday.match(val)
if found_day:
params, end = found_day
params, val = found_day
else:
found_date = self.date.match(val, start=end)
found_date = self.date.match(val)
if found_date:
params, end = found_date
params, val = found_date
found_time = self.time.match(val, start=end)
found_time = self.time.match(val)
if found_time:
params = {**params, **found_time.params}
end = found_time.end
return MatcherReturn(params, end) if len(params) > 0 else None
val = found_time.unconsumed
return MatcherReturn(params=params, unconsumed=val) if len(params) > 0 else None
Locales = Dict[str, Locale]
......@@ -30,9 +30,10 @@ locales["en_iso"] = Locale(
rf"(?:(?P<days>[-+]?\d+)\s?d(?:ays?)?{td_sep_en})?"
rf"(?:(?P<hours>[-+]?\d+)\s?h(?:(?:r|our)?s?){td_sep_en})?"
rf"(?:(?P<minutes>[-+]?\d+)\s?m(?:in(?:ute)?s?)?{td_sep_en})?"
r"(?:(?P<seconds>[-+]?\d+)\s?s(?:ec(?:ond)?s?)?)?"),
date=RegexMatcher(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"),
weekday=WeekdayMatcher(pattern=r"today"
r"(?:(?P<seconds>[-+]?\d+)\s?s(?:ec(?:ond)?s?)?)?"
r"(?:\s|$)"),
date=RegexMatcher(r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})\s"),
weekday=WeekdayMatcher(pattern=r"(?:today"
r"|tomorrow"
r"|mon(?:day)?"
r"|tues?(?:day)?"
......@@ -40,7 +41,8 @@ locales["en_iso"] = Locale(
r"|thu(?:rs(?:day)?)?"
r"|fri(?:day)?"
r"|sat(?:urday)?"
r"|sun(?:day)?",
r"|sun(?:day)?)"
r"(?:\s|$)",
map={
"tod": +0, "tom": +1, "mon": MO, "tue": TU, "wed": WE, "thu": TH,
"fri": FR, "sat": SA, "sun": SU,
......@@ -48,22 +50,24 @@ locales["en_iso"] = Locale(
time=RegexMatcher(r"\s?(?:at\s)?"
r"(?P<hour>\d{2})"
r"[:.](?P<minute>\d{2})"
r"(?:[:.](?P<second>\d{2}))?"),
r"(?:[:.](?P<second>\d{2}))?"
r"(?:\s|$)"),
)
time_12_en = TimeMatcher(r"\s?(?:at\s)?"
r"(?P<hour>\d{2})"
r"(?:[:.](?P<minute>\d{2}))?"
r"(?:[:.](?P<second>\d{2}))?"
r"(?:\s(?P<meridiem>a\.?m|p\.?m)\.?)?")
r"(?:\s(?P<meridiem>a\.?m|p\.?m)\.?)?"
r"(?:\s|$)")
locales["en_us"] = locales["en_iso"].replace(
name="English (US)", time=time_12_en,
date=ShortYearMatcher(r"(?P<month>\d{1,2})/(?P<day>\d{1,2})(?:/(?P<year>\d{2}(?:\d{2})?))?"))
name="English (US)", time=time_12_en, date=ShortYearMatcher(
r"(?P<month>\d{1,2})/(?P<day>\d{1,2})(?:/(?P<year>\d{2}(?:\d{2})?))?(?:\s|$)"))
locales["en_uk"] = locales["en_iso"].replace(
name="English (UK)", time=time_12_en,
date=ShortYearMatcher(r"(?P<day>\d{1,2})/(?P<month>\d{1,2})(?:/(?P<year>\d{2}(?:\d{2})?))?"))
name="English (UK)", time=time_12_en, date=ShortYearMatcher(
r"(?P<day>\d{1,2})/(?P<month>\d{1,2})(?:/(?P<year>\d{2}(?:\d{2})?))?(?:\s|$)"))
td_sep_fi = r"(?:[\s,]{1,3}(?:ja\s)?)"
locales["fi_fi"] = Locale(
......@@ -75,8 +79,9 @@ locales["fi_fi"] = Locale(
rf"(?:(?P<hours>[-+]?\d+)\s?t(?:un(?:nin?|tia))?{td_sep_fi})?"
rf"(?:(?P<minutes>[-+]?\d+)\s?m(?:in(?:uut(?:in?|tia))?)?{td_sep_fi})?"
r"(?:(?P<seconds>[-+]?\d+)\s?s(?:ek(?:un(?:nin?|tia))?)?)?"
r"(?:\s(?:kuluttua|päästä?))?"),
date=ShortYearMatcher(r"(?P<day>\d{1,2})\.(?P<month>\d{1,2})\.(?P<year>\d{2}(?:\d{2})?)"),
r"(?:\s(?:kuluttua|päästä?))?"
r"(?:\s|$)"),
date=ShortYearMatcher(r"(?P<day>\d{1,2})\.(?P<month>\d{1,2})\.(?P<year>\d{2}(?:\d{2})?)\s"),
weekday=WeekdayMatcher(pattern=r"(?:tänään"
r"|(?:yli)?huomen"
r"|ma(?:aanantai)?"
......@@ -86,7 +91,8 @@ locales["fi_fi"] = Locale(
r"|pe(?:rjantai)?"
r"|la(?:uantai)?"
r"|su(?:nnuntai)?)"
r"(?:na)?",
r"(?:na)?"
r"(?:\s|$)",
map={
"": +0, "hu": +1, "yl": +2,
"ma": MO, "ti": TU, "ke": WE, "to": TH, "pe": FR, "la": SA, "su": SU,
......@@ -94,7 +100,8 @@ locales["fi_fi"] = Locale(
time=RegexMatcher(r"\s?(?:ke?ll?o\.?\s)?"
r"(?P<hour>\d{2})"
r"[:.](?P<minute>\d{2})"
r"(?:[:.](?P<second>\d{2}))?"),
r"(?:[:.](?P<second>\d{2}))?"
r"(?:\s|$)"),
)
td_sep_de = r"(?:[\s,]{1,3}(?:und\s)?)"
......@@ -108,7 +115,8 @@ locales["de_de"] = Locale(
rf"(?:(?P<hours>[-+]?\d+)\s?stunden?{td_sep_de})?"
rf"(?:(?P<minutes>[-+]?\d+)\s?minuten?{td_sep_de})?"
r"(?:(?P<seconds>[-+]?\d+)\s?sekunden?)?"),
date=ShortYearMatcher(r"(?P<day>\d{1,2})\.(?P<month>\d{1,2})\.(?P<year>\d{2}(?:\d{2})?)"),
date=ShortYearMatcher(
r"(?P<day>\d{1,2})\.(?P<month>\d{1,2})\.(?P<year>\d{2}(?:\d{2})?)(?:\s|$)"),
weekday=WeekdayMatcher(pattern=r"(?:heute"
r"|(?:über)?morgen"
r"|mo(?:ntag)?"
......@@ -117,7 +125,8 @@ locales["de_de"] = Locale(
r"|do(?:nnerstag)?"
r"|fr(?:eitag)?"
r"|sa(?:mstag)?"
r"|so(?:nntag)?)",
r"|so(?:nntag)?)"
r"(?:\s|$)",
map={
"heu": +0, "mor": +1, "übe": +2, "mon": MO, "die": TU, "mit": WE,
"don": TH, "fre": FR, "sam": SA, "son": SU,
......@@ -125,5 +134,6 @@ locales["de_de"] = Locale(
time=RegexMatcher(r"\s?(?:um\s)?"
r"(?P<hour>\d{2})"
r"[:.](?P<minute>\d{2})"
r"(?:[:.](?P<second>\d{2}))?"),
r"(?:[:.](?P<second>\d{2}))?"
r"(?:\s|$)"),
)
......@@ -37,31 +37,6 @@ class Config(BaseProxyConfig):
helper.copy("base_command")
timedelta_regex = re.compile(r"(?:(?P<years>[-+]?\d+)\s?y(?:ears?)?\s?)?"
r"(?:(?P<months>[-+]?\d+)\s?months?\s?)?"
r"(?:(?P<weeks>[-+]?\d+)\s?w(?:eeks?)?\s?)?"
r"(?:(?P<days>[-+]?\d+)\s?d(?:ays?)?\s?)?"
r"(?:(?P<hours>[-+]?\d+)\s?h(?:ours?)?\s?)?"
r"(?:(?P<minutes>[-+]?\d+)\s?m(?:inutes?)?\s?)?"
r"(?:(?P<seconds>[-+]?\d+)\s?s(?:econds?)?\s?)?",
flags=re.IGNORECASE)
date_regex = re.compile(r"(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})")
day_regex = re.compile(r"today"
r"|tomorrow"
r"|mon(?:day)?"
r"|tues?(?:day)?"
r"|wed(?:nesday)?"
r"|thu(?:rs(?:day)?)?"
r"|fri(?:day)?"
r"|sat(?:urday)?"
r"|sun(?:day)?",
flags=re.IGNORECASE)
time_regex = re.compile(r"(?:\sat\s)?(?P<hour>\d{2})"
r"[:.](?P<minute>\d{2})"
r"(?:[:.](?P<second>\d{2}))?",
flags=re.IGNORECASE)
class DateArgument(Argument):
def __init__(self, name: str, label: str = None, *, required: bool = False):
super().__init__(name, label=label, required=required, pass_raw=True)
......@@ -79,7 +54,7 @@ class DateArgument(Argument):
match = locale.match(val)
if match:
date = (datetime.now(tz=tz) + relativedelta(**match.params)).astimezone(pytz.UTC)
return val[match.end:], date
return match.unconsumed, date
return val, None
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment