import argparse import re from abc import ABCMeta, abstractmethod import dateutil.relativedelta from quarg.quassel.types import BufferType, MessageFlag, MessageType from quarg.utils import errx, parse_isodate class ParseEnum(argparse.Action, metaclass=ABCMeta): def __call__(self, parser, namespace, value, option_string=None): key = value.upper() if key not in self.enumclass.__members__: possible = ', '.join([e.name.lower() for e in self.enumclass]) desc = self.enumclass.describe() errx(f'Not a valid {desc}: {value}\nPossible {desc}s are: {possible}') saved = getattr(namespace, self.dest) or [] saved.append(self.enumclass[key]) setattr(namespace, self.dest, saved) @property @abstractmethod def enumclass(self): pass class ParseMessageType(ParseEnum): @property def enumclass(self): return MessageType class ParseMessageFlag(ParseEnum): @property def enumclass(self): return MessageFlag class ParseBufferType(ParseEnum): @property def enumclass(self): return BufferType class ParseDate(argparse.Action): def __call__(self, parser, namespace, datespec, option_string=None): setattr(namespace, self.dest, parse_isodate(datespec)) class ParseOrder(argparse.Action): def __call__(self, parser, namespace, orderspec, option_string=None): if orderspec not in ['asc', 'desc']: errx(f'Invalid order \'{orderspec}\'. Possible values are: asc, desc') setattr(namespace, self.dest, orderspec) class ParseAround(argparse.Action): def __call__(self, parser, namespace, aroundspec, option_string=None): if '/' in aroundspec: datespec, rangespec = aroundspec.split('/', 1) if not rangespec: errx('Missing range for --around') match = re.match(r'^(?P\d+)(?P[hm])?$', rangespec) if not match: errx(f'Invalid range for --around: \'{rangespec}\'') unit = match.group('unit') try: time_range = int(match.group('range')) except ValueError as err: errx(f'Error when parsing range for --around: {err}') else: datespec, time_range, unit = (aroundspec, 12, 'h') date = parse_isodate(datespec) if unit == 'm': offset = dateutil.relativedelta.relativedelta(minutes=time_range) else: offset = dateutil.relativedelta.relativedelta(hours=time_range) setattr(namespace, self.dest, (date - offset, date + offset))