Remove draw.py, fix imports

This commit is contained in:
Darren Burns
2022-10-13 11:15:15 +01:00
parent 467700c759
commit 1b0c94e8a0
17 changed files with 15 additions and 354 deletions

View File

@@ -1,10 +0,0 @@
from enum import Enum
class DrawStyle(Enum):
NONE = "none"
ASCII = "ascii"
SQUARE = "square"
HEAVY = "heavy"
ROUNDED = "rounded"
DOUBLE = "double"

View File

@@ -1,9 +1,7 @@
from io import StringIO
import pytest
from textual.devtools.server import _make_devtools_aiohttp_app
from textual.devtools.client import DevtoolsClient
from textual.devtools.server import _make_devtools_aiohttp_app
from textual.devtools.service import DevtoolsService

View File

@@ -1,12 +1,12 @@
from datetime import datetime
import msgpack
import pytest
import time_machine
from rich.align import Align
from rich.console import Console
from rich.segment import Segment
import msgpack
from tests.utilities.render import wait_for_predicate
from textual.devtools.renderables import DevConsoleLog, DevConsoleNotice

View File

@@ -3,11 +3,11 @@ import types
from asyncio import Queue
from datetime import datetime
import msgpack
import time_machine
from aiohttp.web_ws import WebSocketResponse
from rich.console import ConsoleDimensions
from rich.panel import Panel
import msgpack
from tests.utilities.render import wait_for_predicate
from textual.devtools.client import DevtoolsClient

View File

@@ -1,10 +1,9 @@
import json
from contextlib import redirect_stdout
from datetime import datetime
import msgpack
import time_machine
import msgpack
from textual.devtools.redirect_output import StdoutRedirector
TIMESTAMP = 1649166819

View File

@@ -1,7 +1,7 @@
import pytest
from textual.layouts.vertical import VerticalLayout
from textual.layouts.factory import get_layout, MissingLayout
from textual.layouts.vertical import VerticalLayout
def test_get_layout_valid_layout():

View File

@@ -1,7 +1,7 @@
from rich.segment import Segment
from rich.style import Style
from textual._border import get_box, render_row
from textual._border import render_row
def test_border_render_row():

View File

