Skip to content
Snippets Groups Projects
Commit de3a0ae1 authored by Martin Mareš's avatar Martin Mareš
Browse files

Nové skripty na zakládání/změny kol/soutěží

Postaveny kolem nového modulu mo.arg_attrs.
parent cc8ff120
Branches
No related tags found
No related merge requests found
...@@ -2,14 +2,15 @@ ...@@ -2,14 +2,15 @@
import argparse import argparse
from mo.arg_attrs import CONTEST_ATTRS, HelpFormatter
import mo.db as db import mo.db as db
import mo.util import mo.util
from mo.util import die, init_standalone from mo.util import die, init_standalone
parser = argparse.ArgumentParser(description='Založí soutěže pro dané kolo') parser = argparse.ArgumentParser(description='Založí soutěže pro dané kolo', formatter_class=HelpFormatter)
parser.add_argument(dest='round', type=str, metavar='YY-C-S[p]', help='kód kola') parser.add_argument(dest='round', type=str, metavar='YY-C-S[p]', help='kód kola')
parser.add_argument('-r', '--region', type=str, metavar='CODE', help='soutěžní oblast (default: založit všechny)') parser.add_argument('-r', '--region', type=str, metavar='CODE', help='soutěžní oblast (default: založit všechny)')
parser.add_argument('--online-submit', default=False, action='store_true', help='povolí elektronické odevzdávání') CONTEST_ATTRS.add_to_arg_parser(parser)
parser.add_argument('-n', '--dry-run', default=False, action='store_true', help='pouze ukáže, co by bylo provedeno') parser.add_argument('-n', '--dry-run', default=False, action='store_true', help='pouze ukáže, co by bylo provedeno')
args = parser.parse_args() args = parser.parse_args()
...@@ -24,7 +25,8 @@ round = mo.util.get_round_by_code(round_code) ...@@ -24,7 +25,8 @@ round = mo.util.get_round_by_code(round_code)
if round is None: if round is None:
die("Kolo s tímto kódem neexistuje!") die("Kolo s tímto kódem neexistuje!")
online_submit = round.online_submit or args.online_submit if args.online_submit is Ellipsis:
args.online_submit = round.online_submit
region = None region = None
if args.region is not None: if args.region is not None:
...@@ -42,7 +44,8 @@ if round.is_subround(): ...@@ -42,7 +44,8 @@ if round.is_subround():
print(f"{round.round_code()} pro místo {r.name}: zakládám (podsoutěž)") print(f"{round.round_code()} pro místo {r.name}: zakládám (podsoutěž)")
if not args.dry_run: if not args.dry_run:
c = db.Contest(round=round, place=r, master=mc, state=round.last_state, online_submit=online_submit) c = db.Contest(round=round, place=r, master=mc, state=round.last_state)
CONTEST_ATTRS.args_to_obj(args, c)
sess.add(c) sess.add(c)
sess.flush() sess.flush()
...@@ -50,6 +53,7 @@ if round.is_subround(): ...@@ -50,6 +53,7 @@ if round.is_subround():
mo.util.log(db.LogType.contest, c.contest_id, { mo.util.log(db.LogType.contest, c.contest_id, {
'action': 'created', 'action': 'created',
'reason': 'script', 'reason': 'script',
'new': db.row2dict(c),
}) })
else: else:
...@@ -65,7 +69,8 @@ else: ...@@ -65,7 +69,8 @@ else:
else: else:
print(f"{round.round_code()} pro místo {r.name}: zakládám") print(f"{round.round_code()} pro místo {r.name}: zakládám")
if not args.dry_run: if not args.dry_run:
c = db.Contest(round=round, place=r, state=round.last_state, online_submit=online_submit) c = db.Contest(round=round, place=r, state=round.last_state)
CONTEST_ATTRS.args_to_obj(args, c)
sess.add(c) sess.add(c)
sess.flush() sess.flush()
...@@ -74,6 +79,7 @@ else: ...@@ -74,6 +79,7 @@ else:
mo.util.log(db.LogType.contest, c.contest_id, { mo.util.log(db.LogType.contest, c.contest_id, {
'action': 'created', 'action': 'created',
'reason': 'script', 'reason': 'script',
'new': db.row2dict(c),
}) })
if not args.dry_run: if not args.dry_run:
......
...@@ -2,27 +2,23 @@ ...@@ -2,27 +2,23 @@
import argparse import argparse
from mo.arg_attrs import ROUND_ATTRS, HelpFormatter
import mo.db as db import mo.db as db
import mo.util import mo.util
from mo.util import die from mo.util import die
parser = argparse.ArgumentParser(description='Založí soutěžní kolo') parser = argparse.ArgumentParser(description='Založí soutěžní kolo', formatter_class=HelpFormatter)
parser.add_argument('-y', '--year', type=int, required=True, help='ročník') parser.add_argument('-y', '--year', type=int, required=True, help='ročník')
parser.add_argument('-c', '--cat', type=str, required=True, help='kategorie') parser.add_argument('-c', '--cat', type=str, required=True, help='kategorie')
parser.add_argument('-s', '--seq', type=int, required=True, help='pořadí kola') parser.add_argument('-s', '--seq', type=int, required=True, help='pořadí kola')
parser.add_argument('-l', '--level', type=int, required=True, help='úroveň v hierarchii oblastí')
parser.add_argument('-p', '--part', type=int, default=0, help='část v rámci skupiny kol (default: 0)') parser.add_argument('-p', '--part', type=int, default=0, help='část v rámci skupiny kol (default: 0)')
parser.add_argument('-n', '--name', type=str, required=True, help='název kola') ROUND_ATTRS.add_to_arg_parser(parser)
parser.add_argument('-S', '--step', type=float, default=1, help='bodovací krok (default: 1)')
parser.add_argument('-t', '--type', type=str, default='other', help='typ kola (default: other)')
parser.add_argument('--score-mode', type=str, default='basic', help='režim výsledkové listiny (default: basic)')
parser.add_argument('--enroll-mode', type=str, default='manual', help='režim registrace (default: manual)')
parser.add_argument('--enroll-advert', type=str, default='', help='popis v přihlášce')
parser.add_argument('--publish-score', default=False, action='store_true', help='publikovat výsledkové listiny')
parser.add_argument('--online-submit', default=False, action='store_true', help='povolit elektronické odevzdávání')
args = parser.parse_args() args = parser.parse_args()
if args.points_step is Ellipsis:
args.points_step = 1
mo.util.init_standalone() mo.util.init_standalone()
sess = db.get_session() sess = db.get_session()
...@@ -40,17 +36,10 @@ rnd = db.Round( ...@@ -40,17 +36,10 @@ rnd = db.Round(
category=args.cat, category=args.cat,
seq=args.seq, seq=args.seq,
part=args.part, part=args.part,
level=args.level,
name=args.name,
points_step=args.step,
round_type=db.RoundType.coerce(args.type),
score_mode=db.RoundScoreMode.coerce(args.score_mode),
enroll_mode=db.RoundEnrollMode.coerce(args.enroll_mode),
enroll_advert=args.enroll_advert,
export_score_to_mo_web=args.publish_score,
online_submit=args.online_submit,
) )
ROUND_ATTRS.args_to_obj(args, rnd)
sess.add(rnd) sess.add(rnd)
sess.flush() sess.flush()
......
#!/usr/bin/env python3
import argparse
from mo.arg_attrs import CONTEST_ATTRS, HelpFormatter
import mo.db as db
import mo.util
from mo.util import die
parser = argparse.ArgumentParser(description='Nastaví parametry soutěží', formatter_class=HelpFormatter)
parser.add_argument('--in-round', type=str, metavar='YY-C-S[p]', help='nastaví všem soutěžím v daném kole')
parser.add_argument('--id', type=int, metavar='ID', help='nastaví soutěži s daným ID')
CONTEST_ATTRS.add_to_arg_parser(parser)
args = parser.parse_args()
mo.util.init_standalone()
sess = db.get_session()
if args.in_round is not None:
round_code = mo.util.RoundCode.parse(args.in_round)
if round_code is None:
die("Chybná syntaxe kódu kola")
rnd = mo.util.get_round_by_code(round_code)
if rnd is None:
die("Kolo s tímto kódem neexistuje!")
contests = sess.query(db.Contest).filter_by(round=rnd).all()
elif args.id is not None:
contests = sess.query(db.Contest).filter_by(contest_id=args.id).all()
if not contests:
die("Soutěž s tímto ID neexistuje")
else:
die("Není vybraná žádná soutěž")
num_modified = 0
for c in contests:
CONTEST_ATTRS.args_to_obj(args, c)
if sess.is_modified(c):
num_modified += 1
changes = db.get_object_changes(c)
mo.util.log(
type=db.LogType.contest,
what=c.contest_id,
details={
'action': 'edit',
'reason': 'script',
'changes': changes,
},
)
sess.commit()
print(f'Modifikováno {num_modified} soutěží z {len(contests)}')
#!/usr/bin/env python3
import argparse
from mo.arg_attrs import ROUND_ATTRS, HelpFormatter
import mo.db as db
import mo.util
from mo.util import die
parser = argparse.ArgumentParser(description='Nastaví parametry soutěžního kola', formatter_class=HelpFormatter)
parser.add_argument(dest='round', type=str, metavar='YY-C-S[p]', help='kód kola')
ROUND_ATTRS.add_to_arg_parser(parser)
args = parser.parse_args()
mo.util.init_standalone()
sess = db.get_session()
round_code = mo.util.RoundCode.parse(args.round)
if round_code is None:
die("Chybná syntaxe kódu kola")
rnd = mo.util.get_round_by_code(round_code)
if rnd is None:
die("Kolo s tímto kódem neexistuje!")
ROUND_ATTRS.args_to_obj(args, rnd)
if sess.is_modified(rnd):
changes = db.get_object_changes(rnd)
mo.util.log(
type=db.LogType.round,
what=rnd.round_id,
details={
'action': 'edit',
'reason': 'script',
'changes': changes,
},
)
sess.commit()
# 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)
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('switch_to_grading', parse_time, 'čas automatického přepnutí na opravová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_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'),
])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment