tinyecs 0.4.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 DickerDackel
3
+ Copyright (c) 2026 DickerDackel
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tinyecs
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: The teeniest, tiniest ECS system
5
5
  Author-email: Michael Lamertz <michael.lamertz@gmail.com>
6
6
  License-Expression: MIT
@@ -13,7 +13,19 @@ Classifier: Topic :: Games/Entertainment
13
13
  Classifier: Topic :: Software Development :: Libraries :: pygame
14
14
  Description-Content-Type: text/x-rst
15
15
  License-File: LICENSE
16
- Requires-Dist: pgcooldown
16
+ Provides-Extra: base
17
+ Requires-Dist: tinyecs-compsys-base; extra == "base"
18
+ Provides-Extra: dynamics
19
+ Requires-Dist: tinyecs-compsys-dynamics; extra == "dynamics"
20
+ Provides-Extra: patternengine
21
+ Requires-Dist: tinyecs-compsys-patternengine; extra == "patternengine"
22
+ Provides-Extra: sdl2
23
+ Requires-Dist: tinyecs-compsys-sdl2; extra == "sdl2"
24
+ Provides-Extra: demos
25
+ Requires-Dist: tinyecs[base,dynamics,sdl2]; extra == "demos"
26
+ Requires-Dist: tinyecs-demos; extra == "demos"
27
+ Provides-Extra: all
28
+ Requires-Dist: tinyecs[base,demos,dynamics,patternengine,sdl2]; extra == "all"
17
29
  Dynamic: license-file
18
30
 
19
31
  Introduction
@@ -73,15 +85,6 @@ Issues can be opened on `github issues`_
73
85
 
74
86
  .. _github issues: https://github.com/dickerdackel/tinyecs/issues
75
87
 
76
- Please respect, that I don't want any contributions done with the assistance
77
- of AI. This is a hobby project with focus on the craft of programming. I
78
- have experimentally used AI to audit parts of the code and documentation, and
79
- while it found a lot of typos and 2 actual issues, without exception, the
80
- provided solutions were often besides the point or plain wrong.
81
-
82
- I have no possibility to enforce that request, the simple fact that I ask for
83
- it should be sufficient.
84
-
85
88
  License
86
89
  =======
87
90
 
@@ -55,15 +55,6 @@ Issues can be opened on `github issues`_
55
55
 
56
56
  .. _github issues: https://github.com/dickerdackel/tinyecs/issues
57
57
 
58
- Please respect, that I don't want any contributions done with the assistance
59
- of AI. This is a hobby project with focus on the craft of programming. I
60
- have experimentally used AI to audit parts of the code and documentation, and
61
- while it found a lot of typos and 2 actual issues, without exception, the
62
- provided solutions were often besides the point or plain wrong.
63
-
64
- I have no possibility to enforce that request, the simple fact that I ask for
65
- it should be sufficient.
66
-
67
58
  License
68
59
  =======
69
60
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "tinyecs"
3
3
  description = "The teeniest, tiniest ECS system"
4
- version = "0.4.0"
4
+ version = "0.5.0"
5
5
  readme = "README.rst"
6
6
 