@@ -8,7 +8,6 @@ import pytest
from textual._easing import EASING
POINTS = [
0.0,
0.05,

View File

@@ -1,325 +0,0 @@
from __future__ import annotations
from typing import cast, List, Sequence
import pytest
from rich.console import RenderableType
from rich.text import Text
from tests.utilities.test_app import AppTest
from textual.app import ComposeResult
from textual.css.types import EdgeType
from textual.geometry import Size
from textual.widget import Widget
from textual.widgets import Placeholder
pytestmark = pytest.mark.integration_test
# Let's allow ourselves some abbreviated names for those tests,
# in order to make the test cases a bit easier to read :-)
SCREEN_W = 100 # width of our Screens
SCREEN_H = 8 # height of our Screens
SCREEN_SIZE = Size(SCREEN_W, SCREEN_H)
PLACEHOLDERS_DEFAULT_H = 3 # the default height for our Placeholder widgets
# As per Widget's CSS property, by default Widgets have a horizontal scrollbar of size 1
# and a vertical scrollbar of size 2:
SCROLL_H_SIZE = 1
SCROLL_V_SIZE = 2
@pytest.mark.asyncio
@pytest.mark.parametrize(
(
"placeholders_count",
"root_container_style",
"placeholders_style",
"expected_root_widget_virtual_size",
"expected_placeholders_size",
"expected_placeholders_offset_x",
),
(
*[
[
1,
f"border: {invisible_border_edge};", # #root has no visible border
"", # no specific placeholder style
# #root's virtual size=screen size
(SCREEN_W, SCREEN_H),
# placeholders width=same than screen :: height=default height
(SCREEN_W, PLACEHOLDERS_DEFAULT_H),
# placeholders should be at offset 0
0,
]
for invisible_border_edge in ("", "none", "hidden")
],
[
1,
"border: solid white;", # #root has a visible border
"", # no specific placeholder style
# #root's virtual size is smaller because of its borders
(SCREEN_W - 2, SCREEN_H - 2),
# placeholders width=same than screen, minus 2 borders :: height=default height minus 2 borders
(SCREEN_W - 2, PLACEHOLDERS_DEFAULT_H),
# placeholders should be at offset 1 because of #root's border
1,
],
[
4,
"border: solid white;", # #root has a visible border
"", # no specific placeholder style
# #root's virtual height should be as high as its stacked content
(SCREEN_W - 2 - 1, PLACEHOLDERS_DEFAULT_H * 4),
# placeholders width=same than screen, minus 2 borders, minus scrollbar :: height=default height minus 2 borders
(SCREEN_W - 2 - SCROLL_V_SIZE, PLACEHOLDERS_DEFAULT_H),
# placeholders should be at offset 1 because of #root's border
1,
],
[
1,
"border: solid white;", # #root has a visible border
"align: center top;", # placeholders are centered horizontally
# #root's virtual size=screen size
(SCREEN_W, SCREEN_H),
# placeholders width=same than screen, minus 2 borders :: height=default height
(SCREEN_W - 2, PLACEHOLDERS_DEFAULT_H),
# placeholders should be at offset 1 because of #root's border
1,
],
[
4,
"border: solid white;", # #root has a visible border
"align: center top;", # placeholders are centered horizontally
# #root's virtual height should be as high as its stacked content
(
SCREEN_W - 2 - SCROLL_V_SIZE,
PLACEHOLDERS_DEFAULT_H * 4,
),
# placeholders width=same than screen, minus 2 borders, minus scrollbar :: height=default height
(SCREEN_W - 2 - SCROLL_V_SIZE, PLACEHOLDERS_DEFAULT_H),
# placeholders should be at offset 1 because of #root's border
1,
],
),
)
async def test_composition_of_vertical_container_with_children(
placeholders_count: int,
root_container_style: str,
placeholders_style: str,
expected_placeholders_size: tuple[int, int],
expected_root_widget_virtual_size: tuple[int, int],
expected_placeholders_offset_x: int,
):
class VerticalContainer(Widget):
DEFAULT_CSS = (
"""
VerticalContainer {
layout: vertical;
overflow: hidden auto;
${root_container_style}
}
VerticalContainer Placeholder {
height: ${placeholders_height};
${placeholders_style}
}
""".replace(
"${root_container_style}", root_container_style
)
.replace("${placeholders_height}", str(PLACEHOLDERS_DEFAULT_H))
.replace("${placeholders_style}", placeholders_style)
)
class MyTestApp(AppTest):
def compose(self) -> ComposeResult:
placeholders = [
Placeholder(id=f"placeholder_{i}", name=f"Placeholder #{i}")
for i in range(placeholders_count)
]
yield VerticalContainer(*placeholders, id="root")
app = MyTestApp(size=SCREEN_SIZE, test_name="compositor")
expected_screen_size = SCREEN_SIZE
async with app.in_running_state():
# root widget checks:
root_widget = cast(Widget, app.get_child("root"))
assert root_widget.outer_size == expected_screen_size
root_widget_region = app.screen.find_widget(root_widget).region
assert root_widget_region == (
0,
0,
expected_screen_size.width,
expected_screen_size.height,
)
app_placeholders = cast(List[Widget], app.query("Placeholder"))
assert len(app_placeholders) == placeholders_count
# placeholder widgets checks:
for placeholder in app_placeholders:
assert placeholder.outer_size == expected_placeholders_size
assert placeholder.styles.offset.x.value == 0.0
assert app.screen.get_offset(placeholder).x == expected_placeholders_offset_x
@pytest.mark.asyncio
@pytest.mark.parametrize(
"edge_type,expected_box_inner_size,expected_box_size,expected_top_left_edge_color,expects_visible_char_at_top_left_edge",
(
# These first 3 types of border edge types are synonyms, and display no borders:
["", Size(SCREEN_W, 1), Size(SCREEN_W, 1), "black", False],
["none", Size(SCREEN_W, 1), Size(SCREEN_W, 1), "black", False],
["hidden", Size(SCREEN_W, 1), Size(SCREEN_W, 1), "black", False],
# Let's transition to "blank": we still see no visible border, but the size is increased
# as the gutter space is reserved the same way it would be with a border:
["blank", Size(SCREEN_W - 2, 1), Size(SCREEN_W, 3), "#ffffff", False],
# And now for the "normally visible" border edge types:
# --> we see a visible border, and the size is increased:
*[
[edge_style, Size(SCREEN_W - 2, 1), Size(SCREEN_W, 3), "#ffffff", True]
for edge_style in [
"round",
"solid",
"double",
"dashed",
"heavy",
"inner",
"outer",
"hkey",
"vkey",
]
],
),
)
async def test_border_edge_types_impact_on_widget_size(
edge_type: EdgeType,
expected_box_inner_size: Size,
expected_box_size: Size,
expected_top_left_edge_color: str,
expects_visible_char_at_top_left_edge: bool,
):
class BorderTarget(Widget):
def render(self) -> RenderableType:
return Text("border target", style="black on yellow", justify="center")
border_target = BorderTarget()
border_target.styles.height = "auto"
border_target.styles.border = (edge_type, "white")
class MyTestApp(AppTest):
def compose(self) -> ComposeResult:
yield border_target
app = MyTestApp(size=SCREEN_SIZE, test_name="border_edge_types")
await app.boot_and_shutdown()
box_inner_size = Size(
border_target.content_region.width,
border_target.content_region.height,
)
assert box_inner_size == expected_box_inner_size
assert border_target.outer_size == expected_box_size
top_left_edge_style = app.screen.get_style_at(0, 0)
top_left_edge_color = top_left_edge_style.color.name
assert top_left_edge_color.upper() == expected_top_left_edge_color.upper()
top_left_edge_char = app.get_char_at(0, 0)
top_left_edge_char_is_a_visible_one = top_left_edge_char != " "
assert top_left_edge_char_is_a_visible_one == expects_visible_char_at_top_left_edge
@pytest.mark.asyncio
@pytest.mark.parametrize(
"large_widget_size,container_style,expected_large_widget_visible_region_size",
(
# In these tests we're going to insert a "large widget"
# into a container with size (20,20).
# ---------------- let's start!
# no overflow/scrollbar instructions: no scrollbars
[Size(30, 30), "color: red", Size(20, 20)],
# explicit hiding of the overflow: no scrollbars either
[Size(30, 30), "overflow: hidden", Size(20, 20)],
# scrollbar for both directions
[
Size(30, 30),
"overflow: auto",
Size(
20 - SCROLL_V_SIZE,
20 - SCROLL_H_SIZE,
),
],
# horizontal scrollbar
[Size(30, 30), "overflow-x: auto", Size(20, 20 - SCROLL_H_SIZE)],
# vertical scrollbar
[Size(30, 30), "overflow-y: auto", Size(20 - SCROLL_V_SIZE, 20)],
# scrollbar for both directions, custom scrollbar size
[Size(30, 30), ("overflow: auto", "scrollbar-size: 3 5"), Size(20 - 5, 20 - 3)],
# scrollbar for both directions, custom vertical scrollbar size
[
Size(30, 30),
("overflow: auto", "scrollbar-size-vertical: 3"),
Size(20 - 3, 20 - SCROLL_H_SIZE),
],
# scrollbar for both directions, custom horizontal scrollbar size
[
Size(30, 30),
("overflow: auto", "scrollbar-size-horizontal: 3"),
Size(20 - SCROLL_V_SIZE, 20 - 3),
],
# scrollbar needed only horizontally, custom scrollbar size
[
Size(30, 20),
("overflow: auto", "scrollbar-size: 3 3"),
Size(20, 20 - 3),
],
),
)
async def test_scrollbar_size_impact_on_the_layout(
large_widget_size: Size,
container_style: str | Sequence[str],
expected_large_widget_visible_region_size: Size,
):
class LargeWidget(Widget):
def on_mount(self):
self.styles.width = large_widget_size[0]
self.styles.height = large_widget_size[1]
container_style_rules = (
[container_style] if isinstance(container_style, str) else container_style
)
class LargeWidgetContainer(Widget):
# TODO: Once textual#581 ("Default versus User CSS") is solved the following CSS should just use the
# "LargeWidgetContainer" selector, without having to use a more specific one to be able to override Widget's CSS:
DEFAULT_CSS = """
#large-widget-container {
width: 20;
height: 20;
${container_style};
}
""".replace(
"${container_style}",
";\n".join(container_style_rules),
)
large_widget = LargeWidget()
large_widget.expand = False
container = LargeWidgetContainer(large_widget, id="large-widget-container")
class MyTestApp(AppTest):
def compose(self) -> ComposeResult:
yield container
app = MyTestApp(size=Size(40, 40), test_name="scrollbar_size_impact_on_the_layout")
await app.boot_and_shutdown()
compositor = app.screen._compositor
widgets_map = compositor.map
large_widget_visible_region_size = widgets_map[large_widget].visible_region.size
assert large_widget_visible_region_size == expected_large_widget_visible_region_size

View File

@@ -1,4 +1,5 @@
from __future__ import annotations
from typing import Sequence, cast
import pytest

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
from typing import NamedTuple
import pytest
from textual._layout_resolve import layout_resolve

View File

@@ -1,8 +1,8 @@
import pytest
from textual.geometry import Size
from textual.css.scalar import Scalar
from textual._resolve import resolve
from textual.css.scalar import Scalar
from textual.geometry import Size
def test_resolve_empty():

View File

@@ -5,7 +5,6 @@ import pytest
from textual.app import App, ScreenStackError
from textual.screen import Screen
skip_py310 = pytest.mark.skipif(
sys.version_info.minor == 10 and sys.version_info.major == 3,
reason="segfault on py3.10",

View File

@@ -1,7 +1,6 @@
from rich.segment import Segment
from rich.style import Style
from textual._segment_tools import line_crop, line_trim, line_pad

View File

@@ -3,11 +3,11 @@ from __future__ import annotations
from rich.segment import Segment
from rich.style import Style
from textual.color import Color
from textual.geometry import Region, Size
from textual.css.styles import Styles
from textual._styles_cache import StylesCache
from textual._types import Lines
from textual.color import Color
from textual.css.styles import Styles
from textual.geometry import Region, Size
def _extract_content(lines: Lines):

View File

@@ -1,5 +1,4 @@
import pytest
from rich.style import Style
from textual.app import App
from textual.css.errors import StyleValueError

View File

@@ -14,12 +14,13 @@ from rich.console import Console
from textual import events, errors
from textual._ansi_sequences import SYNC_START
from textual._clock import _Clock
from textual.app import WINDOWS
from textual._context import active_app
from textual.app import App, ComposeResult
from textual.app import WINDOWS
from textual.driver import Driver
from textual.geometry import Size, Region
# N.B. These classes would better be named TestApp/TestConsole/TestDriver/etc,
# but it makes pytest emit warning as it will try to collect them as classes containing test cases :-/