File: devtools.md

package info (click to toggle)
textual 2.1.2-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 55,080 kB
  • sloc: python: 85,423; lisp: 1,669; makefile: 101
file content (242 lines) | stat: -rw-r--r-- 7,086 bytes parent folder | download | duplicates (2)
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
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
136
137
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
183
184
185
186
187
188
189
190
191
192
193
194
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
# Devtools

!!! note inline end

    If you don't have the `textual` command on your path, you may have forgotten to install the `textual-dev` package.

    See [getting started](../getting_started.md#installation) for details.

Textual comes with a command line application of the same name. The `textual` command is a super useful tool that will help you to build apps.

Take a moment to look through the available subcommands. There will be even more helpful tools here in the future.

```bash
textual --help
```


## Run

The `run` sub-command runs Textual apps. If you supply a path to a Python file it will load and run the app.

```bash
textual run my_app.py
```

This is equivalent to running `python my_app.py` from the command prompt, but will allow you to set various switches which can help you debug, such as `--dev` which enable the [Console](#console).

See the `run` subcommand's help for details:

```bash
textual run --help
```

You can also run Textual apps from a python import.
The following command would import `music.play` and run a Textual app in that module:

```bash
textual run music.play
```

This assumes you have a Textual app instance called `app` in `music.play`.
If your app has a different name, you can append it after a colon:

```bash
textual run music.play:MusicPlayerApp
```

!!! note

    This works for both Textual app *instances* and *classes*.


### Running from commands

If your app is installed as a command line script, you can use the `-c` switch to run it.
For instance, the following will run the `textual colors` command:

```bash
textual run -c textual colors
```

## Serve

The devtools can also serve your application in a browser.
Effectively turning your terminal app into a web application!

The `serve` sub-command is similar to `run`. Here's how you can serve an app launched from a Python file:

```
textual serve my_app.py
```

You can also serve a Textual app launched via a command. Here's an example:

```
textual serve "textual keys"
```

The syntax for launching an app in a module is slightly different from `run`.
You need to specify the full command, including `python`.
Here's how you would run the Textual demo:

```
textual serve "python -m textual"
```

Textual's builtin web-server is quite powerful.
You can serve multiple instances of your application at once!

!!! tip

    Textual serve is also useful when developing your app.
    If you make changes to your code, simply refresh the browser to update.

There are some additional switches for serving Textual apps. Run the following for a list:

```
textual serve --help
```

## Live editing

If you combine the `run` command with the `--dev` switch your app will run in *development mode*.

```bash
textual run --dev my_app.py
```

One of the features of *dev* mode is live editing of CSS files: any changes to your CSS will be reflected in the terminal a few milliseconds later.

This is a great feature for iterating on your app's look and feel. Open the CSS in your editor and have your app running in a terminal. Edits to your CSS will appear almost immediately after you save.

## Console

When building a typical terminal application you are generally unable to use `print` when debugging (or log to the console). This is because anything you write to standard output will overwrite application content. Textual has a solution to this in the form of a debug console which restores `print` and adds a few additional features to help you debug.

To use the console, open up **two** terminal emulators. Run the following in one of the terminals:

```bash
textual console
```

You should see the Textual devtools welcome message:

```{.textual title="textual console" path="docs/examples/getting_started/console.py"}
```

In the other console, run your application with `textual run` and the `--dev` switch:

```bash
textual run --dev my_app.py
```

Anything you `print` from your application will be displayed in the console window. Textual will also write log messages to this window which may be helpful when debugging your application.


### Increasing verbosity

Textual writes log messages to inform you about certain events, such as when the user presses a key or clicks on the terminal. To avoid swamping you with too much information, some events are marked as "verbose" and will be excluded from the logs. If you want to see these log messages, you can add the `-v` switch.

```bash
textual console -v
```

### Decreasing verbosity

Log messages are classififed into groups, and the `-x` flag can be used to **exclude** all message from a group. The groups are: `EVENT`, `DEBUG`, `INFO`, `WARNING`, `ERROR`, `PRINT`, `SYSTEM`, `LOGGING` and `WORKER`. The group a message belongs to is printed after its timestamp.

Multiple groups may be excluded, for example to exclude everything except warning, errors, and `print` statements:

```bash
textual console -x SYSTEM -x EVENT -x DEBUG -x INFO
```

### Custom port

You can use the option `--port` to specify a custom port to run the console on, which comes in handy if you have other software running on the port that Textual uses by default:

```bash
textual console --port 7342
```

Then, use the command `run` with the same `--port` option:

```bash
textual run --dev --port 7342 my_app.py
```


## Textual log

Use the `log` function to pretty-print data structures and anything that [Rich](https://rich.readthedocs.io/en/latest/) can display.

You can import the log function as follows:

```python
from textual import log
```

Here's a few examples of writing to the console, with `log`:



```python
def on_mount(self) -> None:
    log("Hello, World")  # simple string
    log(locals())  # Log local variables
    log(children=self.children, pi=3.141592)  # key/values
    log(self.tree)  # Rich renderables
```

### Log method

There's a convenient shortcut to `log` on the `App` and `Widget` objects. This is useful in event handlers. Here's an example:

```python
from textual.app import App

class LogApp(App):

    def on_load(self):
        self.log("In the log handler!", pi=3.141529)

    def on_mount(self):
        self.log(self.tree)

if __name__ == "__main__":
    LogApp().run()
```

## Logging handler

Textual has a [logging handler][textual.logging.TextualHandler] which will write anything logged via the builtin logging library to the devtools.
This may be useful if you have a third-party library that uses the logging module, and you want to see those logs with Textual logs.

!!! note

    The logging library works with strings only, so you won't be able to log Rich renderables such as `self.tree` with the logging handler.

Here's an example of configuring logging to use the `TextualHandler`.

```python
import logging
from textual.app import App
from textual.logging import TextualHandler

logging.basicConfig(
    level="NOTSET",
    handlers=[TextualHandler()],
)


class LogApp(App):
    """Using logging with Textual."""

    def on_mount(self) -> None:
        logging.debug("Logged via TextualHandler")


if __name__ == "__main__":
    LogApp().run()
```