Beispiel #1
0
    def _readconfig(self, filename):
        if not self.minimal:
            print_msg("Loading contest {}".format(self.contestname),
                      headerdepth=1)

        super(ContestConfig, self)._readconfig(filename)
        self._initialize_ranking()
Beispiel #2
0
    def _readconfig(self, filename):
        if not self.minimal:
            print_msg("Loading contest {}".format(self.contestname),
                      headerdepth=1)

        super(ContestConfig, self)._readconfig(filename)
        self._initialize_ranking()
Beispiel #3
0
    def user(self, username, password, firstname, lastname, group=None,
             ip=None, hidden=False, unrestricted=False, timezone=None,
             primary_statements=[], team=None):
        """
        Add a user participating in this contest.

        username (unicode): user name (for login)

        password (unicode): password used both for the user and for the
                            participation

        firstname (unicode): first name

        lastname (unicode): last name

        group (MyGroup): the group to add this user to (by default the
                         default group, which is usually called main)

        ip (unicode): ip address the user must log in from (if this feature
                      is enabled in CMS)

        hidden (bool): whether this user is hidden (not shown on the official
                       scoreboard)

        unrestricted (bool): whether this user is unrestricted (can submit at
                             any time)

        timezone (unicode): time zone for this user (if different from contest
                            time zone)

        primary_statements (string[] or {string: string[]}): either a list of
            languages (it is assumed that all tasks have a translation for
            this language) or a dictionary mapping task names to language names

        team (string or MyTeam): (name of) the team the user belongs to

        return (MyUser): object representing the created user

        """
        if self.minimal:
            return

        if username in self.users:
            raise Exception(
                "User {} specified multiple times".format(username))
        if group is None:
            if self.defaultgroup is None:
                raise Exception("You have to specify a group")
            group = self.defaultgroup
        if team is not None and not isinstance(team, MyTeam):
            team = self.teams[team]
        print_msg("Adding user {} to group {}".format(username, group.name),
                  headerdepth=10)
        self.users[username] = user = \
            MyUser(username, password, group,
                   firstname, lastname,
                   ip, hidden, unrestricted, timezone, primary_statements,
                   team)
        return user
Beispiel #4
0
    def timezone(self, s):
        """
        Set the contest time zone.

        s (unicode): contest time zone (e.g. Europe/Berlin)

        """
        if not self.minimal:
            print_msg("Setting timezone to {}".format(s), headerdepth=10)
        self._timezone = s
Beispiel #5
0
    def description(self, s):
        """
        Set the contest description.

        s (unicode): contest description

        """
        if not self.minimal:
            print_msg("Setting description to {}".format(s), headerdepth=10)
        self._description = s
Beispiel #6
0
    def timezone(self, s):
        """
        Set the contest time zone.

        s (unicode): contest time zone (e.g. Europe/Berlin)

        """
        if not self.minimal:
            print_msg("Setting timezone to {}".format(s), headerdepth=10)
        self._timezone = s
Beispiel #7
0
    def description(self, s):
        """
        Set the contest description.

        s (unicode): contest description

        """
        if not self.minimal:
            print_msg("Setting description to {}".format(s), headerdepth=10)
        self._description = s
Beispiel #8
0
    def user_group(self, s, start, stop, analysis_start=None, analysis_stop=None, per_user_time=None):
        """
        Create a user group.

        s (unicode): user group name;
                     if the group is called "main", it is assumed to be the
                     default group.

        start (string): start time (should be created via a call to time())

        stop (string): stop time (should be created via a call to time())

        analysis_start (string): enable analysis with this start time (should be created via a call to time())

        analysis_stop (string): enable analysis with this stop time (should be created via a call to time())

        per_user_time (timedelta): enable USACO mode with this time per user;
            see :ref:`configuringacontest_usaco-like-contests`

        return (MyGroup): object representing the created group

        """
        if s in self.groups:
            raise Exception("Group {} specified multiple times".format(s))

        if self.minimal:
            return

        if (analysis_start is None) ^ (analysis_stop is None):
            raise Exception("Analysis start and stop time can only be used together")

        usaco_mode_str = ""
        if per_user_time is not None:
            usaco_mode_str = \
                " in USACO mode with time {}".format(per_user_time)
        analysis_mode_str = ""
        if analysis_start is not None:
            analysis_mode_str = \
                ", analysing from {} to {}".format(analysis_start,analysis_stop)
        print_msg("Creating user group {} (working from {} to {}{}{})"
                  .format(s, start, stop, usaco_mode_str, analysis_mode_str), headerdepth=10)

        # We allow specifying an integer or a timedelta
        try:
            per_user_time = per_user_time.seconds
        except AttributeError:
            pass

        self.groups[s] = r = MyGroup(s, start, stop, analysis_start, analysis_stop, per_user_time)
        if s == "main":
            self.defaultgroup = r
        return r
