Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Queries requiring and excluding the same condition now return no matches instead of raising `AssertionError`.
- Component reads and tag cleanup no longer retain unused entities through empty registry rows.
- Failed component removals no longer create empty rows, and clearing removes existing empty rows.
- Replacing component relations from an inherited view now preserves values which depend on the destination.
Expand Down
4 changes: 0 additions & 4 deletions tcod/ecs/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,6 @@ class _QueryLogicalAnd:
_all_of: frozenset[_Query] = frozenset()
_none_of: frozenset[_Query] = frozenset()

def __attrs_post_init__(self) -> None:
"""Verify the current state."""
assert self._all_of.isdisjoint(self._none_of)

def _add_to_cache(self, registry: Registry, cache: _QueryCache) -> None:
for dependency in itertools.chain(self._all_of, self._none_of):
cache.dependencies[dependency].add((registry, self))
Expand Down
28 changes: 27 additions & 1 deletion tests/test_ecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pickletools
import sys
from collections.abc import Callable, Iterator # noqa: TC003
from typing import Final
from typing import Any, Final

import pytest

Expand Down Expand Up @@ -330,3 +330,29 @@ def test_type_form() -> None:

def test_unpickle_is_a() -> None:
assert pickle.loads(PICKLED_ISA) is tcod.ecs.IsA # noqa: S301


@pytest.mark.parametrize("kind", ["component", "tag", "relation"])
@pytest.mark.parametrize("reverse", [False, True])
def test_query_contradictory_filters(kind: str, *, reverse: bool) -> None:
"""A conjunction excluding its own required condition has no matches."""
world = tcod.ecs.Registry()
actor = world["actor"]
conditions: dict[str, Any]
if kind == "component":
actor.components[int] = 3
conditions = {"components": [int]}
elif kind == "tag":
actor.tags.add("actor")
conditions = {"tags": ["actor"]}
else:
actor.relation_tag["room"] = world["room"]
conditions = {"relations": [("room", world["room"])]}
included = world.Q.all_of(**conditions)
excluded = world.Q.none_of(**conditions)
query = excluded.all_of(**conditions) if reverse else included.none_of(**conditions)
assert not query
assert not query.get_entities()
actor.clear()
assert not query
assert not included
Loading