Skip to content
Snippets Groups Projects
Select Git revision
  • dac98e6a953b6d0a37590be57a62a593b74843ad
  • master default protected
2 results

Makefile

Blame
  • arg_attrs.py 5.10 KiB
    # Automatický generátor command-line argumentů pro atributy databázových objektů
    
    import argparse
    from dataclasses import dataclass
    from datetime import datetime
    from typing import Callable, Any, Optional, Type, List
    
    import mo.db as db
    
    
    class HelpFormatter(argparse.HelpFormatter):
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, max_help_position=50, **kwargs)
    
    
    @dataclass
    class Attr:
        name: str
        parser: Callable[[str], Any]
        help: str
        long: Optional[str] = None
        short: Optional[str] = None
        nullable: bool = False
    
        def add_to_arg_parser(self, parser: argparse.ArgumentParser) -> None:
            arg_names = []
            if self.short is not None:
                arg_names.append('-' + self.short)
            if self.long is not None:
                arg_names.append('--' + self.long)
            else:
                arg_names.append('--' + self.name.replace('_', '-'))
    
            other = {
                'metavar': 'X',
            }
    
            typ = self.parser
            if typ is parse_bool:
                other['nargs'] = '?'
                other['const'] = 'true'
                other['metavar'] = 'BOOL'
            if self.nullable:
                typ = make_nullable_parser(typ)
    
            parser.add_argument(*arg_names, type=typ, default=Ellipsis, help=self.help, **other)
    
        def args_to_obj(self, args: argparse.Namespace, obj: Any) -> None:
            key = self.long.replace('-', '_') if self.long else self.name
            val = getattr(args, key)
            assert hasattr(obj, self.name)
            if val is not Ellipsis:
                setattr(obj, self.name, val)
    
    
    @dataclass
    class AttrList:
        attrs: List[Attr]
    
        def add_to_arg_parser(self, parser: argparse.ArgumentParser) -> None:
            for a in self.attrs:
                a.add_to_arg_parser(parser)
    
        def args_to_obj(self, args: argparse.Namespace, obj: Any) -> None:
            for a in self.attrs:
                a.args_to_obj(args, obj)
    
    
    def parse_enum(e: Type[db.MOEnum], s: str) -> Any:
        try:
            return e.coerce(s)
        except ValueError:
            choices = ", ".join([x.name for x in e])
            raise argparse.ArgumentTypeError(f'Invalid value {s} (must be one of {choices})')
    
    
    def parse_type(s: str) -> db.RoundType:
        return parse_enum(db.RoundType, s)
    
    
    def parse_time(s: str) -> Optional[datetime]:
        return datetime.fromisoformat(s).astimezone()
    
    
    def parse_bool(s: str) -> bool:
        if s in ('true', '1', 'yes', 't', 'y'):
            return True
        if s in ('false', '0', 'no', 'f', 'n'):
            return False
        raise ValueError(f'Cannot parse {s} as Boolean value')
    
    
    def parse_score_mode(s: str) -> db.RoundScoreMode:
        return parse_enum(db.RoundScoreMode, s)
    
    
    def parse_enroll_mode(s: str) -> db.RoundEnrollMode:
        return parse_enum(db.RoundEnrollMode, s)
    
    
    def make_nullable_parser(typ: Callable[[str], Any]) -> Any:
        def parse(s: str) -> Any:
            if s == '-' or s == "":
                return None
            else:
                return typ(s)
    
        return parse
    
    
    ROUND_ATTRS = AttrList([
        Attr('level',                   int,                'úroveň v hierarchii oblastí', short='l'),
        Attr('name',                    str,                'název kola', short='n'),
        Attr('round_type',              parse_type,         'typ kola', long='type', short='t'),
        # FIXME: state, last_state
        # tasks_file nenastavujeme
        Attr('ct_tasks_start',          parse_time,         'začátek pro účastníky', nullable=True),
        Attr('ct_submit_end',           parse_time,         'konec odevzdávání pro účastníky'),
        Attr('pr_tasks_start',          parse_time,         'začátek pro dozor'),
        Attr('pr_submit_end',           parse_time,         'konec odevzdávání pro dozor'),
        Attr('online_submit',           parse_bool,         'povoleno elektronické odevzdávání'),
        Attr('score_mode',              parse_score_mode,   'režim výsledkové listiny'),
        Attr('score_winner_limit',      float,              'hranice bodů pro vítěze', nullable=True),
        Attr('score_successful_limit',  float,              'hranice bodů pro úspěšného řešitele', nullable=True),
        Attr('score_advance_limit',     float,              'hranice bodů pro postup', nullable=True),
        Attr('points_step',             float,              'bodovací krok', short='S'),
        Attr('has_messages',            parse_bool,         'povoleny zprávičky'),
        Attr('enroll_mode',             parse_enroll_mode,  'režim registrace'),
        Attr('enroll_advert',           str,                'popis v přihlášce'),
        Attr('enroll_deadline',         parse_time,         'deadline přihlašování', nullable=True),
        Attr('min_rec_grade',           int,                'minimální doporučený ročník (1-12)', nullable=True),
        Attr('max_rec_grade',           int,                'maximální doporučený ročník (1-12)', nullable=True),
        Attr('export_score_to_mo_web',  parse_bool,         'exportovat výsledkovky na web', long='publish-score'),
    ])
    
    
    CONTEST_ATTRS = AttrList([
        Attr('online_submit',           parse_bool,         'povoleno elektronické odevzdávání'),
        Attr('tex_hacks',               str,                'hacky pro sazbu výsledkových listin'),
    ])