X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=dateparse%2Fdateparse_utils.py;h=6ba647c847e48931017292947bfe36cb423f772f;hb=f2600f30801c849fc1d139386e3ddc3c9eb43e30;hp=05bee8dee7d95d4124192d0b6a2ee553f7d2a9f7;hpb=09e6d10face80d98a4578ff54192b5c8bec007d7;p=python_utils.git diff --git a/dateparse/dateparse_utils.py b/dateparse/dateparse_utils.py index 05bee8d..6ba647c 100755 --- a/dateparse/dateparse_utils.py +++ b/dateparse/dateparse_utils.py @@ -1,8 +1,13 @@ #!/usr/bin/env python3 +# type: ignore + +""" +Parse dates in a variety of formats. + +""" import datetime import functools -import holidays # type: ignore import logging import re import sys @@ -11,18 +16,21 @@ from typing import Any, Callable, Dict, Optional import antlr4 # type: ignore import dateutil.easter import dateutil.tz +import holidays # type: ignore import pytz import acl import bootstrap -from datetime_utils import ( - TimeUnit, n_timeunits_from_base, datetime_to_date, date_to_datetime -) +import decorator_utils from dateparse.dateparse_utilsLexer import dateparse_utilsLexer # type: ignore from dateparse.dateparse_utilsListener import dateparse_utilsListener # type: ignore from dateparse.dateparse_utilsParser import dateparse_utilsParser # type: ignore -from decorator_utils import decorate_matching_methods_with - +from datetime_utils import ( + TimeUnit, + date_to_datetime, + datetime_to_date, + n_timeunits_from_base, +) logger = logging.getLogger(__name__) @@ -30,67 +38,57 @@ logger = logging.getLogger(__name__) def debug_parse(enter_or_exit_f: Callable[[Any, Any], None]): @functools.wraps(enter_or_exit_f) def debug_parse_wrapper(*args, **kwargs): - slf = args[0] + # slf = args[0] ctx = args[1] depth = ctx.depth() logger.debug( - ' ' * (depth-1) + - f'Entering {enter_or_exit_f.__name__} ({ctx.invokingState} / {ctx.exception})' + ' ' * (depth - 1) + + f'Entering {enter_or_exit_f.__name__} ({ctx.invokingState} / {ctx.exception})' ) for c in ctx.getChildren(): - logger.debug( - ' ' * (depth-1) + - f'{c} {type(c)}' - ) + logger.debug(' ' * (depth - 1) + f'{c} {type(c)}') retval = enter_or_exit_f(*args, **kwargs) return retval + return debug_parse_wrapper class ParseException(Exception): """An exception thrown during parsing because of unrecognized input.""" + def __init__(self, message: str) -> None: - logger.error(message) self.message = message class RaisingErrorListener(antlr4.DiagnosticErrorListener): """An error listener that raises ParseExceptions.""" - def syntaxError( - self, recognizer, offendingSymbol, line, column, msg, e - ): - logger.error(msg) + + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): raise ParseException(msg) - def reportAmbiguity( - self, recognizer, dfa, startIndex, stopIndex, exact, - ambigAlts, configs - ): + def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs): pass def reportAttemptingFullContext( - self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, - configs + self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs ): pass - def reportContextSensitivity( - self, recognizer, dfa, startIndex, stopIndex, prediction, configs - ): + def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs): pass -@decorate_matching_methods_with( +@decorator_utils.decorate_matching_methods_with( debug_parse, acl=acl.StringWildcardBasedACL( allowed_patterns=[ 'enter*', 'exit*', ], - denied_patterns=None, + denied_patterns=['enterEveryRule', 'exitEveryRule'], order_to_check_allow_deny=acl.Order.DENY_ALLOW, - default_answer=False - ) + default_answer=False, + ), ) class DateParser(dateparse_utilsListener): PARSE_TYPE_SINGLE_DATE_EXPR = 1 @@ -98,11 +96,7 @@ class DateParser(dateparse_utilsListener): PARSE_TYPE_SINGLE_TIME_EXPR = 3 PARSE_TYPE_BASE_AND_OFFSET_TIME_EXPR = 4 - def __init__( - self, - *, - override_now_for_test_purposes = None - ) -> None: + def __init__(self, *, override_now_for_test_purposes=None) -> None: """C'tor. Passing a value to override_now_for_test_purposes can be used to force this instance to use a custom date/time for its idea of "now" so that the code can be more easily unittested. @@ -136,7 +130,7 @@ class DateParser(dateparse_utilsListener): 9: 30, 10: 31, 11: 30, - 12: 31 + 12: 31, } # N.B. day number is also synched with datetime_utils.TimeUnit values @@ -191,6 +185,8 @@ class DateParser(dateparse_utilsListener): This is the main entrypoint to this class for caller code. """ + date_string = date_string.strip() + date_string = re.sub(r'\s+', ' ', date_string) self._reset() listener = RaisingErrorListener() input_stream = antlr4.InputStream(date_string) @@ -225,8 +221,9 @@ class DateParser(dateparse_utilsListener): to timezone naive (i.e. tzinfo = None). """ dt = self.datetime - if tz is not None: - dt = dt.replace(tzinfo=None).astimezone(tz=tz) + if dt is not None: + if tz is not None: + dt = dt.replace(tzinfo=None).astimezone(tz=tz) return dt # -- helpers -- @@ -238,14 +235,13 @@ class DateParser(dateparse_utilsListener): self.today = datetime.date.today() else: self.now_datetime = self.override_now_for_test_purposes - self.today = datetime_to_date( - self.override_now_for_test_purposes - ) + self.today = datetime_to_date(self.override_now_for_test_purposes) self.date: Optional[datetime.date] = None self.time: Optional[datetime.time] = None self.datetime: Optional[datetime.datetime] = None self.context: Dict[str, Any] = {} self.timedelta = datetime.timedelta(seconds=0) + self.saw_overt_year = False @staticmethod def _normalize_special_day_name(name: str) -> str: @@ -266,16 +262,16 @@ class DateParser(dateparse_utilsListener): return TimeUnit.MONTHS txt = orig.lower()[:3] if txt in self.day_name_to_number: - return(self.day_name_to_number[txt]) + return TimeUnit(self.day_name_to_number[txt]) elif txt in self.delta_unit_to_constant: - return(self.delta_unit_to_constant[txt]) + return TimeUnit(self.delta_unit_to_constant[txt]) raise ParseException(f'Invalid date unit: {orig}') def _figure_out_time_unit(self, orig: str) -> int: """Figure out what unit a time expression piece is talking about.""" txt = orig.lower()[:3] if txt in self.time_delta_unit_to_constant: - return(self.time_delta_unit_to_constant[txt]) + return self.time_delta_unit_to_constant[txt] raise ParseException(f'Invalid time unit: {orig}') def _parse_special_date(self, name: str) -> Optional[datetime.date]: @@ -297,8 +293,10 @@ class DateParser(dateparse_utilsListener): next_last = self.context.get('special_next_last', '') if next_last == 'next': year += 1 + self.saw_overt_year = True elif next_last == 'last': year -= 1 + self.saw_overt_year = True # Holiday names if name == 'easte': @@ -306,13 +304,9 @@ class DateParser(dateparse_utilsListener): elif name == 'hallo': return datetime.date(year=year, month=10, day=31) - for holiday_date, holiday_name in sorted( - holidays.US(years=year).items() - ): + for holiday_date, holiday_name in sorted(holidays.US(years=year).items()): if 'Observed' not in holiday_name: - holiday_name = DateParser._normalize_special_day_name( - holiday_name - ) + holiday_name = DateParser._normalize_special_day_name(holiday_name) if name == holiday_name: return holiday_date if name == 'chriseve': @@ -357,12 +351,12 @@ class DateParser(dateparse_utilsListener): raise ParseException('Missing day') if 'year' not in self.context: self.context['year'] = self.today.year + self.saw_overt_year = False + else: + self.saw_overt_year = True # Handling "ides" and "nones" requires both the day and month. - if ( - self.context['day'] == 'ide' or - self.context['day'] == 'non' - ): + if self.context['day'] == 'ide' or self.context['day'] == 'non': self.context['day'] = self._resolve_ides_nones( self.context['day'], self.context['month'] ) @@ -379,31 +373,31 @@ class DateParser(dateparse_utilsListener): # Try pytz try: - tz = pytz.timezone(txt) - if tz is not None: - return tz - except: + tz1 = pytz.timezone(txt) + if tz1 is not None: + return tz1 + except Exception: pass # Try dateutil try: - tz = dateutil.tz.gettz(txt) - if tz is not None: - return tz - except: + tz2 = dateutil.tz.gettz(txt) + if tz2 is not None: + return tz2 + except Exception: pass # Try constructing an offset in seconds try: - sign = txt[0] - if sign == '-' or sign == '+': - sign = +1 if sign == '+' else -1 + txt_sign = txt[0] + if txt_sign == '-' or txt_sign == '+': + sign = +1 if txt_sign == '+' else -1 hour = int(txt[1:3]) minute = int(txt[-2:]) offset = sign * (hour * 60 * 60) + sign * (minute * 60) tzoffset = dateutil.tz.tzoffset(txt, offset) return tzoffset - except: + except Exception: pass return None @@ -438,19 +432,26 @@ class DateParser(dateparse_utilsListener): micros = self.time.microsecond self.datetime = datetime.datetime( - year, month, day, hour, minute, second, micros, - tzinfo=self.time.tzinfo + year, + month, + day, + hour, + minute, + second, + micros, + tzinfo=self.time.tzinfo, ) # Apply resudual adjustments to times here when we have a # datetime. self.datetime = self.datetime + self.timedelta + assert self.datetime is not None self.time = datetime.time( self.datetime.hour, self.datetime.minute, self.datetime.second, self.datetime.microsecond, - self.datetime.tzinfo + self.datetime.tzinfo, ) def enterDateExpr(self, ctx: dateparse_utilsParser.DateExprContext): @@ -491,10 +492,10 @@ class DateParser(dateparse_utilsListener): if 'delta_before_after' in self.context: before_after = self.context['delta_before_after'].lower() if ( - before_after == 'before' or - before_after == 'until' or - before_after == 'til' or - before_after == 'to' + before_after == 'before' + or before_after == 'until' + or before_after == 'til' + or before_after == 'to' ): count = -count @@ -502,11 +503,7 @@ class DateParser(dateparse_utilsListener): if 'delta_unit' not in self.context: raise ParseException('Missing delta_unit?!') unit = self.context['delta_unit'] - dt = n_timeunits_from_base( - count, - unit, - date_to_datetime(self.date) - ) + dt = n_timeunits_from_base(count, TimeUnit(unit), date_to_datetime(self.date)) self.date = datetime_to_date(dt) def exitTimeExpr(self, ctx: dateparse_utilsParser.TimeExprContext) -> None: @@ -536,10 +533,10 @@ class DateParser(dateparse_utilsListener): if 'time_delta_before_after' in self.context: before_after = self.context['time_delta_before_after'].lower() if ( - before_after == 'before' or - before_after == 'until' or - before_after == 'til' or - before_after == 'to' + before_after == 'before' + or before_after == 'until' + or before_after == 'til' + or before_after == 'to' ): count = -count @@ -555,63 +552,49 @@ class DateParser(dateparse_utilsListener): elif unit == TimeUnit.HOURS: self.timedelta = datetime.timedelta(hours=count) else: - raise ParseException() + raise ParseException(f'Invalid Unit: "{unit}"') - def exitDeltaPlusMinusExpr( - self, ctx: dateparse_utilsParser.DeltaPlusMinusExprContext - ) -> None: + def exitDeltaPlusMinusExpr(self, ctx: dateparse_utilsParser.DeltaPlusMinusExprContext) -> None: try: n = ctx.nth() if n is None: - raise ParseException( - f'Bad N in Delta +/- Expr: {ctx.getText()}' - ) + raise ParseException(f'Bad N in Delta +/- Expr: {ctx.getText()}') n = n.getText() n = self._get_int(n) - unit = self._figure_out_date_unit( - ctx.deltaUnit().getText().lower() - ) - except: + unit = self._figure_out_date_unit(ctx.deltaUnit().getText().lower()) + except Exception: raise ParseException(f'Invalid Delta +/-: {ctx.getText()}') else: self.context['delta_int'] = n self.context['delta_unit'] = unit - def exitNextLastUnit( - self, ctx: dateparse_utilsParser.DeltaUnitContext - ) -> None: + def exitNextLastUnit(self, ctx: dateparse_utilsParser.DeltaUnitContext) -> None: try: unit = self._figure_out_date_unit(ctx.getText().lower()) - except: + except Exception: raise ParseException(f'Bad delta unit: {ctx.getText()}') else: self.context['delta_unit'] = unit - def exitDeltaNextLast( - self, ctx: dateparse_utilsParser.DeltaNextLastContext - ) -> None: + def exitDeltaNextLast(self, ctx: dateparse_utilsParser.DeltaNextLastContext) -> None: try: txt = ctx.getText().lower() - except: + except Exception: raise ParseException(f'Bad next/last: {ctx.getText()}') - if ( - 'month' in self.context or - 'day' in self.context or - 'year' in self.context - ): - raise ParseException( - 'Next/last expression expected to be relative to today.' - ) + if 'month' in self.context or 'day' in self.context or 'year' in self.context: + raise ParseException('Next/last expression expected to be relative to today.') if txt[:4] == 'next': self.context['delta_int'] = +1 self.context['day'] = self.now_datetime.day self.context['month'] = self.now_datetime.month self.context['year'] = self.now_datetime.year + self.saw_overt_year = True elif txt[:4] == 'last': self.context['delta_int'] = -1 self.context['day'] = self.now_datetime.day self.context['month'] = self.now_datetime.month self.context['year'] = self.now_datetime.year + self.saw_overt_year = True else: raise ParseException(f'Bad next/last: {ctx.getText()}') @@ -619,57 +602,41 @@ class DateParser(dateparse_utilsListener): self, ctx: dateparse_utilsParser.CountUnitsBeforeAfterTimeExprContext ) -> None: if 'nth' not in self.context: - raise ParseException( - f'Bad count expression: {ctx.getText()}' - ) + raise ParseException(f'Bad count expression: {ctx.getText()}') try: - unit = self._figure_out_time_unit( - ctx.deltaTimeUnit().getText().lower() - ) + unit = self._figure_out_time_unit(ctx.deltaTimeUnit().getText().lower()) self.context['time_delta_unit'] = unit - except: + except Exception: raise ParseException(f'Bad delta unit: {ctx.getText()}') if 'time_delta_before_after' not in self.context: - raise ParseException( - f'Bad Before/After: {ctx.getText()}' - ) + raise ParseException(f'Bad Before/After: {ctx.getText()}') - def exitDeltaTimeFraction( - self, ctx: dateparse_utilsParser.DeltaTimeFractionContext - ) -> None: + def exitDeltaTimeFraction(self, ctx: dateparse_utilsParser.DeltaTimeFractionContext) -> None: try: txt = ctx.getText().lower()[:4] if txt == 'quar': self.context['time_delta_int'] = 15 - self.context[ - 'time_delta_unit' - ] = TimeUnit.MINUTES + self.context['time_delta_unit'] = TimeUnit.MINUTES elif txt == 'half': self.context['time_delta_int'] = 30 - self.context[ - 'time_delta_unit' - ] = TimeUnit.MINUTES + self.context['time_delta_unit'] = TimeUnit.MINUTES else: raise ParseException(f'Bad time fraction {ctx.getText()}') - except: + except Exception: raise ParseException(f'Bad time fraction {ctx.getText()}') - def exitDeltaBeforeAfter( - self, ctx: dateparse_utilsParser.DeltaBeforeAfterContext - ) -> None: + def exitDeltaBeforeAfter(self, ctx: dateparse_utilsParser.DeltaBeforeAfterContext) -> None: try: txt = ctx.getText().lower() - except: + except Exception: raise ParseException(f'Bad delta before|after: {ctx.getText()}') else: self.context['delta_before_after'] = txt - def exitDeltaTimeBeforeAfter( - self, ctx: dateparse_utilsParser.DeltaBeforeAfterContext - ) -> None: + def exitDeltaTimeBeforeAfter(self, ctx: dateparse_utilsParser.DeltaBeforeAfterContext) -> None: try: txt = ctx.getText().lower() - except: + except Exception: raise ParseException(f'Bad delta before|after: {ctx.getText()}') else: self.context['time_delta_before_after'] = txt @@ -696,9 +663,7 @@ class DateParser(dateparse_utilsListener): year = self.context.get('year', self.today.year) if 'month' not in self.context: - raise ParseException( - f'Missing month expression: {ctx.getText()}' - ) + raise ParseException(f'Missing month expression: {ctx.getText()}') month = self.context['month'] dow = self.context['dow'] @@ -729,10 +694,8 @@ class DateParser(dateparse_utilsListener): self.context['month'] = month self.context['day'] = 1 self.main_type = DateParser.PARSE_TYPE_BASE_AND_OFFSET_EXPR - except: - raise ParseException( - f'Invalid nthWeekday expression: {ctx.getText()}' - ) + except Exception: + raise ParseException(f'Invalid nthWeekday expression: {ctx.getText()}') def exitFirstLastWeekdayInMonthMaybeYearExpr( self, @@ -743,14 +706,12 @@ class DateParser(dateparse_utilsListener): def exitNth(self, ctx: dateparse_utilsParser.NthContext) -> None: try: i = self._get_int(ctx.getText()) - except: + except Exception: raise ParseException(f'Bad nth expression: {ctx.getText()}') else: self.context['nth'] = i - def exitFirstOrLast( - self, ctx: dateparse_utilsParser.FirstOrLastContext - ) -> None: + def exitFirstOrLast(self, ctx: dateparse_utilsParser.FirstOrLastContext) -> None: try: txt = ctx.getText() if txt == 'first': @@ -758,10 +719,8 @@ class DateParser(dateparse_utilsListener): elif txt == 'last': txt = -1 else: - raise ParseException( - f'Bad first|last expression: {ctx.getText()}' - ) - except: + raise ParseException(f'Bad first|last expression: {ctx.getText()}') + except Exception: raise ParseException(f'Bad first|last expression: {ctx.getText()}') else: self.context['nth'] = txt @@ -770,14 +729,12 @@ class DateParser(dateparse_utilsListener): try: dow = ctx.getText().lower()[:3] dow = self.day_name_to_number.get(dow, None) - except: + except Exception: raise ParseException('Bad day of week') else: self.context['dow'] = dow - def exitDayOfMonth( - self, ctx: dateparse_utilsParser.DayOfMonthContext - ) -> None: + def exitDayOfMonth(self, ctx: dateparse_utilsParser.DayOfMonthContext) -> None: try: day = ctx.getText().lower() if day[:3] == 'ide': @@ -791,16 +748,12 @@ class DateParser(dateparse_utilsListener): return day = self._get_int(day) if day < 1 or day > 31: - raise ParseException( - f'Bad dayOfMonth expression: {ctx.getText()}' - ) - except: + raise ParseException(f'Bad dayOfMonth expression: {ctx.getText()}') + except Exception: raise ParseException(f'Bad dayOfMonth expression: {ctx.getText()}') self.context['day'] = day - def exitMonthName( - self, ctx: dateparse_utilsParser.MonthNameContext - ) -> None: + def exitMonthName(self, ctx: dateparse_utilsParser.MonthNameContext) -> None: try: month = ctx.getText() while month[0] == '/' or month[0] == '-': @@ -808,27 +761,19 @@ class DateParser(dateparse_utilsListener): month = month[:3].lower() month = self.month_name_to_number.get(month, None) if month is None: - raise ParseException( - f'Bad monthName expression: {ctx.getText()}' - ) - except: + raise ParseException(f'Bad monthName expression: {ctx.getText()}') + except Exception: raise ParseException(f'Bad monthName expression: {ctx.getText()}') else: self.context['month'] = month - def exitMonthNumber( - self, ctx: dateparse_utilsParser.MonthNumberContext - ) -> None: + def exitMonthNumber(self, ctx: dateparse_utilsParser.MonthNumberContext) -> None: try: month = self._get_int(ctx.getText()) if month < 1 or month > 12: - raise ParseException( - f'Bad monthNumber expression: {ctx.getText()}' - ) - except: - raise ParseException( - f'Bad monthNumber expression: {ctx.getText()}' - ) + raise ParseException(f'Bad monthNumber expression: {ctx.getText()}') + except Exception: + raise ParseException(f'Bad monthNumber expression: {ctx.getText()}') else: self.context['month'] = month @@ -837,9 +782,10 @@ class DateParser(dateparse_utilsListener): year = self._get_int(ctx.getText()) if year < 1: raise ParseException(f'Bad year expression: {ctx.getText()}') - except: + except Exception: raise ParseException(f'Bad year expression: {ctx.getText()}') else: + self.saw_overt_year = True self.context['year'] = year def exitSpecialDateMaybeYearExpr( @@ -848,10 +794,8 @@ class DateParser(dateparse_utilsListener): try: special = ctx.specialDate().getText().lower() self.context['special'] = special - except: - raise ParseException( - f'Bad specialDate expression: {ctx.specialDate().getText()}' - ) + except Exception: + raise ParseException(f'Bad specialDate expression: {ctx.specialDate().getText()}') try: mod = ctx.thisNextLast() if mod is not None: @@ -861,10 +805,8 @@ class DateParser(dateparse_utilsListener): self.context['special_next_last'] = 'next' elif mod.LAST() is not None: self.context['special_next_last'] = 'last' - except: - raise ParseException( - f'Bad specialDateNextLast expression: {ctx.getText()}' - ) + except Exception: + raise ParseException(f'Bad specialDateNextLast expression: {ctx.getText()}') def exitNFoosFromTodayAgoExpr( self, ctx: dateparse_utilsParser.NFoosFromTodayAgoExprContext @@ -874,19 +816,14 @@ class DateParser(dateparse_utilsListener): count = self._get_int(ctx.unsignedInt().getText()) unit = ctx.deltaUnit().getText().lower() ago_from_now = ctx.AGO_FROM_NOW().getText() - except: - raise ParseException( - f'Bad NFoosFromTodayAgoExpr: {ctx.getText()}' - ) + except Exception: + raise ParseException(f'Bad NFoosFromTodayAgoExpr: {ctx.getText()}') if "ago" in ago_from_now or "back" in ago_from_now: count = -count unit = self._figure_out_date_unit(unit) - d = n_timeunits_from_base( - count, - unit, - d) + d = n_timeunits_from_base(count, TimeUnit(unit), d) self.context['year'] = d.year self.context['month'] = d.month self.context['day'] = d.day @@ -894,42 +831,59 @@ class DateParser(dateparse_utilsListener): def exitDeltaRelativeToTodayExpr( self, ctx: dateparse_utilsParser.DeltaRelativeToTodayExprContext ) -> None: + # When someone says "next week" they mean a week from now. + # Likewise next month or last year. These expressions are now + # +/- delta. + # + # But when someone says "this Friday" they mean "this coming + # Friday". It would be weird to say "this Friday" if today + # was already Friday but I'm parsing it to mean: the next day + # that is a Friday. So when you say "next Friday" you mean + # the Friday after this coming Friday, or 2 Fridays from now. + # + # This set handles this weirdness. + weekdays = set( + [ + TimeUnit.MONDAYS, + TimeUnit.TUESDAYS, + TimeUnit.WEDNESDAYS, + TimeUnit.THURSDAYS, + TimeUnit.FRIDAYS, + TimeUnit.SATURDAYS, + TimeUnit.SUNDAYS, + ] + ) d = self.now_datetime try: mod = ctx.thisNextLast() + unit = ctx.deltaUnit().getText().lower() + unit = self._figure_out_date_unit(unit) if mod.LAST(): count = -1 elif mod.THIS(): - count = +1 + if unit in weekdays: + count = +1 + else: + count = 0 elif mod.NEXT(): - count = +2 + if unit in weekdays: + count = +2 + else: + count = +1 else: - raise ParseException( - f'Bad This/Next/Last modifier: {mod}' - ) - unit = ctx.deltaUnit().getText().lower() - except: - raise ParseException( - f'Bad DeltaRelativeToTodayExpr: {ctx.getText()}' - ) - unit = self._figure_out_date_unit(unit) - d = n_timeunits_from_base( - count, - unit, - d) + raise ParseException(f'Bad This/Next/Last modifier: {mod}') + except Exception: + raise ParseException(f'Bad DeltaRelativeToTodayExpr: {ctx.getText()}') + d = n_timeunits_from_base(count, TimeUnit(unit), d) self.context['year'] = d.year self.context['month'] = d.month self.context['day'] = d.day - def exitSpecialTimeExpr( - self, ctx: dateparse_utilsParser.SpecialTimeExprContext - ) -> None: + def exitSpecialTimeExpr(self, ctx: dateparse_utilsParser.SpecialTimeExprContext) -> None: try: txt = ctx.specialTime().getText().lower() - except: - raise ParseException( - f'Bad special time expression: {ctx.getText()}' - ) + except Exception: + raise ParseException(f'Bad special time expression: {ctx.getText()}') else: if txt == 'noon' or txt == 'midday': self.context['hour'] = 12 @@ -947,25 +901,23 @@ class DateParser(dateparse_utilsListener): try: tz = ctx.tzExpr().getText() self.context['tz'] = self._parse_tz(tz) - except: + except Exception: pass - def exitTwelveHourTimeExpr( - self, ctx: dateparse_utilsParser.TwelveHourTimeExprContext - ) -> None: + def exitTwelveHourTimeExpr(self, ctx: dateparse_utilsParser.TwelveHourTimeExprContext) -> None: try: hour = ctx.hour().getText() while not hour[-1].isdigit(): hour = hour[:-1] hour = self._get_int(hour) - except: + except Exception: raise ParseException(f'Bad hour: {ctx.hour().getText()}') if hour <= 0 or hour > 12: raise ParseException(f'Bad hour (out of range): {hour}') try: minute = self._get_int(ctx.minute().getText()) - except: + except Exception: minute = 0 if minute < 0 or minute > 59: raise ParseException(f'Bad minute (out of range): {minute}') @@ -973,7 +925,7 @@ class DateParser(dateparse_utilsListener): try: seconds = self._get_int(ctx.second().getText()) - except: + except Exception: seconds = 0 if seconds < 0 or seconds > 59: raise ParseException(f'Bad second (out of range): {seconds}') @@ -981,7 +933,7 @@ class DateParser(dateparse_utilsListener): try: micros = self._get_int(ctx.micros().getText()) - except: + except Exception: micros = 0 if micros < 0 or micros > 1000000: raise ParseException(f'Bad micros (out of range): {micros}') @@ -989,7 +941,7 @@ class DateParser(dateparse_utilsListener): try: ampm = ctx.ampm().getText() - except: + except Exception: raise ParseException(f'Bad ampm: {ctx.ampm().getText()}') if hour == 12: hour = 0 @@ -1000,7 +952,7 @@ class DateParser(dateparse_utilsListener): try: tz = ctx.tzExpr().getText() self.context['tz'] = self._parse_tz(tz) - except: + except Exception: pass def exitTwentyFourHourTimeExpr( @@ -1011,7 +963,7 @@ class DateParser(dateparse_utilsListener): while not hour[-1].isdigit(): hour = hour[:-1] hour = self._get_int(hour) - except: + except Exception: raise ParseException(f'Bad hour: {ctx.hour().getText()}') if hour < 0 or hour > 23: raise ParseException(f'Bad hour (out of range): {hour}') @@ -1019,7 +971,7 @@ class DateParser(dateparse_utilsListener): try: minute = self._get_int(ctx.minute().getText()) - except: + except Exception: minute = 0 if minute < 0 or minute > 59: raise ParseException(f'Bad minute (out of range): {ctx.getText()}') @@ -1027,7 +979,7 @@ class DateParser(dateparse_utilsListener): try: seconds = self._get_int(ctx.second().getText()) - except: + except Exception: seconds = 0 if seconds < 0 or seconds > 59: raise ParseException(f'Bad second (out of range): {ctx.getText()}') @@ -1035,7 +987,7 @@ class DateParser(dateparse_utilsListener): try: micros = self._get_int(ctx.micros().getText()) - except: + except Exception: micros = 0 if micros < 0 or micros >= 1000000: raise ParseException(f'Bad micros (out of range): {ctx.getText()}') @@ -1044,7 +996,7 @@ class DateParser(dateparse_utilsListener): try: tz = ctx.tzExpr().getText() self.context['tz'] = self._parse_tz(tz) - except: + except Exception: pass @@ -1059,8 +1011,10 @@ def main() -> None: try: dt = parser.parse(line) except Exception as e: + logger.exception(e) print("Unrecognized.") else: + assert dt is not None print(dt.strftime('%A %Y/%m/%d %H:%M:%S.%f %Z(%z)')) sys.exit(0)