Skip to content

execution

All the code used to record code execution.

TermageNamespace

A simple namespace for exec globals, exposed as termage.

You can use all below methods by referencing the termage object in termage-run code, which you don't have to import.

You usually want to hide these lines, as they are generally for styling purposes.

Source code in termage/execution.py
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
class TermageNamespace:
    """A simple namespace for exec globals, exposed as `termage`.

    You can use all below methods by referencing the `termage` object
    in termage-run code, which you don't have to import.

    You _usually_ want to hide these lines, as they are generally for
    styling purposes.
    """

    @property
    def terminal(self) -> ptg.Terminal:
        """Returns the current terminal object."""

        return ptg.get_terminal()

    def fit(self, widget: ptg.Widget) -> None:
        """Fits the output terminal around the given widget."""

        self.terminal.size = widget.width, widget.height

    def resize(self, width: int, height: int) -> None:
        """Resizes the output terminal to the given dimensions."""

        self.terminal.size = width, height

fit(widget)

Fits the output terminal around the given widget.

Source code in termage/execution.py
65
66
67
68
def fit(self, widget: ptg.Widget) -> None:
    """Fits the output terminal around the given widget."""

    self.terminal.size = widget.width, widget.height

resize(width, height)

Resizes the output terminal to the given dimensions.

Source code in termage/execution.py
70
71
72
73
def resize(self, width: int, height: int) -> None:
    """Resizes the output terminal to the given dimensions."""

    self.terminal.size = width, height

terminal() property

Returns the current terminal object.

Source code in termage/execution.py
59
60
61
62
63
@property
def terminal(self) -> ptg.Terminal:
    """Returns the current terminal object."""

    return ptg.get_terminal()

execute(code=None, file=None, highlight=False, *, exec_globals=EXEC_GLOBALS)

Executes the given code under a custom context.

Parameters:

Name Type Description Default
code str | None

The Python code to execute.

None
file Path | None

A file that will be opened, and its contents will be added to the executed code before the code argument.

None
highlight bool

If set, the combined code will only be highlighted using PyTermGUI's highlight_python function, with that result being written to the SVG. Great for quick code screenshots!

False
exec_globals dict[str, Any]

The dictionary that will be passed to exec, which makes it the global namespace of the context.

EXEC_GLOBALS
Source code in termage/execution.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
def execute(
    code: str | None = None,
    file: Path | None = None,
    highlight: bool = False,
    *,
    exec_globals: dict[str, Any] = EXEC_GLOBALS,
) -> None:
    """Executes the given code under a custom context.

    Args:
        code: The Python code to execute.
        file: A file that will be opened, and its contents will
            be added to the executed code *before* the `code` argument.
        highlight: If set, the combined code will only be highlighted using
            PyTermGUI's `highlight_python` function, with that result being
            written to the SVG. Great for quick code screenshots!
        exec_globals: The dictionary that will be passed to `exec`, which
            makes it the global namespace of the context.
    """

    ptg.WindowManager.autorun = False

    exec_globals = exec_globals.copy()
    code = code or ""

    # if module is not None:
    # mod_name, *args = module.split()
    # sys.argv = [*args]
    # out = runpy.run_module(mod_name, init_globals={"sys": sys})
    # print(out)

    if file is not None:
        with open(file, "r", encoding="utf-8") as source:
            code = source.read() + code

    if highlight:
        print(ptg.tim.parse(ptg.highlight_python(code)))
        return exec_globals

    exec(code, exec_globals)

    if "manager" in exec_globals:
        exec_globals["manager"].compositor.draw()

    return exec_globals

format_codeblock(block)

Formats a codeblock into display and executed lines.

Source code in termage/execution.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def format_codeblock(block: str) -> tuple[str, str]:
    """Formats a codeblock into display and executed lines."""

    disp_lines, exec_lines = [], []

    lines = block.splitlines()
    indent = " " * (len(lines[0]) - len(lines[0].lstrip()))

    for line in lines:
        line = line.replace(indent, "", 1)
        if line.startswith("&"):
            exec_lines.append(line[1:])
            continue

        exec_lines.append(line)
        disp_lines.append(line)

    return "\n".join(disp_lines), "\n".join(exec_lines)

patched_stdout_recorder(width, height)

Records everything written to stdout, even built is print.

It does so by monkeypathing sys.stdout.write to a custom function, which first writes to a custom Terminal.

Parameters:

