test fixes, tests for partition

This commit is contained in:
Will McGugan
2022-07-27 15:37:33 +01:00
parent 90de092fd5
commit 1abe8f933d
11 changed files with 21 additions and 481 deletions

View File

@@ -1,231 +0,0 @@
/* CSS file for basic.py */
* {
transition: color 300ms linear, background 300ms linear;
}
* {
scrollbar-background: $panel-darken-2;
scrollbar-background-hover: $panel-darken-3;
scrollbar-color: $system;
scrollbar-color-active: $accent-darken-1;
scrollbar-size-horizontal: 1;
scrollbar-size-vertical: 2;
}
App > Screen {
layout: dock;
docks: side=left/1;
background: $surface;
color: $text-surface;
}
#sidebar {
color: $text-primary;
background: $primary-background;
dock: side;
width: 30;
offset-x: -100%;
layout: dock;
transition: offset 500ms in_out_cubic;
}
#sidebar.-active {
offset-x: 0;
}
#sidebar .title {
height: 3;
background: $primary-background-darken-2;
color: $text-primary-darken-2 ;
border-right: outer $primary-darken-3;
content-align: center middle;
}
#sidebar .user {
height: 8;
background: $primary-background-darken-1;
color: $text-primary-darken-1;
border-right: outer $primary-background-darken-3;
content-align: center middle;
}
#sidebar .content {
background: $primary-background;
color: $text-primary-background;
border-right: outer $primary-background-darken-3;
content-align: center middle;
}
#header {
color: $text-primary-darken-1;
background: $primary-darken-1;
height: 3;
content-align: center middle;
}
#content {
color: $text-background;
background: $background;
layout: vertical;
overflow-y: scroll;
}
Tweet {
height:12;
width: 100%;
margin: 1 3;
background: $panel;
color: $text-panel;
layout: vertical;
/* border: outer $primary; */
padding: 1;
border: wide $panel-darken-2;
overflow: auto;
/* scrollbar-gutter: stable; */
align-horizontal: center;
box-sizing: border-box;
}
.scrollable {
overflow-y: scroll;
margin: 1 2;
height: 20;
align-horizontal: center;
layout: vertical;
}
.code {
height: auto;
}
TweetHeader {
height:1;
background: $accent;
color: $text-accent
}
TweetBody {
width: 100%;
background: $panel;
color: $text-panel;
height: auto;
padding: 0 1 0 0;
}
Tweet.scroll-horizontal TweetBody {
width: 350;
}
.button {
background: $accent;
color: $text-accent;
width:20;
height: 3;
/* border-top: hidden $accent-darken-3; */
border: tall $accent-darken-2;
/* border-left: tall $accent-darken-1; */
/* padding: 1 0 0 0 ; */
transition: background 400ms in_out_cubic, color 400ms in_out_cubic;
}
.button:hover {
background: $accent-lighten-1;
color: $text-accent-lighten-1;
width: 20;
height: 3;
border: tall $accent-darken-1;
/* border-left: tall $accent-darken-3; */
}
#footer {
color: $text-accent;
background: $accent;
height: 1;
border-top: hkey $accent-darken-2;
content-align: center middle;
}
#sidebar .content {
layout: vertical
}
OptionItem {
height: 3;
background: $primary-background;
border-right: outer $primary-background-darken-2;
border-left: blank;
content-align: center middle;
}
OptionItem:hover {
height: 3;
color: $accent;
background: $primary-background-darken-1;
/* border-top: hkey $accent2-darken-3;
border-bottom: hkey $accent2-darken-3; */
text-style: bold;
border-left: outer $accent-darken-2;
}
Error {
width: 100%;
height:3;
background: $error;
color: $text-error;
border-top: hkey $error-darken-2;
border-bottom: hkey $error-darken-2;
margin: 1 3;
text-style: bold;
align-horizontal: center;
}
Warning {
width: 100%;
height:3;
background: $warning;
color: $text-warning-fade-1;
border-top: hkey $warning-darken-2;
border-bottom: hkey $warning-darken-2;
margin: 1 2;
text-style: bold;
align-horizontal: center;
}
Success {
width: 100%;
height:3;
box-sizing: border-box;
background: $success-lighten-3;
color: $text-success-lighten-3-fade-1;
border-top: hkey $success;
border-bottom: hkey $success;
margin: 1 2;
text-style: bold;
align-horizontal: center;
}
.horizontal {
layout: horizontal
}

