Problem
Grid.getFirstLocation (src/grid.py:38) raises StopIteration on a grid with no locations. Reproduced against the current main:
Grid(0, 0).getFirstLocation()
# StopIteration
The method is return next(iter(self.locations.values())) with no default, so an empty dictionary propagates StopIteration to the caller — an exception with an empty message, which says nothing about what went wrong.
Why this matters
After PR #44 and PR #46, every other retrieval path on Grid degrades gracefully on the absent path: getEntity returns None, getLocation warns and returns None, getRandomLocation warns and returns None, and getLocationByCoordinates returns -1. getFirstLocation is now the last retrieval path that raises.
A zero-sized grid is constructible, and removeLocation can take a populated grid down to none, so the empty case is reachable in normal use rather than only through a degenerate constructor argument.
StopIteration is also a poor choice of signal specifically: inside a generator it is swallowed and converted to RuntimeError (PEP 479), so a caller iterating over grids would see a confusing failure some distance from the cause.
Suggested fix
An emptiness check in the style now used by getRandomLocation — a warning matching the existing wording convention and a None return. None is the sentinel already chosen for the by-ID and random retrieval paths in PR #46, so it is the consistent choice here too.
Acceptance criteria
- Retrieving the first location of a grid with no locations does not raise.
- The absent path is covered by a test, alongside a test that the populated path stays silent.
This issue body was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).
drafted by Claude on behalf of Daniel Stephenson
Problem
Grid.getFirstLocation(src/grid.py:38) raisesStopIterationon a grid with no locations. Reproduced against the currentmain:The method is
return next(iter(self.locations.values()))with no default, so an empty dictionary propagatesStopIterationto the caller — an exception with an empty message, which says nothing about what went wrong.Why this matters
After PR #44 and PR #46, every other retrieval path on
Griddegrades gracefully on the absent path:getEntityreturnsNone,getLocationwarns and returnsNone,getRandomLocationwarns and returnsNone, andgetLocationByCoordinatesreturns-1.getFirstLocationis now the last retrieval path that raises.A zero-sized grid is constructible, and
removeLocationcan take a populated grid down to none, so the empty case is reachable in normal use rather than only through a degenerate constructor argument.StopIterationis also a poor choice of signal specifically: inside a generator it is swallowed and converted toRuntimeError(PEP 479), so a caller iterating over grids would see a confusing failure some distance from the cause.Suggested fix
An emptiness check in the style now used by
getRandomLocation— a warning matching the existing wording convention and aNonereturn.Noneis the sentinel already chosen for the by-ID and random retrieval paths in PR #46, so it is the consistent choice here too.Acceptance criteria
This issue body was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).
drafted by Claude on behalf of Daniel Stephenson