Skip to content

Commit e624d8c

Browse files
authored
Merge pull request #3044 from HalfWhitt/fix_getitem_bypass
Fixed enforcement of property names in property name update
2 parents 870dccf + 857175d commit e624d8c

File tree

4 files changed

+78
-21
lines changed

4 files changed

+78
-21
lines changed

changes/3044.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The ``Pack.margin`` property (and its deprecated alias, ``padding``) can now be accessed via bracket notation, as in ``style["margin"]``. (Previously this worked for the "sub-properties" of ``margin_top`` etc., but not for ``margin``/``padding`` itself.)

changes/3044.misc.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
An issue with PR #3033 that allowed bracket access of invalid style names on a Pack object has been fixed.

core/src/toga/style/pack.py

+21-5
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@ def _hidden(self) -> bool:
112112

113113
# Pack.alignment is still an actual property, despite being deprecated, so we need
114114
# to suppress deprecation warnings when reapply is called.
115-
def reapply(self, *args, **kw):
115+
def reapply(self, *args, **kwargs):
116116
with warnings.catch_warnings():
117117
warnings.filterwarnings("ignore", category=DeprecationWarning)
118-
super().reapply(*args, **kw)
118+
super().reapply(*args, **kwargs)
119119

120120
DEPRECATED_PROPERTIES = {
121121
# Map each deprecated property name to its replacement.
@@ -211,13 +211,29 @@ def __delattr__(self, name):
211211
# Index notation
212212

213213
def __getitem__(self, name):
214-
return getattr(self, name.replace("-", "_"))
214+
# As long as we're mucking about with backwards compatibility: Travertino 0.3.0
215+
# doesn't support accessing directional properties via bracket notation, so
216+
# special-case it here to gain access to the FUTURE.
217+
if name in {"padding", "margin"}:
218+
return getattr(self, name)
219+
220+
return super().__getitem__(self._update_property_name(name.replace("-", "_")))
215221

216222
def __setitem__(self, name, value):
217-
setattr(self, name.replace("-", "_"), value)
223+
if name in {"padding", "margin"}:
224+
setattr(self, name, value)
225+
return
226+
227+
return super().__setitem__(
228+
self._update_property_name(name.replace("-", "_")), value
229+
)
218230

219231
def __delitem__(self, name):
220-
delattr(self, name.replace("-", "_"))
232+
if name in {"padding", "margin"}:
233+
delattr(self, name)
234+
return
235+
236+
return super().__delitem__(self._update_property_name(name.replace("-", "_")))
221237

222238
#######################################################
223239
# End backwards compatibility

core/tests/style/pack/test_deprecated_properties.py

+55-16
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,26 @@ def setitem(obj, name, value):
2020
obj[name] = value
2121

2222

23+
def setitem_hyphen(obj, name, value):
24+
obj[name.replace("_", "-")] = value
25+
26+
2327
def getitem(obj, name):
2428
return obj[name]
2529

2630

31+
def getitem_hyphen(obj, name):
32+
return obj[name.replace("_", "-")]
33+
34+
2735
def delitem(obj, name):
2836
del obj[name]
2937

3038

39+
def delitem_hyphen(obj, name):
40+
del obj[name.replace("_", "-")]
41+
42+
3143
@pytest.mark.parametrize(
3244
"old_name, new_name, value, default",
3345
[
@@ -38,14 +50,14 @@ def delitem(obj, name):
3850
("padding_left", "margin_left", 5, 0),
3951
],
4052
)
41-
@pytest.mark.parametrize("set_fn", (setattr, setitem))
42-
@pytest.mark.parametrize("get_fn", (getattr, getitem))
43-
@pytest.mark.parametrize("del_fn", (delattr, delitem))
53+
@pytest.mark.parametrize("set_fn", (setattr, setitem, setitem_hyphen))
54+
@pytest.mark.parametrize("get_fn", (getattr, getitem, getitem_hyphen))
55+
@pytest.mark.parametrize("del_fn", (delattr, delitem, delitem_hyphen))
4456
def test_deprecated_properties(
4557
old_name, new_name, value, default, set_fn, get_fn, del_fn
4658
):
4759
"""Deprecated names alias to new names, and issue deprecation warnings."""
48-
# Set the old name, then check the new name.
60+
# Set the old name, then check the new name
4961
style = Pack()
5062
with pytest.warns(DeprecationWarning):
5163
set_fn(style, old_name, value)
@@ -56,7 +68,7 @@ def test_deprecated_properties(
5668
del_fn(style, old_name)
5769
assert get_fn(style, new_name) == default
5870

59-
# Set the new name, then check the old name.
71+
# Set the new name, then check the old name
6072
style = Pack()
6173
set_fn(style, new_name, value)
6274
with pytest.warns(DeprecationWarning):
@@ -85,31 +97,40 @@ def test_deprecated_properties(
8597
(COLUMN, LTR, CENTER, CENTER),
8698
],
8799
)
88-
def test_alignment_align_items(direction, text_direction, alignment, align_items):
100+
@pytest.mark.parametrize("set_fn", (setattr, setitem, setitem_hyphen))
101+
@pytest.mark.parametrize("get_fn", (getattr, getitem, getitem_hyphen))
102+
@pytest.mark.parametrize("del_fn", (delattr, delitem, delitem_hyphen))
103+
def test_alignment_align_items(
104+
direction, text_direction, alignment, align_items, set_fn, get_fn, del_fn
105+
):
89106
"""Alignment (with deprecation warning) and align_items map to each other."""
107+
# Set alignment, check align_items
90108
with pytest.warns(DeprecationWarning):
91109
style = Pack(
92110
direction=direction,
93111
text_direction=text_direction,
94-
alignment=alignment,
95112
)
96-
assert style.align_items == align_items
113+
set_fn(style, "alignment", alignment)
114+
assert get_fn(style, "align_items") == align_items
97115

116+
# Delete alignment, check align_items
98117
with pytest.warns(DeprecationWarning):
99-
del style.alignment
100-
assert style.align_items is None
118+
del_fn(style, "alignment")
119+
assert get_fn(style, "align_items") is None
101120

121+
# Set align_items, check alignment
102122
style = Pack(
103123
direction=direction,
104124
text_direction=text_direction,
105-
align_items=align_items,
106125
)
126+
set_fn(style, "align_items", align_items)
107127
with pytest.warns(DeprecationWarning):
108-
assert style.alignment == alignment
128+
assert get_fn(style, "alignment") == alignment
109129

110-
del style.align_items
130+
# Delete align_items, check alignment
131+
del_fn(style, "align_items")
111132
with pytest.warns(DeprecationWarning):
112-
assert style.alignment is None
133+
assert get_fn(style, "alignment") is None
113134

114135

115136
@pytest.mark.parametrize(
@@ -121,8 +142,26 @@ def test_alignment_align_items(direction, text_direction, alignment, align_items
121142
(COLUMN, BOTTOM),
122143
],
123144
)
124-
def test_alignment_align_items_invalid(direction, alignment):
145+
@pytest.mark.parametrize("get_fn", (getattr, getitem, getitem_hyphen))
146+
def test_alignment_align_items_invalid(direction, alignment, get_fn):
125147
"""Invalid settings for alignment should return None for align_items."""
126148
with pytest.warns(DeprecationWarning):
127149
style = Pack(direction=direction, alignment=alignment)
128-
assert style.align_items is None
150+
assert get_fn(style, "align_items") is None
151+
152+
153+
def test_bogus_property_name():
154+
"""Invalid property name in brackets should be an error.
155+
156+
This is tested here along with deprecated property names, because normally it should
157+
be verified by Travertino's tests. It can only be an issue as long as we're
158+
overriding the relevant methods in Pack.
159+
"""
160+
style = Pack()
161+
162+
with pytest.raises(KeyError):
163+
style["bogus"] = 1
164+
with pytest.raises(KeyError):
165+
style["bogus"]
166+
with pytest.raises(KeyError):
167+
del style["bogus"]

0 commit comments

Comments
 (0)