Skip to content

Commit 7bf19c2

Browse files
committed
Add TypeForm support
Converts containers to use TypeForm instead of Type. This allows for type expressions to be used as component types.
1 parent d48de23 commit 7bf19c2

4 files changed

Lines changed: 15 additions & 17 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ dependencies = [
2222
"attrs >=23.1.0",
2323
"cattrs >=23.1.2",
2424
"sentinel-value >=1.0.0",
25-
"typing-extensions >=4.9.0",
25+
"typing-extensions >=4.13.1",
2626
]
2727

2828
[tool.setuptools_scm]

tcod/ecs/entity.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
MutableMapping,
1414
MutableSet,
1515
Tuple,
16-
Type,
1716
TypeVar,
1817
Union,
1918
overload,
@@ -22,7 +21,7 @@
2221

2322
import attrs
2423
from sentinel_value import sentinel
25-
from typing_extensions import Self, deprecated
24+
from typing_extensions import Self, TypeForm, deprecated
2625

2726
import tcod.ecs.callbacks
2827
import tcod.ecs.query
@@ -389,7 +388,7 @@ def _traverse_entities(start: Entity, traverse_parents: tuple[object, ...]) -> I
389388

390389

391390
@attrs.define(eq=False, frozen=True, weakref_slot=False)
392-
class EntityComponents(MutableMapping[Union[Type[Any], Tuple[object, Type[Any]]], object]):
391+
class EntityComponents(MutableMapping[Union[TypeForm[Any], Tuple[object, TypeForm[Any]]], Any]):
393392
"""A proxy attribute to access an entities components like a dictionary.
394393
395394
See :any:`Entity.components`.
@@ -474,7 +473,7 @@ def keys(self) -> AbstractSet[ComponentKey[object]]: # type: ignore[override]
474473
*(_components_by_entity.get(entity, ()) for entity in _traverse_entities(self.entity, self.traverse))
475474
)
476475

477-
def __contains__(self, key: ComponentKey[object]) -> bool: # type: ignore[override]
476+
def __contains__(self, key: ComponentKey[object]) -> bool:
478477
"""Return True if this entity has the provided component."""
479478
_components_by_entity = self.entity.registry._components_by_entity
480479
return any(
@@ -500,21 +499,20 @@ def update_values(self, values: Iterable[object]) -> None:
500499
self.set(value)
501500

502501
@deprecated("This method has been deprecated. Iterate over items instead.", category=FutureWarning)
503-
def by_name_type(self, name_type: type[_T1], component_type: type[_T2]) -> Iterator[tuple[_T1, type[_T2]]]:
502+
def by_name_type(self, name_type: TypeForm[_T1], component_type: TypeForm[_T2]) -> Iterator[tuple[_T1, type[_T2]]]:
504503
"""Iterate over all of an entities component keys with a specific (name_type, component_type) combination.
505504
506505
.. versionadded:: 3.0
507506
508507
.. deprecated:: 3.1
509508
This method has been deprecated. Iterate over items instead.
510509
"""
511-
# Naive implementation until I feel like optimizing it
512510
for key in self:
513511
if not isinstance(key, tuple):
514512
continue
515513
key_name, key_component = key
516514
if key_component is component_type and isinstance(key_name, name_type):
517-
yield key_name, key_component
515+
yield key_name, key_component # type: ignore[unused-ignore] # Too complex for PyLance, deprecated anyways
518516

519517
@overload
520518
def __ior__(self, value: SupportsKeysAndGetItem[ComponentKey[Any], Any]) -> Self: ...
@@ -544,7 +542,7 @@ def get(self, __key: ComponentKey[T], /, default: _T1 | None = None) -> T | _T1:
544542
except KeyError:
545543
return default # type: ignore[return-value] # https://github.com/python/mypy/issues/3737
546544

547-
def setdefault(self, __key: ComponentKey[T], __default: T, /) -> T:
545+
def setdefault(self, __key: ComponentKey[T], __default: T, /) -> T: # type: ignore[override] # Does not allow None
548546
"""Assign a default value if a component is missing, then returns the current value."""
549547
try:
550548
return self[__key]
@@ -1032,14 +1030,14 @@ def __getitem__(self, key: ComponentKey[T]) -> EntityComponentRelationMapping[T]
10321030
"""Access relations for this component key as a `{target: component}` dict-like object."""
10331031
return EntityComponentRelationMapping(self.entity, key, self.traverse)
10341032

1035-
def __setitem__(self, __key: ComponentKey[T], __values: Mapping[Entity, object], /) -> None:
1033+
def __setitem__(self, __key: ComponentKey[T], __values: Mapping[Entity, T], /) -> None:
10361034
"""Redefine the component relations for this entity.
10371035
10381036
..versionadded:: 4.2.0
10391037
"""
10401038
if isinstance(__values, EntityComponentRelationMapping) and __values.entity is self.entity:
10411039
return
1042-
mapping: EntityComponentRelationMapping[object] = self[__key]
1040+
mapping: EntityComponentRelationMapping[T] = self[__key]
10431041
mapping.clear()
10441042
for target, component in __values.items():
10451043
mapping[target] = component

tcod/ecs/registry.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ def _defaultdict_of_dict() -> defaultdict[_T1, dict[_T2, _T3]]:
3232

3333

3434
def _components_by_entity_from(
35-
by_type: defaultdict[ComponentKey[object], dict[Entity, Any]],
36-
) -> defaultdict[Entity, dict[ComponentKey[object], Any]]:
35+
by_type: defaultdict[ComponentKey[_T1], dict[Entity, _T1]],
36+
) -> defaultdict[Entity, dict[ComponentKey[_T1], _T1]]:
3737
"""Return the component lookup table from the components sparse-set."""
38-
by_entity: defaultdict[Entity, dict[ComponentKey[object], Any]] = defaultdict(dict)
38+
by_entity: defaultdict[Entity, dict[ComponentKey[_T1], _T1]] = defaultdict(dict)
3939
for component_key, components in by_type.items():
4040
for entity, component in components.items():
4141
by_entity[entity][component_key] = component

tcod/ecs/typing.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
import sys
66
import types
7-
from typing import TYPE_CHECKING, Any, Tuple, Type, TypeVar, Union
7+
from typing import TYPE_CHECKING, Any, Tuple, TypeVar, Union
88

9-
from typing_extensions import TypeAlias
9+
from typing_extensions import TypeAlias, TypeForm
1010

1111
if TYPE_CHECKING:
1212
from tcod.ecs.entity import Entity
@@ -22,7 +22,7 @@
2222

2323
_T = TypeVar("_T")
2424

25-
ComponentKey: TypeAlias = Union[Type[_T], Tuple[object, Type[_T]]]
25+
ComponentKey: TypeAlias = Union[TypeForm[_T], Tuple[object, TypeForm[_T]]]
2626
"""ComponentKey is plain `type` or tuple `(tag, type)`."""
2727

2828
_RelationTargetLookup: TypeAlias = Union[Entity, EllipsisType]

0 commit comments

Comments
 (0)