Skip to content

Commit

Permalink
Reverted style default None arg, and removed logic checking for None …
Browse files Browse the repository at this point in the history
…style
  • Loading branch information
HalfWhitt committed Oct 31, 2024
1 parent 8cb132d commit c12e4f5
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 93 deletions.
1 change: 0 additions & 1 deletion changes/224.feature.rst

This file was deleted.

19 changes: 8 additions & 11 deletions src/travertino/node.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
class Node:
def __init__(self, style=None, applicator=None, children=None):
def __init__(self, style, applicator=None, children=None):
# Explicitly set the internal attribute first, since the setter for style will
# access the applicator property.
self._applicator = None

self.style = style
self.applicator = applicator

Expand All @@ -23,10 +27,6 @@ def style(self):

@style.setter
def style(self, style):
if style is None:
self._style = None
return

self._style = style.copy()
self.intrinsic = self.style.IntrinsicSize()
self.layout = self.style.Box(self)
Expand All @@ -41,19 +41,16 @@ def applicator(self):
Assigning an applicator triggers an application of the node's style if a style
has already been assigned.
"""
# Has to have a fallback, because it's accessed before its assignment in the
# setter for style
return getattr(self, "_applicator", None)
return self._applicator

@applicator.setter
def applicator(self, applicator):
self._applicator = applicator
self.style._applicator = applicator

if applicator:
applicator.node = self

if self.style is not None:
self.style._applicator = applicator

@property
def root(self):
"""The root of the tree containing this node.
Expand Down
144 changes: 63 additions & 81 deletions tests/test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def test_clear():
assert node.children == []


def test_create_with_only_style():
def test_create_with_no_applicator():
style = Style(int_prop=5)
node = Node(style=style)

Expand All @@ -258,131 +258,113 @@ def test_create_with_only_style():
node.style.reapply.assert_not_called()


def test_assign_only_style():
def test_create_with_applicator():
style = Style(int_prop=5)
node = Node()
node.style = style
applicator = Mock()
node = Node(style=style, applicator=applicator)

# Style copies on assignment.
assert isinstance(node.style, Style)
assert node.style == style
assert node.style is not style

# Since no applicator has been assigned, style wasn't applied.
node.style.reapply.assert_not_called()


def test_create_with_only_applicator():
applicator = Mock()

# No reapply should be attempted. If it were, it would raise an AttributeError as
# None has no reapply() method.
node = Node(applicator=applicator)

# Applicator assignment does *not* copy.
assert node.applicator is applicator

# Applicator gets a reference back to its node and to the style.
assert applicator.node is node
assert node.style._applicator is applicator


def test_assign_only_applicator():
applicator = Mock()
node = Node()

# No reapply should be attempted. If it were, it would raise an AttributeError as
# None has no reapply() method.
node.applicator = applicator

# Applicator assignment does *not* copy.
assert node.applicator is applicator


def test_create_with_style_and_applicator():
style = Style(int_prop=5)
applicator = Mock()
node = Node(style=style, applicator=applicator)

# With both style and applicator present, style should be applied.
# Assigning a non-None applicator should always apply style.
node.style.reapply.assert_called_once()
# Should have also assigned the applicator the style.
assert node.style._applicator is applicator


def test_style_then_applicator():
style = Style(int_prop=5)
@pytest.mark.parametrize(
"node",
[
Node(style=Style()),
Node(style=Style(), applicator=Mock()),
],
)
def test_assign_applicator(node):
node.style.reapply.reset_mock()

applicator = Mock()
node = Node(style=style)
node.applicator = applicator

# With both style and applicator present, style should be applied.
node.style.reapply.assert_called_once()
# Should have also assigned the applicator the style.
# Applicator assignment does *not* copy.
assert node.applicator is applicator
# Applicator gets a reference back to its node and to the style.
assert applicator.node is node
assert node.style._applicator is applicator


def test_applicator_then_style():
style = Style(int_prop=5)
applicator = Mock()
node = Node(applicator=applicator)
node.style = style

# With both style and applicator present, style should be applied.
# Assigning a non-None applicator should always apply style.
node.style.reapply.assert_called_once()
# Should have also assigned the applicator the style.
assert node.style._applicator is applicator


@pytest.mark.parametrize(
"node",
[
Node(),
Node(style=Style()),
Node(applicator=Mock()),
Node(style=Style(), applicator=Mock()),
],
)
def test_assign_applicator_none(node):
if node.style is not None:
node.style.reapply.reset_mock()
node.style.reapply.reset_mock()

node.applicator = None
assert node.applicator is None

if node.style is not None:
# Should be updated on style as well
assert node.style._applicator is None
# Assigning None to applicator does not trigger reapply.
node.style.reapply.assert_not_called()
# Should be updated on style as well
assert node.style._applicator is None
# Assigning None to applicator does not trigger reapply.
node.style.reapply.assert_not_called()


@pytest.mark.parametrize(
"node",
[
Node(),
Node(style=Style()),
Node(applicator=Mock()),
Node(style=Style(), applicator=Mock()),
],
)
def test_assign_style_none(node):
node.style = None
assert node.style is None
def test_assign_style_with_applicator():
style_1 = Style(int_prop=5)
node = Node(style=style_1, applicator=Mock())

# No reapply should be attempted. If it were, it would raise an AttributeError as
# None has no reapply() method.
node.style.reapply.reset_mock()
style_2 = Style(int_prop=10)
node.style = style_2

# Style copies on assignment.
assert isinstance(node.style, Style)
assert node.style == style_2
assert node.style is not style_2

assert node.style != style_1

# Since an applicator has already been assigned, assigning style applies the style.
node.style.reapply.assert_called_once()


def test_assign_style_with_no_applicator():
style_1 = Style(int_prop=5)
node = Node(style=style_1)

node.style.reapply.reset_mock()
style_2 = Style(int_prop=10)
node.style = style_2

# Style copies on assignment.
assert isinstance(node.style, Style)
assert node.style == style_2
assert node.style is not style_2

assert node.style != style_1

# Since no applicator was present, style should not be applied.
node.style.reapply.assert_not_called()


def test_apply_before_node_is_ready():
style = BrokenStyle()
applicator = Mock()

with pytest.warns(RuntimeWarning):
Node(style=style, applicator=applicator)

with pytest.warns(RuntimeWarning):
node = Node(style=style)
node.applicator = applicator

with pytest.warns(RuntimeWarning):
node = Node(applicator=applicator)
node.style = style
Node(style=style, applicator=applicator)

0 comments on commit c12e4f5

Please sign in to comment.