View File

@@ -1,185 +0,0 @@
from rich.console import RenderableType
from rich.style import Style
from rich.syntax import Syntax
from rich.text import Text
from textual.app import App
from textual.reactive import Reactive
from textual.widget import Widget
from textual.widgets import Static
CODE = '''
class Offset(NamedTuple):
"""A point defined by x and y coordinates."""
x: int = 0
y: int = 0
@property
def is_origin(self) -> bool:
"""Check if the point is at the origin (0, 0)"""
return self == (0, 0)
def __bool__(self) -> bool:
return self != (0, 0)
def __add__(self, other: object) -> Offset:
if isinstance(other, tuple):
_x, _y = self
x, y = other
return Offset(_x + x, _y + y)
return NotImplemented
def __sub__(self, other: object) -> Offset:
if isinstance(other, tuple):
_x, _y = self
x, y = other
return Offset(_x - x, _y - y)
return NotImplemented
def __mul__(self, other: object) -> Offset:
if isinstance(other, (float, int)):
x, y = self
return Offset(int(x * other), int(y * other))
return NotImplemented
'''
lorem_short = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. In velit liber a a a, volutpat nec hendrerit at, faucibus in odio. Aliquam hendrerit nibh sed quam volutpat maximus. Nullam suscipit convallis lorem quis sodales. In tristique lobortis ante et dictum. Ut at finibus ipsum."""
lorem = (
lorem_short
+ """ In urna dolor, placerat et mi facilisis, congue sollicitudin massa. Phasellus felis turpis, cursus eu lectus et, porttitor malesuada augue. Sed feugiat volutpat velit, sollicitudin fringilla velit bibendum faucibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In velit libero, volutpat nec hendrerit at, faucibus in odio. Aliquam hendrerit nibh sed quam volutpat maximus. Nullam suscipit convallis lorem quis sodales. In tristique lobortis ante et dictum. Ut at finibus ipsum. In urna dolor, placerat et mi facilisis, congue sollicitudin massa. Phasellus felis turpis, cursus eu lectus et, porttitor malesuada augue. Sed feugiat volutpat velit, sollicitudin fringilla velit bibendum faucibus. """
)
lorem_short_text = Text.from_markup(lorem_short)
lorem_long_text = Text.from_markup(lorem * 2)
class TweetHeader(Widget):
def render(self) -> RenderableType:
return Text("Lorem Impsum", justify="center")
class TweetBody(Widget):
short_lorem = Reactive(False)
def render(self) -> Text:
return lorem_short_text if self.short_lorem else lorem_long_text
class Tweet(Widget):
pass
class OptionItem(Widget):
def render(self) -> Text:
return Text("Option")
class Error(Widget):
def render(self) -> Text:
return Text("This is an error message", justify="center")
class Warning(Widget):
def render(self) -> Text:
return Text("This is a warning message", justify="center")
class Success(Widget):
def render(self) -> Text:
return Text("This is a success message", justify="center")
class BasicApp(App, css_path="basic.css"):
"""A basic app demonstrating CSS"""
def on_load(self):
"""Bind keys here."""
self.bind("s", "toggle_class('#sidebar', '-active')")
def on_mount(self):
"""Build layout here."""
self.scroll_to_target = Tweet(TweetBody())
self.mount(
header=Static(
Text.from_markup(
"[b]This is a [u]Textual[/u] app, running in the terminal"
),
),
content=Widget(
Tweet(TweetBody()),
Widget(
Static(Syntax(CODE, "python"), classes="code"),
classes="scrollable",
),
Error(),
Tweet(TweetBody(), classes="scrollbar-size-custom"),
Warning(),
Tweet(TweetBody(), classes="scroll-horizontal"),
Success(),
Tweet(TweetBody(), classes="scroll-horizontal"),
Tweet(TweetBody(), classes="scroll-horizontal"),
Tweet(TweetBody(), classes="scroll-horizontal"),
Tweet(TweetBody(), classes="scroll-horizontal"),
Tweet(TweetBody(), classes="scroll-horizontal"),
),
footer=Widget(),
sidebar=Widget(
Widget(classes="title"),
Widget(classes="user"),
OptionItem(),
OptionItem(),
OptionItem(),
Widget(classes="content"),
),
)
async def on_key(self, event) -> None:
await self.dispatch_key(event)
def key_d(self):
self.dark = not self.dark
async def key_q(self):
await self.shutdown()
def key_x(self):
self.panic(self.tree)
def key_escape(self):
self.app.bell()
def key_t(self):
# Pressing "t" toggles the content of the TweetBody widget, from a long "Lorem ipsum..." to a shorter one.
tweet_body = self.query("TweetBody").first()
tweet_body.short_lorem = not tweet_body.short_lorem
def key_v(self):
self.get_child(id="content").scroll_to_widget(self.scroll_to_target)
def key_space(self):
self.bell()
app = BasicApp()
if __name__ == "__main__":
app.run()
from textual.geometry import Region
from textual.color import Color
print(Region.intersection.cache_info())
print(Region.overlaps.cache_info())
print(Region.union.cache_info())
print(Region.split_vertical.cache_info())
print(Region.__contains__.cache_info())
from textual.css.scalar import Scalar
print(Scalar.resolve_dimension.cache_info())
from rich.style import Style
print(Style._add.cache_info())

View File

@@ -1,50 +0,0 @@
def partition_will(pred, values):
if not values:
return [], []
if len(values) == 1:
return ([], values) if pred(values[0]) else (values, [])
values = sorted(values, key=pred)
lower = 0
upper = len(values) - 1
index = (lower + upper) // 2
while True:
value = pred(values[index])
if value and not pred(values[index - 1]):
return values[:index], values[index:]
if value:
upper = index
else:
lower = index
index = (lower + upper) // 2
def partition_more_iter(pred, iterable):
"""
Returns a 2-tuple of iterables derived from the input iterable.
The first yields the items that have ``pred(item) == False``.
The second yields the items that have ``pred(item) == True``.
>>> is_odd = lambda x: x % 2 != 0
>>> iterable = range(10)
>>> even_items, odd_items = partition(is_odd, iterable)
>>> list(even_items), list(odd_items)
([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
If *pred* is None, :func:`bool` is used.
>>> iterable = [0, 1, False, True, '', ' ']
>>> false_items, true_items = partition(None, iterable)
>>> list(false_items), list(true_items)
([0, False, ''], [1, True, ' '])
"""
if pred is None:
pred = bool
evaluations = ((pred(x), x) for x in iterable)
t1, t2 = tee(evaluations)
return (
(x for (cond, x) in t1 if not cond),
(x for (cond, x) in t2 if cond),
)

View File

@@ -167,7 +167,7 @@ class Color(NamedTuple):
"""This color encoded in Rich's Color class.""" """This color encoded in Rich's Color class."""
r, g, b, _a = self r, g, b, _a = self
return RichColor( return RichColor(
f"#{r:02X}{g:02X}{b:02X}", _TRUECOLOR, None, ColorTriplet(r, g, b) f"#{r:02x}{g:02x}{b:02x}", _TRUECOLOR, None, ColorTriplet(r, g, b)
) )
@property @property

View File

@@ -98,12 +98,6 @@ def test_docks_property_help_text(styling_context):
assert "docks" in rendered assert "docks" in rendered
def test_dock_property_help_text(styling_context):
rendered = render(dock_property_help_text("dock", styling_context))
assert "Invalid value for" in rendered
assert "dock" in rendered
def test_fractional_property_help_text(styling_context): def test_fractional_property_help_text(styling_context):
rendered = render(fractional_property_help_text("opacity", styling_context)) rendered = render(fractional_property_help_text("opacity", styling_context))
assert "Invalid value for" in rendered assert "Invalid value for" in rendered

View File

@@ -12,7 +12,7 @@ from textual.css.tokenize import tokenize
from textual.css.tokenizer import Token, ReferencedBy from textual.css.tokenizer import Token, ReferencedBy
from textual.css.transition import Transition from textual.css.transition import Transition
from textual.geometry import Spacing from textual.geometry import Spacing
from textual.layouts.dock import DockLayout from textual.layouts.vertical import VerticalLayout
class TestVariableReferenceSubstitution: class TestVariableReferenceSubstitution:
@@ -861,13 +861,13 @@ class TestVariableReferenceSubstitution:
class TestParseLayout: class TestParseLayout:
def test_valid_layout_name(self): def test_valid_layout_name(self):
css = "#some-widget { layout: dock; }" css = "#some-widget { layout: vertical; }"
stylesheet = Stylesheet() stylesheet = Stylesheet()
stylesheet.add_source(css) stylesheet.add_source(css)
styles = stylesheet.rules[0].styles styles = stylesheet.rules[0].styles
assert isinstance(styles.layout, DockLayout) assert isinstance(styles.layout, VerticalLayout)
def test_invalid_layout_name(self): def test_invalid_layout_name(self):
css = "#some-widget { layout: invalidlayout; }" css = "#some-widget { layout: invalidlayout; }"

View File

@@ -7,10 +7,8 @@ from textual.widget import Widget
@pytest.mark.parametrize( @pytest.mark.parametrize(
"layout,display,expected_in_displayed_children", "layout,display,expected_in_displayed_children",
[ [
("dock", "block", True),
("horizontal", "block", True), ("horizontal", "block", True),
("vertical", "block", True), ("vertical", "block", True),
("dock", "none", False),
("horizontal", "none", False), ("horizontal", "none", False),
("vertical", "none", False), ("vertical", "none", False),
], ],

View File

@@ -137,7 +137,7 @@ def test_height():
box_model = get_box_model( box_model = get_box_model(
styles, Size(60, 20), Size(80, 24), one, get_auto_width, get_auto_height styles, Size(60, 20), Size(80, 24), one, get_auto_width, get_auto_height
) )
assert box_model == BoxModel(Fraction(54), Fraction(20), Spacing(1, 2, 3, 4)) assert box_model == BoxModel(Fraction(54), Fraction(16), Spacing(1, 2, 3, 4))
styles.height = "auto" styles.height = "auto"
styles.margin = 2 styles.margin = 2

View File

@@ -228,7 +228,7 @@ async def test_border_edge_types_impact_on_widget_size(
top_left_edge_style = app.screen.get_style_at(0, 0) top_left_edge_style = app.screen.get_style_at(0, 0)
top_left_edge_color = top_left_edge_style.color.name top_left_edge_color = top_left_edge_style.color.name
assert top_left_edge_color == expected_top_left_edge_color 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 = app.get_char_at(0, 0)
top_left_edge_char_is_a_visible_one = top_left_edge_char != " " top_left_edge_char_is_a_visible_one = top_left_edge_char != " "

15
tests/test_partition.py Normal file
View File

@@ -0,0 +1,15 @@
from textual._partition import partition
def test_partition():
def is_odd(value: int) -> bool:
return bool(value % 2)
assert partition(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) == (
[2, 4, 6, 8, 10],
[1, 3, 5, 7, 9],
)
assert partition(is_odd, [1, 2]) == ([2], [1])
assert partition(is_odd, [1]) == ([], [1])
assert partition(is_odd, []) == ([], [])

View File

@@ -1,6 +1,5 @@
import pytest import pytest
from textual.layouts.dock import DockLayout
from textual.layouts.grid import GridLayout from textual.layouts.grid import GridLayout
from textual.layouts.horizontal import HorizontalLayout from textual.layouts.horizontal import HorizontalLayout
from textual.layouts.vertical import VerticalLayout from textual.layouts.vertical import VerticalLayout