File size: 2,321 Bytes
22de727
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
"""The paper's final primitive and task sets (data/final_set.yaml) and the lock they put on the annotation tool.

With ``locked: true`` the tool is read-only: no macro registration and no task, verifier or review edits; its pickers
offer only the final primitives and its task list shows only the final tasks. The grader-audit labels are the one
thing it still records. Regenerate the file with ``src/miniweb/scripts/make_final_set.py``; set ``MINIWEB_UNLOCK=1`` to edit
anyway (e.g. a local fix that the paper's numbers will then have to absorb).
"""
from helpers.paths import REPO_ROOT
import os
from functools import lru_cache

import yaml

PATH = os.environ.get("MINIWEB_FINAL_SET") or os.path.join(
    str(REPO_ROOT), "data", "final_set.yaml")

# write routes that stay open under the lock: sessions, read-only search and the grader- and task-audit labels
OPEN_WRITES = {"/annotate/login", "/annotate/logout", "/annotate/api/auto_login", "/annotate/api/auto_logout",
               "/annotate/api/toggle_2fa", "/annotate/api/macro_search"}
OPEN_PREFIXES = ("/annotate/api/grader_audit/", "/annotate/api/task_audit/")


@lru_cache(maxsize=1)
def _data():
    try:
        with open(PATH) as f:
            return yaml.safe_load(f) or {}
    except FileNotFoundError:
        return {}


def locked():
    return bool(_data().get("locked")) and os.environ.get("MINIWEB_UNLOCK") != "1"


def primitives():
    return set(_data().get("primitives") or [])


def tasks():
    """{task_id} of the final task set (task ids are unique across annotators)."""
    return set(_data().get("tasks") or [])


def write_allowed(path):
    return path in OPEN_WRITES or path.startswith(OPEN_PREFIXES)


def keep_primitives(names):
    """Filter a macro list to the final primitives when locked (order kept)."""
    if not locked():
        return list(names)
    keep = primitives()
    return [n for n in names if n in keep]


BANNER = ('<div id="final-set-lock" style="position:fixed;right:12px;top:7px;z-index:99999;padding:3px 10px;'
          'border-radius:12px;background:#334155;color:#f8fafc;font:12px/1.4 system-ui,sans-serif;opacity:.85;'
          'pointer-events:none">Final set locked: {n_p} primitives, {n_t} tasks (read-only)</div>')


def banner():
    return BANNER.format(n_p=len(primitives()), n_t=len(tasks()))