refactor(page): delete the dead child-measurement helpers (R6)

page.py carried a closed cluster of five methods with no callers outside
itself:

    _get_child_property   called only by the four below
    _get_child_height     called by nothing
    _get_child_position   called only by _point_in_child
    _point_in_child       called by nothing
    _get_child_size       called only by _point_in_child

138 lines, verified unreferenced across pyWebLayout/, tests/, examples/
and scripts/.

They existed because Renderable declares no size, so the code probed
_size, size, _height, height, _origin and position in turn with hasattr,
guessing at each child's shape. query_point already does the right thing
instead: it hit-tests through the Queriable interface.

Hardening the Renderable contract so this cannot grow back - Renderable
has origin but no size - belongs with S10.1, which is already going to
revisit the render contract in core/base.py. Left alone here rather than
half-done.

894 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-08 12:56:05 +02:00
co-authored by Claude Opus 5
parent 62ca15159a
commit e81ba48f6d
-138
View File
@@ -258,69 +258,6 @@ class Page(Renderable, Queriable):
"""Get a copy of the children list""" """Get a copy of the children list"""
return self._children.copy() return self._children.copy()
def _get_child_property(self, child: Renderable, private_attr: str,
public_attr: str, index: Optional[int] = None,
default: Optional[int] = None) -> Optional[int]:
"""
Generic helper to extract properties from child objects with multiple fallback strategies.
Args:
child: The child object
private_attr: Name of the private attribute (e.g., '_size')
public_attr: Name of the public property (e.g., 'size')
index: Optional index for array-like properties (0 for width, 1 for height)
default: Default value if property cannot be determined
Returns:
Property value or default
"""
# Try private attribute first
if hasattr(child, private_attr):
value = getattr(child, private_attr)
if value is not None:
if isinstance(value, (list, tuple, np.ndarray)):
if index is not None and len(value) > index:
return int(value[index])
elif index is None:
return value
# Try public property
if hasattr(child, public_attr):
value = getattr(child, public_attr)
if value is not None:
if isinstance(value, (list, tuple, np.ndarray)):
if index is not None and len(value) > index:
return int(value[index])
elif index is None:
return value
else:
return int(value)
return default
def _get_child_height(self, child: Renderable) -> int:
"""
Get the height of a child object.
Args:
child: The child to measure
Returns:
Height in pixels
"""
# Try to get height from size property (index 1)
height = self._get_child_property(child, '_size', 'size', index=1)
if height is not None:
return height
# Try direct height attribute
height = self._get_child_property(child, '_height', 'height')
if height is not None:
return height
# Default fallback height
return 20
def render_children(self): def render_children(self):
""" """
Call render on all children in the list. Call render on all children in the list.
@@ -379,23 +316,6 @@ class Page(Renderable, Queriable):
return canvas return canvas
def _get_child_position(self, child: Renderable) -> Tuple[int, int]:
"""
Get the position where a child should be rendered.
Args:
child: The child object
Returns:
Tuple of (x, y) coordinates
"""
# Try to get x coordinate
x = self._get_child_property(child, '_origin', 'position', index=0, default=0)
# Try to get y coordinate
y = self._get_child_property(child, '_origin', 'position', index=1, default=0)
return (x, y)
def query_point(self, point: Tuple[int, int]) -> Optional[QueryResult]: def query_point(self, point: Tuple[int, int]) -> Optional[QueryResult]:
""" """
Query a point to find the deepest object at that location. Query a point to find the deepest object at that location.
@@ -432,64 +352,6 @@ class Page(Renderable, Queriable):
bounds=(int(point[0]), int(point[1]), 0, 0) bounds=(int(point[0]), int(point[1]), 0, 0)
) )
def _point_in_child(self, point: np.ndarray, child: Renderable) -> bool:
"""
Check if a point is within a child's bounds.
Args:
point: The point to check
child: The child to check against
Returns:
True if the point is within the child's bounds
"""
# If child implements Queriable interface, use it
if isinstance(child, Queriable) and hasattr(child, 'in_object'):
try:
return child.in_object(point)
except BaseException:
pass # Fall back to bounds checking
# Get child position and size for bounds checking
child_pos = self._get_child_position(child)
child_size = self._get_child_size(child)
if child_size is None:
return False
# Check if point is within child bounds
return (
child_pos[0] <= point[0] < child_pos[0] + child_size[0] and
child_pos[1] <= point[1] < child_pos[1] + child_size[1]
)
def _get_child_size(self, child: Renderable) -> Optional[Tuple[int, int]]:
"""
Get the size of a child object.
Args:
child: The child to measure
Returns:
Tuple of (width, height) or None if size cannot be determined
"""
# Try to get width and height from size property
width = self._get_child_property(child, '_size', 'size', index=0)
height = self._get_child_property(child, '_size', 'size', index=1)
# If size property worked, return it
if width is not None and height is not None:
return (width, height)
# Try direct width/height attributes
width = self._get_child_property(child, '_width', 'width')
height = self._get_child_property(child, '_height', 'height')
if width is not None and height is not None:
return (width, height)
return None
def _make_query_result(self, obj, point: Tuple[int, int]) -> QueryResult: def _make_query_result(self, obj, point: Tuple[int, int]) -> QueryResult:
""" """
Package an object into a QueryResult with metadata. Package an object into a QueryResult with metadata.