Beispiel #9
0
    def supplement_file(self, key, filename):
        """
        Set the storage file for supplements registered with the given
        file type.

        key (string): a string specifying for which purpose to use the
                      supplement

        filename (string): name of the file to save the supplements to

        """
        print_msg("Supplement file for {} set to {}".format(key, filename),
                  headerdepth=10)
        self.supplements[key].add_file(filename)
Beispiel #10
0
    def _task(self, s, feedback, score_mode, minimal, standalone_task=False):
        """
        Add a task to this contest (full version, not accessible from
        config.py).

        s (unicode): task name; the task description has to reside in the
                     folder with the same name
        feedback:    type of feedback (one of the variables no_feedback,
                     partial_feedback, full_feedback, restricted_feedback)
        score_mode:  how to calculate the final score (one of SCORE_MODE_MAX,
                     SCORE_MODE_MAX_SUBTASK, SCORE_MODE_MAX_TOKENED_LAST)
        minimal (bool): only try to compile statement?

        """
        # Check if this task should be ignored
        if self.onlytask is not None and self.onlytask != s:
            return

        if not os.path.isdir(s):
            raise Exception("No directory found for task {}".format(s))

        if s in self.tasks:
            raise Exception("Task {} specified multiple times".format(s))

        with chdir(s):
            if not os.path.isfile("config.py"):
                raise Exception("Couldn't find task config file. Make sure it "
                                "is named 'config.py' and located on the "
                                "topmost level of the folder {}"
                                .format(os.getcwd()))

            with TaskConfig(self, os.path.abspath(".rules"),
                            s, len(self.tasks),
                            feedback, score_mode,
                            ignore_latex=self.ignore_latex,
                            relevant_language=self.relevant_language,
                            minimal=minimal,
                            standalone_task=standalone_task) as taskconfig:

                for f in self.ontasks:
                    f(taskconfig)
                taskconfig._readconfig("config.py")
                taskconfig._printresult()
                self.tasks[s] = taskconfig

            if minimal:
                print_msg("Statement for task {} generated successfully".
                          format(s), success=True)
            else:
                print_msg("Task {} loaded completely".format(s), success=True)
Beispiel #11
0
    def user_group(self, s, start, stop, analysis_start=None, analysis_stop=None, per_user_time=None):
        """
        Create a user group.

        s (unicode): user group name;
                     if the group is called "main", it is assumed to be the
                     default group.

        start (string): start time (should be created via a call to time())

        stop (string): stop time (should be created via a call to time())

        analysis_start (string): enable analysis with this start time (should be created via a call to time())

        analysis_stop (string): enable analysis with this stop time (should be created via a call to time())

        per_user_time (timedelta): enable USACO mode with this time per user;
            see :ref:`configuringacontest_usaco-like-contests`

        return (MyGroup): object representing the created group

        """
        if s in self.groups:
            raise Exception("Group {} specified multiple times".format(s))

        if (analysis_start is None) ^ (analysis_stop is None):
            raise Exception("Analysis start and stop time can only be used together")

        usaco_mode_str = ""
        if per_user_time is not None:
            usaco_mode_str = \
                " in USACO mode with time {}".format(per_user_time)
        analysis_mode_str = ""
        if analysis_start is not None:
            analysis_mode_str = \
                ", analysing from {} to {}".format(analysis_start,analysis_stop)
        print_msg("Creating user group {} (working from {} to {}{}{})"
                  .format(s, start, stop, usaco_mode_str, analysis_mode_str), headerdepth=10)

        # We allow specifying an integer or a timedelta
        try:
            per_user_time = per_user_time.seconds
        except AttributeError:
            pass

        self.groups[s] = r = MyGroup(s, start, stop, analysis_start, analysis_stop, per_user_time)
        if s == "main":
            self.defaultgroup = r
        return r
