mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
[App] Add _path suffixes to PathLike constructor args
This commit is contained in:
@@ -87,7 +87,7 @@ class ColorChanger(App):
|
||||
self.background = f"on color({event.key})"
|
||||
|
||||
|
||||
ColorChanger.run(log="textual.log")
|
||||
ColorChanger.run(log_path="textual.log")
|
||||
```
|
||||
|
||||
You'll notice that the `on_key` method above contains an additional `event` parameter which wasn't present on the beeper example. If the `event` argument is present, Textual will call the handler with an event object. Every event has an associated handler object, in this case it is a KeyEvent which contains additional information regarding which key was pressed.
|
||||
@@ -114,7 +114,7 @@ class SimpleApp(App):
|
||||
await self.view.dock(Placeholder(), Placeholder(), edge="top")
|
||||
|
||||
|
||||
SimpleApp.run(log="textual.log")
|
||||
SimpleApp.run(log_path="textual.log")
|
||||
```
|
||||
|
||||
This app contains a single event handler `on_mount`. The mount event is sent when the app or widget is ready to start processing events, and is typically used for initialization. You may have noticed that `on_mount` is an `async` function. Since Textual is an asynchronous framework we will need this if we need to call most other methods.
|
||||
@@ -137,7 +137,7 @@ await self.view.dock(Placeholder(), Placeholder(), edge="top")
|
||||
|
||||
You will notice that this time we are docking _two_ Placeholder objects onto the `"top"` edge. We haven't set an explicit size this time so Textual will divide the remaining size amongst the two new widgets.
|
||||
|
||||
The last line calls the `run` class method in the usual way, but with an argument we haven't seen before: `log="textual.log"` tells Textual to write log information to the given file. You can tail textual.log to see events being processed and other debug information.
|
||||
The last line calls the `run` class method in the usual way, but with an argument we haven't seen before: `log_path="textual.log"` tells Textual to write log information to the given file. You can tail textual.log to see events being processed and other debug information.
|
||||
|
||||
If you run the above example, you will see something like the following:
|
||||
|
||||
@@ -183,7 +183,7 @@ class HoverApp(App):
|
||||
await self.view.dock(*hovers, edge="top")
|
||||
|
||||
|
||||
HoverApp.run(log="textual.log")
|
||||
HoverApp.run(log_path="textual.log")
|
||||
```
|
||||
|
||||
The `Hover` class is a custom widget which displays a panel containing the classic text "Hello World". The first line in the Hover class may seem a little mysterious at this point:
|
||||
|
||||
@@ -7,4 +7,4 @@ class ColorChanger(App):
|
||||
self.background = f"on color({event.key})"
|
||||
|
||||
|
||||
ColorChanger.run(log="textual.log")
|
||||
ColorChanger.run(log_path="textual.log")
|
||||
|
||||
@@ -29,4 +29,4 @@ class HoverApp(App):
|
||||
await self.screen.dock(*hovers, edge="top")
|
||||
|
||||
|
||||
HoverApp.run(log="textual.log")
|
||||
HoverApp.run(log_path="textual.log")
|
||||
|
||||
@@ -12,4 +12,4 @@ class SimpleApp(App):
|
||||
await self.screen.dock(Placeholder(), Placeholder(), edge="top")
|
||||
|
||||
|
||||
SimpleApp.run(log="textual.log")
|
||||
SimpleApp.run(log_path="textual.log")
|
||||
|
||||
@@ -143,9 +143,9 @@ class BasicApp(App):
|
||||
|
||||
sandbox_folder = Path(__file__).parent
|
||||
app = BasicApp(
|
||||
css_file=sandbox_folder / "basic.css",
|
||||
css_path=sandbox_folder / "basic.css",
|
||||
watch_css=True,
|
||||
log=sandbox_folder / "textual.log",
|
||||
log_path=sandbox_folder / "basic.log",
|
||||
log_verbosity=0,
|
||||
)
|
||||
|
||||
|
||||
@@ -35,4 +35,4 @@ class SmoothApp(App):
|
||||
# self.set_timer(10, lambda: self.action("quit"))
|
||||
|
||||
|
||||
SmoothApp.run(log="textual.log", log_verbosity=2)
|
||||
SmoothApp.run(log_path="textual.log", log_verbosity=2)
|
||||
|
||||
@@ -30,4 +30,4 @@ class MyApp(App):
|
||||
await self.call_later(add_content)
|
||||
|
||||
|
||||
MyApp.run(title="Simple App", log="textual.log")
|
||||
MyApp.run(title="Simple App", log_path="textual.log")
|
||||
|
||||
@@ -55,4 +55,4 @@ class BordersApp(App):
|
||||
self.mount(borders=borders_view)
|
||||
|
||||
|
||||
BordersApp.run(css_file="borders.css", log="textual.log")
|
||||
BordersApp.run(css_path="borders.css", log_path="textual.log")
|
||||
|
||||
@@ -212,4 +212,4 @@ class CalculatorApp(App):
|
||||
await self.screen.dock(Calculator())
|
||||
|
||||
|
||||
CalculatorApp.run(title="Calculator Test", log="textual.log")
|
||||
CalculatorApp.run(title="Calculator Test", log_path="textual.log")
|
||||
|
||||
@@ -67,4 +67,4 @@ class MyApp(App):
|
||||
|
||||
|
||||
# Run our app class
|
||||
MyApp.run(title="Code Viewer", log="textual.log")
|
||||
MyApp.run(title="Code Viewer", log_path="textual.log")
|
||||
|
||||
@@ -42,4 +42,4 @@ class EasingApp(App):
|
||||
self.side = not self.side
|
||||
|
||||
|
||||
EasingApp().run(log="textual.log")
|
||||
EasingApp().run(log_path="textual.log")
|
||||
|
||||
@@ -31,4 +31,4 @@ class GridTest(App):
|
||||
)
|
||||
|
||||
|
||||
GridTest.run(title="Grid Test", log="textual.log")
|
||||
GridTest.run(title="Grid Test", log_path="textual.log")
|
||||
|
||||
@@ -19,4 +19,4 @@ class GridTest(App):
|
||||
grid.place(*placeholders, center=Placeholder())
|
||||
|
||||
|
||||
GridTest.run(title="Grid Test", log="textual.log")
|
||||
GridTest.run(title="Grid Test", log_path="textual.log")
|
||||
|
||||
@@ -48,4 +48,4 @@ class MyApp(App):
|
||||
await self.call_later(get_markdown, "richreadme.md")
|
||||
|
||||
|
||||
MyApp.run(title="Simple App", log="textual.log")
|
||||
MyApp.run(title="Simple App", log_path="textual.log")
|
||||
|
||||
@@ -22,4 +22,4 @@ class AlignApp(App):
|
||||
self.log(self.screen.tree)
|
||||
|
||||
|
||||
AlignApp.run(css_file="align.css", log="textual.log", watch_css=True)
|
||||
AlignApp.run(css_path="align.css", log_path="textual.log", watch_css=True)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
from pathlib import Path
|
||||
|
||||
from rich.align import Align
|
||||
from rich.console import RenderableType
|
||||
from rich.syntax import Syntax
|
||||
from rich.text import Text
|
||||
@@ -141,11 +138,10 @@ class BasicApp(App):
|
||||
self.panic(self.tree)
|
||||
|
||||
|
||||
sandbox_folder = Path(__file__).parent
|
||||
app = BasicApp(
|
||||
css_file=sandbox_folder / "basic.css",
|
||||
css_path="basic.css",
|
||||
watch_css=True,
|
||||
log=sandbox_folder / "textual.log",
|
||||
log_path="textual.log",
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -5,7 +5,6 @@ from textual import layout
|
||||
|
||||
|
||||
class ButtonsApp(App[str]):
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield layout.Vertical(
|
||||
Button("foo", id="foo"),
|
||||
@@ -19,7 +18,7 @@ class ButtonsApp(App[str]):
|
||||
self.exit(event.button.id)
|
||||
|
||||
|
||||
app = ButtonsApp(log="textual.log", log_verbosity=2)
|
||||
app = ButtonsApp(log_path="textual.log", log_verbosity=2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = app.run()
|
||||
|
||||
@@ -34,4 +34,4 @@ class BasicApp(App):
|
||||
self.panic(self.tree)
|
||||
|
||||
|
||||
BasicApp.run(css_file="dev_sandbox.scss", watch_css=True, log="textual.log")
|
||||
BasicApp.run(css_path="dev_sandbox.scss", watch_css=True, log_path="textual.log")
|
||||
|
||||
@@ -33,4 +33,4 @@ class BasicApp(App):
|
||||
self.log(header.styles)
|
||||
|
||||
|
||||
BasicApp.run(css_file="local_styles.css", log="textual.log")
|
||||
BasicApp.run(css_path="local_styles.css", log_path="textual.log")
|
||||
|
||||
@@ -144,4 +144,4 @@ class BasicApp(App):
|
||||
self.mount(example.widget)
|
||||
|
||||
|
||||
BasicApp.run(css_file="tabs.scss", watch_css=True, log="textual.log")
|
||||
BasicApp.run(css_path="tabs.scss", watch_css=True, log_path="textual.log")
|
||||
|
||||
@@ -83,7 +83,7 @@ class BasicApp(App):
|
||||
self.focused.styles.border_top = ("solid", "invalid-color")
|
||||
|
||||
|
||||
app = BasicApp(css_file="uber.css", log="textual.log", log_verbosity=1)
|
||||
app = BasicApp(css_path="uber.css", log_path="textual.log", log_verbosity=1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
|
||||
@@ -106,20 +106,20 @@ class App(Generic[ReturnType], DOMNode):
|
||||
def __init__(
|
||||
self,
|
||||
driver_class: Type[Driver] | None = None,
|
||||
log: str | PurePath = "",
|
||||
log_path: str | PurePath = "",
|
||||
log_verbosity: int = 1,
|
||||
title: str = "Textual Application",
|
||||
css_file: str | PurePath | None = None,
|
||||
css_path: str | PurePath | None = None,
|
||||
watch_css: bool = True,
|
||||
):
|
||||
"""Textual application base class
|
||||
|
||||
Args:
|
||||
driver_class (Type[Driver] | None, optional): Driver class or ``None`` to auto-detect. Defaults to None.
|
||||
log (str | PurePath, optional): Path to log file, or "" to disable. Defaults to "".
|
||||
log_path (str | PurePath, optional): Path to log file, or "" to disable. Defaults to "".
|
||||
log_verbosity (int, optional): Log verbosity from 0-3. Defaults to 1.
|
||||
title (str, optional): Default title of the application. Defaults to "Textual Application".
|
||||
css_file (str | PurePath | None, optional): Path to CSS or ``None`` for no CSS file. Defaults to None.
|
||||
css_path (str | PurePath | None, optional): Path to CSS or ``None`` for no CSS file. Defaults to None.
|
||||
watch_css (bool, optional): Watch CSS for changes. Defaults to True.
|
||||
"""
|
||||
# N.B. This must be done *before* we call the parent constructor, because MessagePump's
|
||||
@@ -151,8 +151,8 @@ class App(Generic[ReturnType], DOMNode):
|
||||
|
||||
self._log_console: Console | None = None
|
||||
self._log_file: TextIO | None = None
|
||||
if log:
|
||||
self._log_file = open(log, "wt")
|
||||
if log_path:
|
||||
self._log_file = open(log_path, "wt")
|
||||
self._log_console = Console(
|
||||
file=self._log_file,
|
||||
markup=False,
|
||||
@@ -171,10 +171,10 @@ class App(Generic[ReturnType], DOMNode):
|
||||
self.stylesheet = Stylesheet(variables=self.get_css_variables())
|
||||
self._require_styles_update = False
|
||||
|
||||
self.css_file = css_file
|
||||
self.css_path = css_path
|
||||
self.css_monitor = (
|
||||
FileMonitor(css_file, self._on_css_change)
|
||||
if (watch_css and css_file)
|
||||
FileMonitor(css_path, self._on_css_change)
|
||||
if (watch_css and css_path)
|
||||
else None
|
||||
)
|
||||
|
||||
@@ -450,13 +450,13 @@ class App(Generic[ReturnType], DOMNode):
|
||||
|
||||
async def _on_css_change(self) -> None:
|
||||
"""Called when the CSS changes (if watch_css is True)."""
|
||||
if self.css_file is not None:
|
||||
if self.css_path is not None:
|
||||
|
||||
try:
|
||||
time = perf_counter()
|
||||
self.stylesheet.read(self.css_file)
|
||||
self.stylesheet.read(self.css_path)
|
||||
elapsed = (perf_counter() - time) * 1000
|
||||
self.log(f"loaded {self.css_file} in {elapsed:.0f}ms")
|
||||
self.log(f"loaded {self.css_path} in {elapsed:.0f}ms")
|
||||
except Exception as error:
|
||||
# TODO: Catch specific exceptions
|
||||
self.console.bell()
|
||||
@@ -647,8 +647,8 @@ class App(Generic[ReturnType], DOMNode):
|
||||
except DevtoolsConnectionError:
|
||||
self.log(f"Couldn't connect to devtools ({self.devtools.url})")
|
||||
try:
|
||||
if self.css_file is not None:
|
||||
self.stylesheet.read(self.css_file)
|
||||
if self.css_path is not None:
|
||||
self.stylesheet.read(self.css_path)
|
||||
if self.CSS is not None:
|
||||
self.stylesheet.add_source(
|
||||
self.CSS, path=f"<{self.__class__.__name__}>"
|
||||
|
||||
@@ -36,8 +36,8 @@ def _check_selectors(selectors: list[Selector], node: DOMNode) -> bool:
|
||||
|
||||
DESCENDENT = CombinatorType.DESCENDENT
|
||||
|
||||
css_path = node.css_path
|
||||
path_count = len(css_path)
|
||||
css_path_nodes = node.css_path_nodes
|
||||
path_count = len(css_path_nodes)
|
||||
selector_count = len(selectors)
|
||||
|
||||
stack: list[tuple[int, int]] = [(0, 0)]
|
||||
@@ -51,7 +51,7 @@ def _check_selectors(selectors: list[Selector], node: DOMNode) -> bool:
|
||||
if selector_index == selector_count or node_index == path_count:
|
||||
pop()
|
||||
else:
|
||||
path_node = css_path[node_index]
|
||||
path_node = css_path_nodes[node_index]
|
||||
selector = selectors[selector_index]
|
||||
if selector.combinator == DESCENDENT:
|
||||
# Find a matching descendent
|
||||
|
||||
@@ -167,7 +167,7 @@ class DOMNode(MessagePump):
|
||||
return self.__class__.__name__.lower()
|
||||
|
||||
@property
|
||||
def css_path(self) -> list[DOMNode]:
|
||||
def css_path_nodes(self) -> list[DOMNode]:
|
||||
"""A list of nodes from the root to this node, forming a "path".
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -132,4 +132,4 @@ if __name__ == "__main__":
|
||||
async def on_mount(self, event: events.Mount) -> None:
|
||||
await self.screen.dock(DirectoryTree("/Users/willmcgugan/projects"))
|
||||
|
||||
TreeApp.run(log="textual.log")
|
||||
TreeApp(log_path="textual.log").run()
|
||||
|
||||
@@ -328,4 +328,4 @@ if __name__ == "__main__":
|
||||
else:
|
||||
await message.node.toggle()
|
||||
|
||||
TreeApp.run(log="textual.log")
|
||||
TreeApp(log_path="textual.log").run()
|
||||
|
||||
Reference in New Issue
Block a user