Merge branch 'main' into list-view

This commit is contained in:
Will McGugan
2022-12-09 10:09:07 +00:00
committed by GitHub
53 changed files with 2682 additions and 394 deletions

View File

@@ -0,0 +1,28 @@
import pytest
from textual.layouts.grid import GridLayout
from textual.layouts.horizontal import HorizontalLayout
from textual.layouts.vertical import VerticalLayout
from textual.geometry import Size
from textual.widget import Widget
LAYOUTS = [GridLayout, HorizontalLayout, VerticalLayout]
@pytest.mark.parametrize("layout", LAYOUTS)
def test_empty_widget_height(layout):
"""Test that an empty widget has height equal to 0."""
l = layout()
# Make sure this measurement does not depend on the width.
assert l.get_content_height(Widget(), Size(80, 24), Size(80, 24), 24) == 0
assert l.get_content_height(Widget(), Size(80, 24), Size(80, 24), 20) == 0
assert l.get_content_height(Widget(), Size(80, 24), Size(80, 24), 10) == 0
assert l.get_content_height(Widget(), Size(80, 24), Size(80, 24), 0) == 0
@pytest.mark.parametrize("layout", LAYOUTS)
def test_empty_widget_width(layout):
"""Test that an empty widget has width equal to 0."""
l = layout()
assert l.get_content_width(Widget(), Size(80, 24), Size(80, 24)) == 0

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,37 @@
from textual.app import App, ComposeResult
from textual.containers import Horizontal
from textual.widgets import Static
class HeightApp(App[None]):
CSS = """
Horizontal {
border: solid red;
height: auto;
}
Static {
border: solid green;
width: auto;
}
#fill_parent {
height: 100%;
}
#static {
height: 16;
}
"""
def compose(self) -> ComposeResult:
yield Horizontal(
Static("As tall as container", id="fill_parent"),
Static("This has default\nheight\nbut a\nfew lines"),
Static("I have a static height", id="static"),
)
if __name__ == "__main__":
HeightApp().run()

View File

@@ -0,0 +1,41 @@
from textual.app import App, ComposeResult
from textual.containers import Vertical
from textual.widgets import Label, Static
class Box(Static):
DEFAULT_CSS = """
Box {
border: solid white;
background: darkblue;
width: 16;
height: auto;
}
"""
def compose(self) -> ComposeResult:
yield Label("FOO\nBAR\nBAZ")
class OffsetsApp(App):
CSS = """
#box1 {
offset: 5 5;
}
#box2 {
offset: 15 10;
}
"""
def compose(self) -> ComposeResult:
yield Box(id="box1")
yield Box(id="box2")
if __name__ == "__main__":
app = OffsetsApp()
app.run()

View File

@@ -0,0 +1,75 @@
from textual.app import App, ComposeResult
from textual.screen import Screen
from textual.widgets import Header, Footer, Label
from textual.containers import Vertical, Container
class Overlay(Container):
def compose(self) -> ComposeResult:
yield Label("This should float over the top")
class Body1(Vertical):
def compose(self) -> ComposeResult:
yield Label("My God! It's full of stars! " * 300)
class Body2(Vertical):
def compose(self) -> ComposeResult:
yield Label("My God! It's full of stars! " * 300)
class Good(Screen):
def compose(self) -> ComposeResult:
yield Header()
yield Overlay()
yield Body1()
yield Footer()
class Bad(Screen):
def compose(self) -> ComposeResult:
yield Overlay()
yield Header()
yield Body2()
yield Footer()
class Layers(App[None]):
CSS = """
Screen {
layers: base higher;
}
Overlay {
layer: higher;
dock: top;
width: auto;
height: auto;
padding: 2;
border: solid yellow;
background: red;
color: yellow;
}
Body2 {
background: green;
}
"""
SCREENS = {"good": Good, "bad": Bad}
BINDINGS = [("t", "toggle", "Toggle Screen")]
def on_mount(self):
self.push_screen("good")
def action_toggle(self):
self.switch_screen(
"bad" if self.screen.__class__.__name__ == "Good" else "good"
)
if __name__ == "__main__":
Layers().run()

View File

@@ -0,0 +1,48 @@
from textual.app import App
from textual.containers import Vertical
from textual.widgets import Static
class Visibility(App):
"""Check that visibility: hidden also makes children invisible;"""
CSS = """
Screen {
layout: horizontal;
}
Vertical {
width: 1fr;
border: solid red;
}
#container1 {
visibility: hidden;
}
.float {
border: solid blue;
}
/* Make a child of a hidden widget visible again */
#container1 .float {
visibility: visible;
}
"""
def compose(self):
yield Vertical(
Static("foo"),
Static("float", classes="float"),
id="container1",
)
yield Vertical(
Static("bar"),
Static("float", classes="float"),
id="container2",
)
if __name__ == "__main__":
app = Visibility()
app.run()