Name Type Description Default
width int | None

The width of the terminal used for the recording.

required
height int | None

The height of the terminal used for the recording.

required

Returns:

Type Description
Generator[ptg.Recorder, None, None]

The recorder object, with all the data written to it.

Source code in termage/execution.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
@contextmanager
def patched_stdout_recorder(
    width: int | None, height: int | None
) -> Generator[ptg.Recorder, None, None]:
    """Records everything written to stdout, even built is print.

    It does so by monkeypathing `sys.stdout.write` to a custom function,
    which first writes to a custom `Terminal`.

    Args:
        width: The width of the terminal used for the recording.
        height: The height of the terminal used for the recording.

    Returns:
        The recorder object, with all the data written to it.
    """

    if width is None:
        width = DEFAULT_WIDTH

    if height is None:
        height = DEFAULT_HEIGHT

    stdout_write = sys.stdout.write

    stream = StringIO()
    terminal = ptg.Terminal(stream=stream, size=(width, height))

    ptg.set_global_terminal(terminal)

    def _write(item, **kwargs) -> None:
        """Writes something, breaks lines."""

        ends_with_linebreak = item.endswith("\n")

        lines = list(ptg.break_line(item, terminal.width))

        for i, line in enumerate(lines):
            if ends_with_linebreak or i < len(lines) - 1:
                line += "\n"

            terminal.write(line, **kwargs)

    with terminal.record() as recorder:
        try:
            sys.stdout.write = _write
            yield recorder

        finally:
            sys.stdout.write = stdout_write  # type: ignore

set_colors(foreground, background)

Sets the colors that will be used by the terminal.

Source code in termage/execution.py
185
186
187
188
189
190
191
192
def set_colors(foreground: str | None, background: str | None) -> None:
    """Sets the colors that will be used by the terminal."""

    if foreground is not None:
        ptg.Color.default_foreground = ptg.str_to_color(foreground)

    if background is not None:
        ptg.Color.default_background = ptg.str_to_color(background)

termage(code='', include=None, width=None, height=None, title='', chrome=True, foreground=None, background=None, highlight_only=False, save_as=None)

A generalized wrapper for Termage functionality.

Parameters:

Name Type Description Default
code str

The code that will be run to generate the file.

''
include str | Path | None

A path to a Python file that will be included before code.

None
width int | None

The output terminal's width.

None
height int | None

The output terminal's height.

None
title str

The output terminal's window title. Has no effect when chrome is False.

''
chrome bool

Shows or hides the window decorations.

True
foreground str | None

Sets the default foreground (text) style of the output. Only applies to unstyled text.

None
background str | None

Sets the output terminal's background color.

None
highlight_only bool

If set, the given code is not run, rather given to the ptg.highlight_python function.

False
save_as str | Path | None

If set, the export will be written to this filepath. The export will be returned regardless of this setting.

None

Returns:

Type Description
str

The exported SVG file.

Source code in termage/execution.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def termage(  # pylint: disable=too-many-arguments
    code: str = "",
    include: str | Path | None = None,
    width: int | None = None,
    height: int | None = None,
    title: str = "",
    chrome: bool = True,
    foreground: str | None = None,
    background: str | None = None,
    highlight_only: bool = False,
    save_as: str | Path | None = None,
) -> str:
    """A generalized wrapper for Termage functionality.

    Args:
        code: The code that will be run to generate the file.
        include: A path to a Python file that will be included before `code`.
        width: The output terminal's width.
        height: The output terminal's height.
        title: The output terminal's window title. Has no effect when `chrome`
            is `False`.
        chrome: Shows or hides the window decorations.
        foreground: Sets the default foreground (text) style of the output. Only
            applies to unstyled text.
        background: Sets the output terminal's background color.
        highlight_only: If set, the given code is not run, rather given to the
            `ptg.highlight_python` function.
        save_as: If set, the export will be written to this filepath. The export
            will be returned regardless of this setting.

    Returns:
        The exported SVG file.
    """

    set_colors(foreground, background)
    if include is not None:
        with open(include, "r", encoding="utf-8") as includefile:
            code = includefile.read() + code

    with patched_stdout_recorder(width, height) as recording:
        execute(code=code, highlight=highlight_only)

    export = recording.export_svg(title=title, chrome=chrome)

    if save_as is not None:
        with open(save_as, "w", encoding="utf-8") as save:
            save.write(export)

    return export