Beispiel #12
0
    def _task(self, s, feedback, minimal):
        """
        Add a task to this contest (full version, not accessible from
        config.py).

        s (unicode): task name; the task description has to reside in the
                     folder with the same name
        feedback:    type of feedback (one of the variables no_feedback,
                     partial_feedback, full_feedback, restricted_feedback)
        minimal (bool): only try to compile statement?

        """
        # Check if this task should be ignored
        if self.onlytask is not None and self.onlytask != s:
            return

        if not os.path.isdir(s):
            raise Exception("No directory found for task {}".format(s))

        if s in self.tasks:
            raise Exception("Task {} specified multiple times".format(s))

        with chdir(s):
            if not os.path.isfile("config.py"):
                raise Exception("Couldn't find task config file. Make sure it "
                                "is named 'config.py' and located on the "
                                "topmost level of the folder {}"
                                .format(os.getcwd()))

            with TaskConfig(self, os.path.abspath(".rules"),
                            s, len(self.tasks),
                            feedback,
                            ignore_latex=self.ignore_latex,
                            minimal=minimal) as taskconfig:
                for f in self.ontasks:
                    f(taskconfig)
                taskconfig._readconfig("config.py")
                taskconfig._printresult()
                self.tasks[s] = taskconfig
            if minimal:
                print_msg("Statement for task {} generated successfully".
                          format(s), success=True)
            else:
                print_msg("Task {} loaded completely".format(s), success=True)
Beispiel #13
0
    def make_overview_sheets(self):
        """
        Print overview sheets in two versions (with tasks and all contestants
        of any individual team in one file OR without tasks and all contestants
        separately) and ZIP them together
        """
        if self.contest.ignore_latex:
            return

        teams = {}
        contestants_with_language = {}
        overview_sheets_for = {}

        assert (all(t._feedback_level == FEEDBACK_LEVEL_RESTRICTED
                    for t in self.contest.tasks.values()))
        assert (all(t.score_mode() == SCORE_MODE_MAX_SUBTASK
                    for t in self.contest.tasks.values()))

        prefix = "overview-sheets-for"

        for u in self.contest.users.values():
            team = u.team

            if team not in teams:
                teams[team] = []
            teams[team].append(u)

            for l in u.primary_statements:
                if l not in contestants_with_language:
                    contestants_with_language[l] = []
                contestants_with_language[l].append(u)

        if not os.path.exists("overview"):
            os.mkdir("overview")

        copyrecursivelyifnecessary(
            os.path.join(self.contest.wdir, "general"),
            os.path.join(self.contest.wdir, "overview", "general"))

        self.contest.supply("contestoverview",
                            def_latex("olympiadyear", self.year))

        import csv
        printingunwanted = dict()
        requestsfile = "printingrequested.csv"
        if os.path.exists(requestsfile):
            with open(requestsfile, encoding='utf-8-sig') as f:
                reader = csv.DictReader(f, delimiter=',', quotechar='"')
                for row in reader:
                    c, l = row["Country"], row["Language"]
                    if c not in printingunwanted:
                        printingunwanted[c] = dict()
                    printingunwanted[c]["en"] = row["English"] == "No"
                    printingunwanted[c][l] = row["Own"] == "No"

        with chdir("overview"):
            if not os.path.exists(".overviews-per-language"):
                os.mkdir(".overviews-per-language")

            with chdir(".overviews-per-language"):
                for l, users in contestants_with_language.items():
                    if self.contest.relevant_language and \
                        self.contest.relevant_language != l:
                        continue

                    self.supply_overview()
                    self.contest._build_supplements_for_key("contestoverview")

                    #Provide access to the BOI logo
                    shutil.copy(
                        os.path.join(os.path.dirname(__file__),
                                     "header{}.pdf".format(self.year)),
                        os.path.join(os.getcwd(), "header.pdf"))

                    def do_supply_language():
                        return self.language_supplement(l)

                    def do_supply_credentials():
                        return "\n".join("\\printoverviewpage{%s}{%s, %s}{%s}" % \
                            (u.username, u.lastname, u.firstname, u.password)
                            for u in users)

                    self.contest.supply("lang", do_supply_language)
                    self.contest.supply("credentials", do_supply_credentials)

                    filename = prefix + "-" + l + ".tex"

                    shutil.copy(
                        os.path.join(os.path.dirname(__file__),
                                     "overview-template.tex"), filename)
                    self.contest._build_supplements_for_key("credentials")
                    self.contest._build_supplements_for_key("lang")

                    pdf = PdfFileReader(self.contest.compile(filename))
                    assert (pdf.getNumPages() == len(users))

                    for i, u in enumerate(users):
                        overview_sheets_for[(u.username, l)] = pdf.getPage(i)

                    self.contest.supplements["lang"].parts.clear()
                    self.contest.supplements["credentials"].parts.clear()

            def cleardoublepage(stream):
                if stream.getNumPages() % 2 == 1:
                    stream.addBlankPage()

            for team, users in teams.items():
                if not os.path.exists(team.code):
                    os.mkdir(team.code)

                with chdir(team.code):
                    hw = PdfFileWriter()

                    for u in users:
                        # Overview sheets
                        ow = PdfFileWriter()

                        for l in u.primary_statements:
                            if self.contest.relevant_language and \
                                self.contest.relevant_language != l:
                                continue
                            ow.addPage(overview_sheets_for[(u.username, l)])
                        with open("overview-" + u.username + ".pdf",
                                  "wb") as f:
                            ow.write(f)

                        # handout
                        for l in u.primary_statements:
                            if self.contest.relevant_language and \
                                self.contest.relevant_language != l:
                                continue
                            if printingunwanted \
                                .get(team.name, dict()) \
                                .get(l, False):
                                print_msg("Not adding translation to language "
                                          "{} for user {} to the handout "
                                          "as requested by team {}".format(
                                              l, u.username, team.code))
                                hw.addPage(overview_sheets_for[(u.username,
                                                                l)])
                                cleardoublepage(hw)
                                continue
                            hw.addPage(overview_sheets_for[(u.username, l)])
                            cleardoublepage(hw)

                            for t in sorted(self.contest.tasks.values(),
                                            key=lambda x: x.name):
                                if l in t._statements:
                                    st = PdfFileReader(t._statements[l].file_)
                                    hw.appendPagesFromReader(st)
                                    cleardoublepage(hw)

                    with open("handout.pdf", "wb") as f:
                        hw.write(f)

                job = {
                    "overview-" + u.username + ".pdf":
                    os.path.join(team.code, "overview-" + u.username + ".pdf")
                    for u in users
                }
                job["handout.pdf"] = os.path.join(team.code, "handout.pdf")

                r = ZipRule(os.path.join("..", ".rules"),
                            team.code + "-all.zip", job).ensure()
