-
Notifications
You must be signed in to change notification settings - Fork 819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add read-only access to the children of a TreeNode
#1495
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
30d5c1e
Add a generic immutable sequence wrapper class
davep 7779211
Add read-only access to the children of a TreeNode
davep f9e0062
Simplify ImmutableSequence.__bool__
davep 8d5ea89
Focus less on it being a list and more a thing that's wrapped
davep 83c0ef7
Only convert to an indexable sequence if absolutely necessary
davep a15fa7f
Tweak the unit tests for ImmutableSequence
davep e5869b9
Merge branch 'main' into tree-node-children-prop
davep 71cc1bc
Rename ImmutableSequence to ImmutableSequenceView
davep 395ed4b
Correct docstring for the return type of index
davep 0217462
Add support for star/stop values on index
davep File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
"""Provides an immutable sequence view class.""" | ||
|
||
from __future__ import annotations | ||
from sys import maxsize | ||
from typing import Generic, TypeVar, Iterator, overload, Sequence | ||
|
||
T = TypeVar("T") | ||
|
||
|
||
class ImmutableSequenceView(Generic[T]): | ||
"""Class to wrap a sequence of some sort, but not allow modification.""" | ||
|
||
def __init__(self, wrap: Sequence[T]) -> None: | ||
"""Initialise the immutable sequence. | ||
|
||
Args: | ||
wrap (Sequence[T]): The sequence being wrapped. | ||
""" | ||
self._wrap = wrap | ||
|
||
@overload | ||
def __getitem__(self, index: int) -> T: | ||
... | ||
|
||
@overload | ||
def __getitem__(self, index: slice) -> ImmutableSequenceView[T]: | ||
... | ||
|
||
def __getitem__(self, index: int | slice) -> T | ImmutableSequenceView[T]: | ||
return ( | ||
self._wrap[index] | ||
if isinstance(index, int) | ||
else ImmutableSequenceView[T](self._wrap[index]) | ||
) | ||
|
||
def __iter__(self) -> Iterator[T]: | ||
return iter(self._wrap) | ||
|
||
def __len__(self) -> int: | ||
return len(self._wrap) | ||
|
||
def __length_hint__(self) -> int: | ||
return len(self) | ||
|
||
def __bool__(self) -> bool: | ||
return bool(self._wrap) | ||
|
||
def __contains__(self, item: T) -> bool: | ||
return item in self._wrap | ||
|
||
def index(self, item: T, start: int = 0, stop: int = maxsize) -> int: | ||
"""Return the index of the given item. | ||
|
||
Args: | ||
item (T): The item to find in the sequence. | ||
start (int, optional): Optional start location. | ||
stop (int, optional): Optional stop location. | ||
|
||
Returns: | ||
T: The index of the item in the sequence. | ||
|
||
Raises: | ||
ValueError: If the item is not in the sequence. | ||
""" | ||
return self._wrap.index(item, start, stop) | ||
|
||
def __reversed__(self) -> Iterator[T]: | ||
return reversed(self._wrap) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import pytest | ||
|
||
from typing import Sequence | ||
from textual._immutable_sequence_view import ImmutableSequenceView | ||
|
||
def wrap(source: Sequence[int]) -> ImmutableSequenceView[int]: | ||
"""Wrap a sequence of integers inside an immutable sequence view.""" | ||
return ImmutableSequenceView[int](source) | ||
|
||
|
||
def test_empty_immutable_sequence() -> None: | ||
"""An empty immutable sequence should act as anticipated.""" | ||
assert len(wrap([])) == 0 | ||
assert bool(wrap([])) is False | ||
assert list(wrap([])) == [] | ||
|
||
|
||
def test_non_empty_immutable_sequence() -> None: | ||
"""A non-empty immutable sequence should act as anticipated.""" | ||
assert len(wrap([0])) == 1 | ||
assert bool(wrap([0])) is True | ||
assert list(wrap([0])) == [0] | ||
|
||
|
||
def test_no_assign_to_immutable_sequence() -> None: | ||
"""It should not be possible to assign into an immutable sequence.""" | ||
tester = wrap([1,2,3,4,5]) | ||
with pytest.raises(TypeError): | ||
tester[0] = 23 | ||
with pytest.raises(TypeError): | ||
tester[0:3] = 23 | ||
|
||
|
||
def test_no_del_from_iummutable_sequence() -> None: | ||
"""It should not be possible delete an item from an immutable sequence.""" | ||
tester = wrap([1,2,3,4,5]) | ||
with pytest.raises(TypeError): | ||
del tester[0] | ||
|
||
|
||
def test_get_item_from_immutable_sequence() -> None: | ||
"""It should be possible to get an item from an immutable sequence.""" | ||
assert wrap(range(10))[0] == 0 | ||
assert wrap(range(10))[-1] == 9 | ||
|
||
|
||
def test_get_slice_from_immutable_sequence() -> None: | ||
"""It should be possible to get a slice from an immutable sequence.""" | ||
assert list(wrap(range(10))[0:2]) == [0,1] | ||
assert list(wrap(range(10))[0:-1]) == [0,1,2,3,4,5,6,7,8] | ||
|
||
|
||
def test_immutable_sequence_contains() -> None: | ||
"""It should be possible to see if an immutable sequence contains a value.""" | ||
tester = wrap([1,2,3,4,5]) | ||
assert 1 in tester | ||
assert 11 not in tester | ||
|
||
|
||
def test_immutable_sequence_index() -> None: | ||
tester = wrap([1,2,3,4,5]) | ||
assert tester.index(1) == 0 | ||
with pytest.raises(ValueError): | ||
_ = tester.index(11) | ||
|
||
|
||
def test_reverse_immutable_sequence() -> None: | ||
assert list(reversed(wrap([1,2]))) == [2,1] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import pytest | ||
from textual.widgets import Tree, TreeNode | ||
|
||
def label_of(node: TreeNode[None]): | ||
"""Get the label of a node as a string""" | ||
return str(node.label) | ||
|
||
|
||
def test_tree_node_children() -> None: | ||
"""A node's children property should act like an immutable list.""" | ||
CHILDREN=23 | ||
tree = Tree[None]("Root") | ||
for child in range(CHILDREN): | ||
tree.root.add(str(child)) | ||
assert len(tree.root.children)==CHILDREN | ||
for child in range(CHILDREN): | ||
assert label_of(tree.root.children[child]) == str(child) | ||
assert label_of(tree.root.children[0]) == "0" | ||
assert label_of(tree.root.children[-1]) == str(CHILDREN-1) | ||
assert [label_of(node) for node in tree.root.children] == [str(n) for n in range(CHILDREN)] | ||
assert [label_of(node) for node in tree.root.children[:2]] == [str(n) for n in range(2)] | ||
with pytest.raises(TypeError): | ||
tree.root.children[0] = tree.root.children[1] | ||
with pytest.raises(TypeError): | ||
del tree.root.children[0] | ||
with pytest.raises(TypeError): | ||
del tree.root.children[0:2] |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you run Black on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not by hand on the tests, no.
black
is run by pre-commit of course so if there's a non-black-happy-ness in the above, that would suggest that both pre-commit and CI black checks avoid the unit tests?Checking:
Guess none of us are?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we may be excluding tests.
Can you check you are also running the latest black specified in dev dependencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which seems to be a later version that specified in poetry.lock?
Although weirdly:
from pyproject.toml