File: _gen_screenshots.py

package info (click to toggle)
magicgui 0.9.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 21,796 kB
  • sloc: python: 11,202; makefile: 11; sh: 9
file content (102 lines) | stat: -rw-r--r-- 3,047 bytes parent folder | download
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import re
import subprocess
from itertools import count
from pathlib import Path
from textwrap import dedent

import mkdocs_gen_files
from qtpy.QtWidgets import QApplication

DOCS = Path(__file__).parent.parent
CODE_BLOCK = re.compile("``` ?python\n([^`]*)```", re.DOTALL)


def _set_dark_mode(dark_mode: bool):
    """Set the system to dark mode or not."""
    cmd = ["osascript", "-l", "JavaScript", "-e"]
    if dark_mode:
        cmd += ["Application('System Events').appearancePreferences.darkMode = true"]
    else:
        cmd += ["Application('System Events').appearancePreferences.darkMode = false"]
    subprocess.run(cmd)


# internally used trick to leave a window open at the end of a cell
# add this to the end of a cell to leave it open
LEAVE_OPEN = "# leave open"
LEFT_OPEN = False


def _clear_left_open() -> None:
    global LEFT_OPEN
    for w in QApplication.topLevelWidgets():
        w.close()
        w.deleteLater()
    QApplication.processEvents()
    LEFT_OPEN = False


def _write_markdown_result_image(src: str, ns: dict, dest: str) -> None:
    global LEFT_OPEN
    top_widgets = set(QApplication.topLevelWidgets())
    try:
        exec(src, ns, ns)
    except NameError as e:
        raise NameError(
            f"Error evaluating code for {dest!r} with namespace {set(ns)!r}:\n\n{src}. "
            f"{e}"
        ) from e

    if not LEFT_OPEN:
        top_widgets = set(QApplication.topLevelWidgets()) - top_widgets
    if not top_widgets:
        print("No top level widgets found for", dest)
    if len(top_widgets) > 1:
        name = re.search(r"([^\s\.]+).show\(\)", src, re.DOTALL)[1]
        try:
            top_widgets = {ns[name].native}
        except KeyError:
            pass  # FIXME... it's probably an attribute
    for w in top_widgets:
        w.setMinimumWidth(200)
        w.show()
        w.activateWindow()
        w.update()

        with mkdocs_gen_files.open(dest, "wb") as f:
            if not w.grab().save(f.name):
                print("Error saving", dest)

        if LEAVE_OPEN in src:
            LEFT_OPEN = True
        else:
            _clear_left_open()


EXCLUDE = {"migration.md"}


def main() -> None:
    for mdfile in sorted(DOCS.rglob("*.md"), reverse=True):
        if mdfile.name in EXCLUDE:
            continue
        _clear_left_open()

        md = mdfile.read_text()
        w_iter = count()
        code_blocks = list(CODE_BLOCK.finditer(md))
        has_show = any(".show()" in match.group(0) for match in code_blocks)
        if has_show:
            namespace: dict = {}
            for match in code_blocks:
                code = dedent(match.group(1))
                if ".show()" in match.group(0):
                    dest = f"_images/{mdfile.stem}_{next(w_iter)}.png"
                    _write_markdown_result_image(code, namespace, dest)
                else:
                    # still need to execute the code to populate the namespace
                    # for later code blocks
                    exec(code, namespace, namespace)


main()