Beispiel #14
0
    def user(self, username, password, firstname, lastname, group=None,
             ip=None, hidden=False, unofficial=False, unrestricted=False, timezone=None,
             primary_statements=None, team=None):
        """
        Add a user participating in this contest.

        username (unicode): user name (for login)

        password (unicode): password used both for the user and for the
                            participation

        firstname (unicode): first name

        lastname (unicode): last name

        group (MyGroup): the group to add this user to (by default the
                         default group, which is usually called main)

        ip (unicode): ip address the user must log in from (if this feature
                      is enabled in CMS)

        hidden (bool): whether this user is hidden (not shown on the official
                       scoreboard)

        unofficial (bool): whether this user is unofficial (can be hidden on the
                       official scoreboard)

        unrestricted (bool): whether this user is unrestricted (can submit at
                             any time)

        timezone (unicode): time zone for this user (if different from contest
                            time zone)

        primary_statements (string[] or None): the list of standard task
                                               languages for this user (if None,
                                               the languages for the
                                               corresponding team will be used)

        team (string or MyTeam): (name of) the team the user belongs to

        return (MyUser): object representing the created user

        """
        team = team or self._current_team
        if not isinstance(team, MyTeam):
            team = self.teams[team]
        primary_statements = primary_statements or team.primary_statements

        if username in self.users:
            raise Exception(
                "User {} specified multiple times".format(username))
        if group is None:
            if self.defaultgroup is None:
                raise Exception("You have to specify a group")
            group = self.defaultgroup

        print_msg("Adding user {} to group {}".format(username, group.name),
                  headerdepth=10)
        self.users[username] = user = \
            MyUser(username, password, group,
                   firstname, lastname,
                   ip, hidden, unofficial, unrestricted, timezone, primary_statements[:],
                   team)
        return user