mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Merge pull request #985 from Textualize/query-parse
Add sensible error to query
This commit is contained in:
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [0.2.2] - Unreleased
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- DOMQuery now raises InvalidQueryFormat in response to invalid query strings, rather than cryptic CSS error
|
||||||
|
|
||||||
## [0.2.1] - 2022-10-23
|
## [0.2.1] - 2022-10-23
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ class CalculatorApp(App):
|
|||||||
"plus_minus_sign": "plus-minus",
|
"plus_minus_sign": "plus-minus",
|
||||||
"percent_sign": "percent",
|
"percent_sign": "percent",
|
||||||
"equals_sign": "equals",
|
"equals_sign": "equals",
|
||||||
"enter": "equals",
|
"minus": "minus",
|
||||||
|
"plus": "plus",
|
||||||
}
|
}
|
||||||
|
|
||||||
def watch_numbers(self, value: str) -> None:
|
def watch_numbers(self, value: str) -> None:
|
||||||
@@ -80,7 +81,6 @@ class CalculatorApp(App):
|
|||||||
self.query_one(f"#{button_id}", Button).press()
|
self.query_one(f"#{button_id}", Button).press()
|
||||||
except NoMatches:
|
except NoMatches:
|
||||||
pass
|
pass
|
||||||
self.set_focus(None)
|
|
||||||
|
|
||||||
key = event.key
|
key = event.key
|
||||||
if key.isdecimal():
|
if key.isdecimal():
|
||||||
@@ -89,7 +89,9 @@ class CalculatorApp(App):
|
|||||||
press("c")
|
press("c")
|
||||||
press("ac")
|
press("ac")
|
||||||
else:
|
else:
|
||||||
press(self.NAME_MAP.get(key, key))
|
button_id = self.NAME_MAP.get(key)
|
||||||
|
if button_id is not None:
|
||||||
|
press(self.NAME_MAP.get(key, key))
|
||||||
|
|
||||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
"""Called when a button is pressed."""
|
"""Called when a button is pressed."""
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from typing import cast, Generic, TYPE_CHECKING, Iterator, TypeVar, overload
|
|||||||
|
|
||||||
import rich.repr
|
import rich.repr
|
||||||
|
|
||||||
from .errors import DeclarationError
|
from .errors import DeclarationError, TokenError
|
||||||
from .match import match
|
from .match import match
|
||||||
from .model import SelectorSet
|
from .model import SelectorSet
|
||||||
from .parse import parse_declarations, parse_selectors
|
from .parse import parse_declarations, parse_selectors
|
||||||
@@ -34,6 +34,10 @@ class QueryError(Exception):
|
|||||||
"""Base class for a query related error."""
|
"""Base class for a query related error."""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidQueryFormat(QueryError):
|
||||||
|
"""Query did not parse correctly."""
|
||||||
|
|
||||||
|
|
||||||
class NoMatches(QueryError):
|
class NoMatches(QueryError):
|
||||||
"""No nodes matched the query."""
|
"""No nodes matched the query."""
|
||||||
|
|
||||||
@@ -72,9 +76,17 @@ class DOMQuery(Generic[QueryType]):
|
|||||||
parent._excludes.copy() if parent else []
|
parent._excludes.copy() if parent else []
|
||||||
)
|
)
|
||||||
if filter is not None:
|
if filter is not None:
|
||||||
self._filters.append(parse_selectors(filter))
|
try:
|
||||||
|
self._filters.append(parse_selectors(filter))
|
||||||
|
except TokenError:
|
||||||
|
# TODO: More helpful errors
|
||||||
|
raise InvalidQueryFormat(f"Unable to parse filter {filter!r} as query")
|
||||||
|
|
||||||
if exclude is not None:
|
if exclude is not None:
|
||||||
self._excludes.append(parse_selectors(exclude))
|
try:
|
||||||
|
self._excludes.append(parse_selectors(exclude))
|
||||||
|
except TokenError:
|
||||||
|
raise InvalidQueryFormat(f"Unable to parse filter {filter!r} as query")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def node(self) -> DOMNode:
|
def node(self) -> DOMNode:
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
from textual.widget import Widget
|
from textual.widget import Widget
|
||||||
|
from textual.css.query import InvalidQueryFormat
|
||||||
|
|
||||||
|
|
||||||
def test_query():
|
def test_query():
|
||||||
@@ -78,3 +81,16 @@ def test_query():
|
|||||||
assert list(app.query("#widget1, #widget2")) == [widget1, widget2]
|
assert list(app.query("#widget1, #widget2")) == [widget1, widget2]
|
||||||
assert list(app.query("#widget1 , #widget2")) == [widget1, widget2]
|
assert list(app.query("#widget1 , #widget2")) == [widget1, widget2]
|
||||||
assert list(app.query("#widget1, #widget2, App")) == [app, widget1, widget2]
|
assert list(app.query("#widget1, #widget2, App")) == [app, widget1, widget2]
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_query():
|
||||||
|
class App(Widget):
|
||||||
|
pass
|
||||||
|
|
||||||
|
app = App()
|
||||||
|
|
||||||
|
with pytest.raises(InvalidQueryFormat):
|
||||||
|
app.query("#3")
|
||||||
|
|
||||||
|
with pytest.raises(InvalidQueryFormat):
|
||||||
|
app.query("#foo").exclude("#2")
|
||||||
|
|||||||
Reference in New Issue
Block a user