Fix KeyError in get_components() when the smallest set is found last - #122
Open
uttam12331 wants to merge 1 commit into
Open
Fix KeyError in get_components() when the smallest set is found last#122uttam12331 wants to merge 1 commit into
uttam12331 wants to merge 1 commit into
Conversation
_get_components() scans the requested component types to iterate the smallest component set first, setting the other types aside for a membership check. When it found a new smallest set, it tried to move the previous smallest type into other_types using an index into component_types (component_types[len(other_types)]). That index is only correct while no type has already been set aside; once one has, it points at the wrong type and the real previous-smallest type is dropped. The dropped type is then never checked, so an entity that matches on the remaining types but lacks it slips through and raises a KeyError while building the result tuple. For example, querying three types where the final (smallest) set contains an entity missing the first type crashes instead of returning the correct matches. Track the previous smallest type directly instead of computing it from an index. Adds a regression test covering the size-ordering path.
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
get_components()can raise aKeyErrorfor a perfectly valid query when three or more component types are requested._get_components()iterates the smallest component set first and sets the other requested types aside for a membership check. When it finds a new smallest set, it moves the previously-smallest type intoother_types. It computed that type with an index into the query tuple:component_types[len(other_types)]only points at the previous minimum while nothing has gone through theelsebranch yet. Once a larger set has already been appended toother_types, the index is off — it re-appends an already-present type and the real previous-smallest type is silently dropped.The dropped type is then never used to filter, but it is still read when the result tuple is built (
tuple(entity_comps[ct] for ct in component_types)), so an entity that matches on the remaining types but lacks the dropped one raises aKeyErrorinstead of being skipped.Reproduce
No entity has all three components, so the correct result is an empty list. Instead it crashes:
Posis dropped from the internal filter, so theVel+Tagentity passes the check and then blows up buildingentity_comps[Pos].Fix
Track the previous-smallest type directly instead of deriving it from an index:
The smallest-set-first scan was added as a performance optimization (#116); this keeps that optimization but makes the "demote the old minimum" step correct.
Verification
test_get_components_smallest_set_missing_component, which fails onmaster(KeyError) and passes with the fix.54 passed.mypy esper: clean.