Skip to main content

About

PyPI PyPI - License Documentation Status codecov

Entity/Component containers for implementing composition over inheritance.

Installation

Use pip to install this library:

pip install tcod-ec

If tcod is installed and the version is less than 14.0.0 then import tcod.ec will fail. Remove or update tcod to fix this issue.

Examples

tcod.ec.ComponentDict is a container for anonymous components all with a unique class. The key is the class of the component and can only be assigned one instance of that class.

>>> import attrs
>>> import tcod.ec

# Anonymous components don't need special treatment.
>>> @attrs.define
... class Position:
...     x: int = 0
...     y: int = 0
>>> @attrs.define
... class Graphic:
...     ch: str = "@"

# ComponentDict stores a single instance for every unique class, in this case: [str, Position, Graphic]
>>> entity = tcod.ec.ComponentDict(["Hello world", Position(1, 2), Graphic("!")])
>>> {Position, Graphic} in entity  # Check if an entity has a set of components.
True
>>> entity[str]  # Access components using the class as the key.
'Hello world'
>>> entity[Position].y = 10
>>> entity[Position]
Position(x=1, y=10)
>>> entity[Graphic] = Graphic("?")  # Explicit setting of the component.
>>> entity
ComponentDict(['Hello world', Position(x=1, y=10), Graphic(ch='?')])
>>> entity.set(Graphic("#"))  # Implicit setting.
ComponentDict(['Hello world', Position(x=1, y=10), Graphic(ch='#')])
>>> del entity[Graphic]  # Components can be deleted.
>>> entity
ComponentDict(['Hello world', Position(x=1, y=10)])

# Abstract components can be registered with tcod.ec.abstract_component.
>>> @tcod.ec.abstract_component
... @attrs.define
... class Base:
...     pass
>>> @attrs.define
... class Derived(Base):
...     pass
>>> entity.set(Derived())  # Derived classes may be set implicitly.
ComponentDict(['Hello world', Position(x=1, y=10), Derived()])
>>> entity[Base] = Derived()  # Or explicitly assigned to the abstract key.
>>> Base in entity
True
>>> entity[Base]  # Any derived classes use the base class as the key.
Derived()
>>> entity
ComponentDict(['Hello world', Position(x=1, y=10), Derived()])

tcod.ec.Composite is a collection of anonymous components. Unlike ComponentDict this can store multiple components with the same class. Components can also be accessed using the parent class. This works with multiple inheritance.

While this class looks like an all around upgrade to ComponentDict it's far more complex to work with. The ways it mixes class inheritance with composition can lead to anti-patterns if used carelessly. Any class used as a key will return zero, one, or more instances which must be accounted for. If in doubt then the simpler ComponentDict should be used instead.

>>> @attrs.define
... class Body:
...     name: str
...     hp: int
>>> entity = tcod.ec.Composite([Position(1, 2), Graphic("!"), Body("torso", 10), Body("head", 5)])
>>> {Position, Graphic, Body} in entity
True
>>> (pos,) = entity[Position]  # Use unpacking logic to verify the number of elements.
>>> pos.y = 10
>>> entity[Position]
[Position(x=1, y=10)]
>>> entity[Graphic] = [Graphic("?")]  # New sequences can be assigned, this deletes all previous instances of that key.
>>> entity[Graphic]
[Graphic(ch='?')]
>>> del entity[Graphic]
>>> entity[Graphic]  # Missing keys return an empty sequence instead of KeyError.
()

>>> entity[Body]
[Body(name='torso', hp=10), Body(name='head', hp=5)]
>>> entity.extend([Body("legs", 10), Body("arms", 10)])  # Use append or extend to add new instances.
>>> for body in list(entity[Body]):  # Make a copy of the sequence if you intend to remove values during iteration.
...     body.hp -= 2
...     if body.name == "torso":
...         entity.remove(body)
>>> entity[Body]
[Body(name='head', hp=3), Body(name='legs', hp=8), Body(name='arms', hp=8)]

# All objects can be accessed at once using `object`.
>>> entity[object]
[Position(x=1, y=10), Body(name='head', hp=3), Body(name='legs', hp=8), Body(name='arms', hp=8)]
>>> entity[object] = ("Hello", "world")
>>> entity
Composite(['Hello', 'world'])

Release files for tcod-ec 2.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tcod-ec 2.2.1
File Size Uploaded
tcod-ec-2.2.1.tar.gz 19.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tcod-ec 2.2.1
File Interpreter ABI Platform
tcod_ec-2.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 30.8 kB

Release files / tcod-ec-2.2.1.tar.gz

Download URL tcod-ec-2.2.1.tar.gz
Size 19.9 kB
Tags Source
SHA-256 checksum
How to use checksums
40caffea881b068b3133b861d93cf250e17ed4c07459ab781eea96c5b5801b23
BLAKE2b-256 checksum
How to use checksums
f2967b375f63cdd22c3ead28b6622fe3a5338cc653062584a05c57d2defa8ec5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via python-requests/2.28.1

Release files / tcod_ec-2.2.1-py3-none-any.whl

Download URL tcod_ec-2.2.1-py3-none-any.whl
Size 10.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a69b2004793f52553012ca54b2dbf58bbd047181a5f02dc3305607d478a08016
BLAKE2b-256 checksum
How to use checksums
6dad1a2226da8ee754f61a913fba1b68707ed38970088fbd570f97f412fc20fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via python-requests/2.28.1

Release history Release notifications | RSS feed

This release

2.2.1 This release

2 release files

2.2.0

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page