View File

@@ -2,6 +2,8 @@ from pathlib import Path
import pytest
from textual.widgets import Placeholder
# These paths should be relative to THIS directory.
WIDGET_EXAMPLES_DIR = Path("../../docs/examples/widgets")
LAYOUT_EXAMPLES_DIR = Path("../../docs/examples/guide/layout")
@@ -79,6 +81,12 @@ def test_buttons_render(snap_compare):
assert snap_compare(WIDGET_EXAMPLES_DIR / "button.py", press=["tab"])
def test_placeholder_render(snap_compare):
# Testing the rendering of the multiple placeholder variants and labels.
Placeholder.reset_color_cycle()
assert snap_compare(WIDGET_EXAMPLES_DIR / "placeholder.py")
def test_datatable_render(snap_compare):
press = ["tab", "down", "down", "right", "up", "left"]
assert snap_compare(WIDGET_EXAMPLES_DIR / "data_table.py", press=press)
@@ -104,6 +112,10 @@ def test_fr_units(snap_compare):
assert snap_compare("snapshot_apps/fr_units.py")
def test_visibility(snap_compare):
assert snap_compare("snapshot_apps/visibility.py")
def test_tree_example(snap_compare):
assert snap_compare(WIDGET_EXAMPLES_DIR / "tree.py")
@@ -130,8 +142,31 @@ def test_multiple_css(snap_compare):
assert snap_compare("snapshot_apps/multiple_css/multiple_css.py")
def test_order_independence(snap_compare):
assert snap_compare("snapshot_apps/order_independence.py")
def test_order_independence_toggle(snap_compare):
assert snap_compare("snapshot_apps/order_independence.py", press="t,_")
def test_columns_height(snap_compare):
# Interaction with height auto, and relative heights to make columns
assert snap_compare("snapshot_apps/columns_height.py")
def test_offsets(snap_compare):
"""Test offsets of containers"""
assert snap_compare("snapshot_apps/offsets.py")
# --- Other ---
def test_key_display(snap_compare):
assert snap_compare(SNAPSHOT_APPS_DIR / "key_display.py")
def test_demo(snap_compare):
"""Test the demo app (python -m textual)"""
assert snap_compare(Path("../../src/textual/demo.py"))

View File

@@ -100,7 +100,7 @@ def test_width():
def test_height():
"""Test width settings."""
"""Test height settings."""
styles = Styles()
one = Fraction(1)
@@ -123,7 +123,7 @@ def test_height():
)
assert box_model == BoxModel(Fraction(54), Fraction(16), Spacing(1, 2, 3, 4))
# Set width to 100 vw which should make it the width of the parent
# Set height to 100 vw which should make it the height of the parent
styles.height = "100vh"
box_model = get_box_model(
@@ -131,7 +131,7 @@ def test_height():
)
assert box_model == BoxModel(Fraction(54), Fraction(24), Spacing(1, 2, 3, 4))
# Set the width to 100% should make it fill the container size
# Set the height to 100% should make it fill the container size
styles.height = "100%"
box_model = get_box_model(
@@ -156,6 +156,14 @@ def test_height():
)
assert box_model == BoxModel(Fraction(54), Fraction(10), Spacing(1, 2, 3, 4))
# Set height to auto and set content height to 0 to check if box collapses.
styles.height = "auto"
box_model = get_box_model(
styles, Size(60, 20), Size(80, 24), one, one, get_auto_width, lambda *_: 0
)
assert box_model == BoxModel(Fraction(54), Fraction(0), Spacing(1, 2, 3, 4))
def test_max():
"""Check that max_width and max_height are respected."""

15
tests/test_placeholder.py Normal file
View File

@@ -0,0 +1,15 @@
import pytest
from textual.widgets import Placeholder
from textual.widgets._placeholder import InvalidPlaceholderVariant
def test_invalid_placeholder_variant():
with pytest.raises(InvalidPlaceholderVariant):
Placeholder(variant="this is clearly not a valid variant!")
def test_invalid_reactive_variant_change():
p = Placeholder()
with pytest.raises(InvalidPlaceholderVariant):
p.variant = "this is clearly not a valid variant!"