7
7
  authors = [
@@ -18,14 +18,18 @@ classifiers = [
18
18
  license = "MIT"
19
19
  license-files = ["LICENSE"]
20
20
 
21
- dependencies = [
22
- "pgcooldown"
23
- ]
21
+ dependencies = [ ]
24
22
 
25
23
  [project.optional-dependencies]
26
-
27
- [project.scripts]
28
- tinyecs-demo = 'tinyecs.demo:main'
24
+ base = ["tinyecs-compsys-base"]
25
+ dynamics = ["tinyecs-compsys-dynamics"]
26
+ patternengine = ["tinyecs-compsys-patternengine"]
27
+ sdl2 = ["tinyecs-compsys-sdl2"]
28
+ demos = [
29
+ "tinyecs[base,dynamics,sdl2]",
30
+ "tinyecs-demos",
31
+ ]
32
+ all = ["tinyecs[base,dynamics,sdl2,patternengine,demos]"]
29
33
 
30
34
  [project.urls]
31
35
  homepage = "https://github.com/dickerdackel/tinyecs"
@@ -3,20 +3,21 @@ from collections.abc import Hashable, Iterable
3
3
  from typing import Any, Protocol
4
4
  from uuid import uuid4
5
5
 
6
- __all__ = ['Component', 'ComponentID', 'DomainID', 'EntityID', 'Property',
7
- 'RegistryError', 'UnknownArchetypeError', 'UnknownComponentError',
8
- 'UnknownEntityError', 'UnknownSystemError', 'add_component',
9
- 'add_components', 'add_system', 'add_system_to_domain',
10
- 'add_to_archetype', 'cid_of_comp', 'cids_of_eid',
11
- 'clear_properties', 'comp_of_eid', 'comps_of_archetype',
12
- 'comps_of_eid', 'create_archetype', 'create_entity', 'eid_has',
13
- 'eid_of_comp', 'eids_by_cids', 'eids_by_property', 'has',
14
- 'has_property', 'healthcheck', 'purge_by_property',
15
- 'remove_archetype', 'remove_component', 'remove_entity',
16
- 'remove_from_archetype', 'remove_property', 'remove_system',
17
- 'remove_system_from_domain', 'reset', 'run_all_systems',
18
- 'run_domain', 'run_system', 'set_properties', 'set_property',
19
- 'update_component',]
6
+ __all__ = ['Component', 'ComponentID', 'DomainID', 'EntityID',
7
+ 'EntityComponentsBundle', 'Property', 'RegistryError',
8
+ 'SystemFunction', 'BulkSystemFunction', 'UnknownArchetypeError',
9
+ 'UnknownComponentError', 'UnknownEntityError',
10
+ 'UnknownSystemError', 'add_component', 'add_components',
11
+ 'add_system', 'add_system_to_domain', 'add_to_archetype',
12
+ 'cid_of_comp', 'cids_of_eid', 'clear_properties', 'comp_of_eid',
13
+ 'comps_of_archetype', 'comps_of_eid', 'create_archetype',
14
+ 'create_entity', 'eid_has', 'eid_of_comp', 'eids_by_cids',
15
+ 'eids_by_property', 'has', 'has_property', 'healthcheck',
16
+ 'purge_by_property', 'remove_archetype', 'remove_component',
17
+ 'remove_entity', 'remove_from_archetype', 'remove_property',
18
+ 'remove_system', 'remove_system_from_domain', 'reset',
19
+ 'run_all_systems', 'run_bulk_system', 'run_domain', 'run_system',
20
+ 'set_properties', 'set_property', 'update_component',]
20
21
 
21
22
  type EntityID = Hashable
22
23
  type ComponentID = Hashable
@@ -32,7 +33,11 @@ type _RunSystemResult = dict[EntityID, Any]
32
33
  # The typehinting system can't work with functions using *args, **kwargs.
33
34
  # This solution comes from https://docs.python.org/3/library/typing.html#annotating-callable-objects
34
35
  class SystemFunction(Protocol):
35
- def __call__(self, eid: EntityID, *cids: ComponentID, **kwargs: dict[str, object]) -> Any: ...
36
+ def __call__(self, eid: EntityID, *cids: ComponentID, **kwargs: dict[str, Any]) -> Any: ...
37
+
38
+
39
+ class BulkSystemFunction(Protocol):
40
+ def __call__(self, call_list: list[tuple[EntityID, *tuple[Component, ...]]], **kwargs: dict[str, Any]) -> Any: ...
36
41
 
37
42
 
38
43
  eidx = {} # entity index
@@ -71,14 +76,14 @@ class RegistryError(Exception):
71
76
  :param eid: The entity ID of the defective registry entry
72
77
  :param cid: The component ID of the defective registry entry
73
78
  :param component: The component object of the defective registry entry
74
- :param eid: The properties of the defective registry entry
79
+ :param other: Component in cidx when eidx and cidx mismatch
75
80
 
76
81
  Contains an error message and the registry objects that have been
77
82
  identified as inconsistent.
78
83
  """
79
84
 
80
85
  def __init__(self, error, *, eid, cid=None, component=None, other=None, properties=None):
81
- self.error = error
86
+ super().__init__(error)
82
87
  self.eid = eid
83
88
  self.cid = cid
84
89
  self.component = component
@@ -149,7 +154,7 @@ def create_entity(tag: EntityID = None,
149
154
  :return: The entity ID. Same as given if one is passed, otherwise a uuid4
150
155
  """
151
156
 
152
- eid = tag if tag else str(uuid4())
157
+ eid = tag if tag is not None else str(uuid4())
153
158
  if eid not in eidx:
154
159
  eidx[eid] = {}
155
160
 
@@ -208,6 +213,11 @@ def add_component(eid: EntityID, cid: ComponentID, comp: Component) -> Component
208
213
  .. note:: Technically, there is no reason a comp object couldn't
209
214
  have methods, but by concept, functionality is reserved for the System
210
215
  working on the components, not the component itself.
216
+
217
+ .. note:: This function is also aliased to `update_component` just to be
218
+ able to make it clear in the user code, that a component will be
219
+ replaced. Consider it semantic sugar.
220
+
211
221
  """
212
222
 
213
223
  if eid not in eidx:
@@ -219,12 +229,16 @@ def add_component(eid: EntityID, cid: ComponentID, comp: Component) -> Component
219
229
  # Make sure, when replacing a component, the the old one is removed from
220
230
  # oidx for this entity.
221
231
  try:
222
- old_comp = id(eidx[eid][cid])
223
- oidx[old_comp].discard(eid)
224
- if not oidx[old_comp]:
225
- del oidx[old_comp]
232
+ old_comp = eidx[eid][cid]
226
233
  except KeyError:
227
234
  pass
235
+ else:
236
+ old_comp_id = id(old_comp)
237
+ oidx[old_comp_id].discard(eid)
238
+ if not oidx[old_comp_id]:
239
+ del oidx[old_comp_id]
240
+ if hasattr(old_comp, 'shutdown_'):
241
+ old_comp.shutdown_()
228
242
 
229
243
  cidx[cid][eid] = comp
230
244
  eidx[eid][cid] = comp
@@ -242,7 +256,7 @@ def add_components(eid: EntityID, components: dict[ComponentID, Component]) -> l
242
256
  """A convenience wrapper around add_component.
243
257
 
244
258
  :param components: A dict with component IDs as keys and components as values (see add_component)
245
- :return: None
259
+ :return: list of added component IDs
246
260
  """
247
261
 
248
262
  return [add_component(eid, cid, comp) for cid, comp in components.items()]
@@ -255,8 +269,8 @@ def remove_component(eid: EntityID, *cids: ComponentID) -> None:
255
269
  :param cids: The component ids to remove
256
270
  :return: None
257
271
 
258
- If the component has a shutdown\_ attribute, it is assumed to be a list of
259
- zero parameter functions to be called in order.
272
+ If the component has a shutdown\_ attribute, it is assumed to be a
273
+ zero parameter function that is called after the component removal.
260
274
 
261
275
  .. note:: If the entity no longer exists, the error is silently ignored.
262
276
 
@@ -291,11 +305,10 @@ def add_system(fn: SystemFunction, *cids: ComponentID) -> None:
291
305
 
292
306
  The prototype for the function is::
293
307
 
294
- fn(delta_time, eid, *comps)
308
+ fn(eid, *comps, **kwargs)
295
309
 
296
- where delta_time is e.g. the miliseconds from a pygame tick. eid is the id
297
- of the entity that matches, and \*comps are all requested components for
298
- this specific entity.
310
+ eid is the id of the entity that matches, and \*comps are all requested
311
+ components for this specific entity.
299
312
 
300
313
  This function is called for every entity that matches all specified
301
314
  component ids.
@@ -340,10 +353,10 @@ def add_system_to_domain(domain: DomainID, system: SystemFunction) -> None:
340
353
  .. important:: The system must first be registered with add_system.
341
354
  """
342
355
 
343
- if domain not in didx:
344
- didx[domain] = set()
345
356
  if system not in sidx:
346
357
  raise UnknownSystemError(f'system {system} is not registered')
358
+ if domain not in didx:
359
+ didx[domain] = set()
347
360
  didx[domain].add(system)
348
361
 
349
362
 
@@ -387,9 +400,14 @@ def eid_has(eid: EntityID, *cids: ComponentID) -> bool:
387
400
 
388
401
  :param cids: All component ids that need to match
389
402
  :return: True if all given cids are available for the specified eid
403
+ :raises UnknownEntityError: If the entity is not registered (anymore).
390
404
  """
391
405
 
392
- e = eidx[eid]
406
+ try:
407
+ e = eidx[eid]
408
+ except KeyError:
409
+ raise UnknownEntityError
410
+
393
411
  for cid in cids:
394
412
  if cid not in e:
395
413
  return False
@@ -401,7 +419,7 @@ def eids_by_cids(*cids: ComponentID, has_properties: _OptionalProperties = None)
401
419
  """Get eids that match all specified cids.
402
420
 
403
421
  :param cids: All component ids that need to match
404
- :param as_properties: Optional set/tuple/list of required properties
422
+ :param has_properties: Optional set/tuple/list of required properties
405
423
  :return: A list of tuples of entity IDs and components
406
424
  """
407
425
 
@@ -454,7 +472,7 @@ def comps_of_eid(eid: EntityID, *cids: ComponentID) -> list[Component]:
454
472
  While cids_of_eid gets component IDs, this function now gets the actual
455
473
  components containing the data.
456
474
 
457
- .. note:: If cids is empty or None, returns all components of eid.
475
+ .. note:: If no cids are given, returns all components of eid.
458
476
  """
459
477
 
460
478
  if eid not in eidx:
@@ -484,10 +502,10 @@ def eid_of_comp(comp: Component) -> set[EntityID]:
484
502
  """Find the entity id for object comp.
485
503
 
486
504
  :param comp: The component to find the entity of
487
- :return: The entity_id the given component belongs to
505
+ :return: A set of all entity IDs that contain the given component.
488
506
  """
489
507
 
490
- return oidx[id(comp)]
508
+ return oidx.get(id(comp), set())
491
509
 
492
510
 
493
511
  def cid_of_comp(eid: EntityID, comp: Component) -> ComponentID:
@@ -564,7 +582,7 @@ def run_system(fn: SystemFunction,
564
582
  return {eid: fn(eid, *parms, **kwargs) for eid, *parms in call_list}
565
583
 
566
584
 
567
- def run_bulk_system(fn: SystemFunction,
585
+ def run_bulk_system(fn: BulkSystemFunction,
568
586
  *cids: ComponentID,
569
587
  has_properties: _OptionalProperties = None,
570
588
  **kwargs: dict[str, Any]) -> Any:
@@ -573,18 +591,28 @@ def run_bulk_system(fn: SystemFunction,
573
591
  :param fn: the actual system function
574
592
  :param cids: the components to run on
575
593
  :param has_properties: set of required properties
576
- :return: A dictionary with entity IDs as key and the function result as value
594
+ :return: Returns whatever the given callback returns or None if no
595
+ matching entities have been found
577
596
 
578
- The fn is called with a list of entity ID and components tuples of all
597
+ The fn is called with a list of `(eid, comp...)` tuples of all
579
598
  entities that contain the listed components. The list can further be
580
599
  narrowed down my filtering for given properties.
581
600
 
582
- ``fn`` is called given a list of ``(EntityID, (components,...))``. In
601
+ ``fn`` is called given a list of ``(EntityID, components,...)``. In
583
602
  contrast to ``run_system``, the user is responsible to loop over the list.
584
603
 
604
+ If no entities are found, `fn` is not called.
605
+
585
606
  The prototype of ``fn`` is::
586
607
 
587
- def callback(call_list: list[tuple[EntityID, list[Component]]]) -> Any
608
+ def callback(call_list: list[tuple[EntityID, *tuple[Component, ...]]], **kwargs) -> Any
609
+
610
+ Example::
611
+
612
+ def sys_bulk_render(entities_and_comps):
613
+ for eid, pos, sprite in entities_and_comps:
614
+ ...
615
+
588
616
  """
589
617
 
590
618
  call_list = _create_call_list(cids, has_properties)
@@ -654,20 +682,23 @@ def create_archetype(*cids: ComponentID) -> None:
654
682
 
655
683
 
656
684
  def remove_archetype(cids: Iterable[ComponentID]) -> None:
657
- """Remove an archetype from the system. (See `add_archetype`).
685
+ """Remove an archetype from the system. (See `create_archetype`).
658
686
 
659
687
  :param cids: The list of component IDs that construct the archetype.
660
688
  :return: None
661
689
  """
662
690
 
663
691
  at = tuple(cids)
664
- del archetype[at]
692
+ try:
693
+ del archetype[at]
694
+ except KeyError:
695
+ pass
665
696
 
666
697
 
667
698
  def add_to_archetype(eid: EntityID) -> None:
668
699
  """Make sure, eid is registered with all appropriate archetypes.
669
700
 
670
- :param eids: The entity ID to add to the archetype
701
+ :param eid: The entity ID to add to the archetype
671
702
 
672
703
  There should be no need to call this function manually. It's called
673
704
  internally, when a new component is added to an entity which makes this
@@ -687,7 +718,7 @@ def add_to_archetype(eid: EntityID) -> None:
687
718
  def remove_from_archetype(eid: EntityID, cid: ComponentID | None = None) -> None:
688
719
  """Make sure, eid is only registered with appropriate archetypes.
689
720
 
690
- :param eids: The entity ID to remove from the archetype
721
+ :param eid: The entity ID to remove from the archetype
691
722
  :param cid: An optional component ID.
692
723
 
693
724
  There should be no need to call this function manually. It's called
@@ -726,11 +757,11 @@ def comps_of_archetype(*cids: ComponentID, has_properties: _OptionalProperties =
726
757
  return [(e, comps) for e, comps in archetype[at].items()]
727
758
 
728
759
 
729
- def set_property(eid: EntityID, property: Property) -> None:
760
+ def set_property(eid: EntityID, prop: Property) -> None:
730
761
  """Add a property to the given entity.
731
762
 
732
763
  :param eid: The entity id to add the component to
733
- :param property: A flag or tag that can be filtered, e.g. 'is_drawable'
764
+ :param prop: A flag or tag that can be filtered, e.g. 'is_drawable'
734
765
  :return: None
735
766
  :raises UnknownEntityError: If the entity is not registered (anymore).
736
767
  """
@@ -738,14 +769,14 @@ def set_property(eid: EntityID, property: Property) -> None:
738
769
  if eid not in eidx:
739
770
  raise UnknownEntityError(f'Entity {eid} is not registered')
740
771
 
741
- plist[eid].add(property)
772
+ plist[eid].add(prop)
742
773
 
743
774
 
744
775
  def set_properties(eid: EntityID, properties: Iterable[Property]) -> None:
745
776
  """Add a list of properties to the given entity.
746
777
 
747
778
  :param eid: The entity ID to add the properties to.
748
- :param property: The list of properties to add.
779
+ :param properties: The list of properties to add.
749
780
 
750
781
  This is just a convenience wrapper around `set_property`.
751
782
  """
@@ -757,7 +788,7 @@ def has_property(eid: EntityID, prop: Property) -> bool:
757
788
  """Checks if the given entity has that property.
758
789
 
759
790
  :param eid: The entity id to add the component to
760
- :param property: The property to check for
791
+ :param prop: The property to check for
761
792
  :return: True if the property is set for the given entity
762
793
  :raises UnknownEntityError: If the entity is not registered (anymore).
763
794
  """
@@ -772,7 +803,7 @@ def remove_property(eid: EntityID, prop: Property) -> None:
772
803
  """Removes a property from the given entity.
773
804
 
774
805
  :param eid: The entity id to add the component to
775
- :param property: The property to remove
806
+ :param prop: The property to remove
776
807
  :return: None
777
808
  :raises UnknownEntityError: If the entity is not registered (anymore).
778
809
  """
@@ -780,7 +811,10 @@ def remove_property(eid: EntityID, prop: Property) -> None:
780
811
  if eid not in eidx:
781
812
  raise UnknownEntityError(f'Entity {eid} is not registered')
782
813
 
783
- plist[eid].remove(prop)
814
+ try:
815
+ plist[eid].remove(prop)
816
+ except KeyError:
817
+ pass
784
818
 
785
819
 
786
820
  def clear_properties(eid: EntityID) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tinyecs
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: The teeniest, tiniest ECS system
5
5
  Author-email: Michael Lamertz <michael.lamertz@gmail.com>
6
6
  License-Expression: MIT
@@ -13,7 +13,19 @@ Classifier: Topic :: Games/Entertainment
13
13
  Classifier: Topic :: Software Development :: Libraries :: pygame
14
14
  Description-Content-Type: text/x-rst
15
15
  License-File: LICENSE
16
- Requires-Dist: pgcooldown
16
+ Provides-Extra: base
17
+ Requires-Dist: tinyecs-compsys-base; extra == "base"
18
+ Provides-Extra: dynamics
19
+ Requires-Dist: tinyecs-compsys-dynamics; extra == "dynamics"
20
+ Provides-Extra: patternengine
21
+ Requires-Dist: tinyecs-compsys-patternengine; extra == "patternengine"
22
+ Provides-Extra: sdl2
23
+ Requires-Dist: tinyecs-compsys-sdl2; extra == "sdl2"
24
+ Provides-Extra: demos
25
+ Requires-Dist: tinyecs[base,dynamics,sdl2]; extra == "demos"
26
+ Requires-Dist: tinyecs-demos; extra == "demos"
27
+ Provides-Extra: all
28
+ Requires-Dist: tinyecs[base,demos,dynamics,patternengine,sdl2]; extra == "all"
17
29
  Dynamic: license-file
18
30
 
19
31
  Introduction
@@ -73,15 +85,6 @@ Issues can be opened on `github issues`_
73
85
 
74
86
  .. _github issues: https://github.com/dickerdackel/tinyecs/issues
75
87
 
76
- Please respect, that I don't want any contributions done with the assistance
77
- of AI. This is a hobby project with focus on the craft of programming. I
78
- have experimentally used AI to audit parts of the code and documentation, and
79
- while it found a lot of typos and 2 actual issues, without exception, the
80
- provided solutions were often besides the point or plain wrong.
81
-
82
- I have no possibility to enforce that request, the simple fact that I ask for
83
- it should be sufficient.
84
-
85
88
  License
86
89
  =======
87
90
 
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.rst
3
+ pyproject.toml
4
+ src/tinyecs/__init__.py
5
+ src/tinyecs/tutorial.py
6
+ src/tinyecs.egg-info/PKG-INFO
7
+ src/tinyecs.egg-info/SOURCES.txt
8
+ src/tinyecs.egg-info/dependency_links.txt
9
+ src/tinyecs.egg-info/requires.txt
10
+ src/tinyecs.egg-info/top_level.txt
11
+ tests/test_tinyecs.py
@@ -0,0 +1,19 @@
1
+
2
+ [all]
3
+ tinyecs[base,demos,dynamics,patternengine,sdl2]
4
+
5
+ [base]
6
+ tinyecs-compsys-base
7
+
8
+ [demos]
9
+ tinyecs[base,dynamics,sdl2]
10
+ tinyecs-demos
11
+
12
+ [dynamics]
13
+ tinyecs-compsys-dynamics
14
+
15
+ [patternengine]
16
+ tinyecs-compsys-patternengine
17
+
18
+ [sdl2]
19
+ tinyecs-compsys-sdl2
@@ -338,17 +338,21 @@ def test_eid_has():
338
338
  def test_shutdown():
339
339
  ecs.reset()
340
340
 
341
- shutdown_successful = False
341
+ class HasShutdown(Exception): ...
342
342
 
343
343
  class ShutdownEntity():
344
344
  def shutdown_(self):
345
- nonlocal shutdown_successful
346
- shutdown_successful = True
345
+ raise HasShutdown()
347
346
 
348
- e = ecs.create_entity()
349
- ecs.add_component(e, 'shutdown-test', ShutdownEntity())
350
- ecs.remove_entity(e)
351
- assert shutdown_successful
347
+ eid = ecs.create_entity()
348
+ ecs.add_component(eid, 'shutdown-test', ShutdownEntity())
349
+ with pytest.raises(HasShutdown) as e:
350
+ ecs.add_component(eid, 'shutdown-test', ShutdownEntity())
351
+ assert e.type == HasShutdown
352
+
353
+ with pytest.raises(HasShutdown) as e:
354
+ ecs.remove_entity(eid)
355
+ assert e.type == HasShutdown
352
356
 
353
357
 
354
358
  def test_cid_of_comp():
@@ -536,6 +540,7 @@ if __name__ == '__main__':
536
540
  test_cids_of_eid()
537
541
  test_comps_of_eid()
538
542
  test_run_system()
543
+ test_run_bulk_system()
539
544
  test_run_all_systems()
540
545
  test_remove_system()
541
546
  test_remove_entity()
@@ -546,7 +551,6 @@ if __name__ == '__main__':
546
551
  test_add_system_to_domain()
547
552
  test_remove_system_from_domain()
548
553
  test_run_domain()
549
- test_is_eid()
550
554
  test_eid_has()
551
555
  test_shutdown()
552
556
  test_cid_of_comp()
@@ -561,3 +565,5 @@ if __name__ == '__main__':
561
565
  test_property_archetype()
562
566
  test_property_find_entities()
563
567
  test_property_clear()
568
+ test_property_purge()
569
+ test_property_eid_unknown()
@@ -1 +0,0 @@
1
- from .compsys import *