Repository: benmoran56/esper

Issue:
`World().create_entity()` does not create entity if no components are given
**Describe the bug**
As a factory method I assume it creates entity for sure but that do not happen is edge case of missing components.

**To Reproduce**
```python3
import esper

world = esper.World()
entity = world.create_entity()
assert world.entity_exists(entity)  # raises AssertionError
```
```python3
import esper

world = esper.World()
entity = world.create_entity()
assert not world.entity_exists(entity)  # not existing entity

entity_2 = world.create_entity()
assert entity_2 == 2  # Incrementing counter even though 1st one seems not to exist
```

**Expected behavior**
Imo proper behaviour is to be able to create "empty" entity and provide it with components later. Kind of how you do it with builder pattern.
Plus I've found that `add_component()` has logic for creating missing entity and that is most probably result of that bug. Following Single Responsibility Principle, that should not be part of `add_component()` method imo. See example below:
```python3
import esper

world = esper.World()
made_up_entity = 123
world.add_component(made_up_entity, None)  # Imo should raise KeyError because of missing entity
world.entity_exists(made_up_entity)  # Works just fine and should not
```

**Development environment:**
 - Python 3.11
 - Esper 2.4

**Fix proposal**
To fix that it is simple enough to pull https://github.com/benmoran56/esper/blob/master/esper/__init__.py#L227 
```python3
if entity not in self._entities:
    self._entities[entity] = {}
```
out of for loop in `create_entity()` method.
Consider removing entity creation from `add_component()` method. 

Tell me what do you think about it, I can implement change and unit tests later on

Discussion:
gretkierewicz: @benmoran56 

Patch:
diff --git a/esper/__init__.py b/esper/__init__.py
index c67b5dd..5ac17a7 100644
--- a/esper/__init__.py
+++ b/esper/__init__.py
@@ -215,6 +215,9 @@ class World:
 
         entity = self._next_entity_id
 
+        if entity not in self._entities:
+            self._entities[entity] = {}
+
         for component_instance in components:
 
             component_type = type(component_instance)
@@ -224,9 +227,6 @@ class World:
 
             self._components[component_type].add(entity)
 
-            if entity not in self._entities:
-                self._entities[entity] = {}
-
             self._entities[entity][component_type] = component_instance
             self.clear_cache()
 
@@ -314,9 +314,6 @@ class World:
 
         self._components[component_type].add(entity)
 
-        if entity not in self._entities:
-            self._entities[entity] = {}
-
         self._entities[entity][component_type] = component_instance
         self.clear_cache()
 


Test patch:
diff --git a/tests/test_world.py b/tests/test_world.py
index 8af332f..126102c 100644
--- a/tests/test_world.py
+++ b/tests/test_world.py
@@ -39,6 +39,11 @@ def test_create_entity_with_components(world):
     assert world.has_component(entity2, ComponentB) is True
 
 
+def test_adding_component_to_not_existing_entity_raises_error(world):
+    with pytest.raises(KeyError):
+        world.add_component(123, ComponentA())
+
+
 def test_create_entity_and_add_components(world):
     entity1 = world.create_entity()
     world.add_component(entity1, ComponentA())
@@ -59,18 +64,17 @@ def test_delete_entity(world):
     world.add_component(entity1, ComponentC())
     entity2 = world.create_entity()
     world.add_component(entity2, ComponentD())
-    entity3 = world.create_entity()
-    world.add_component(entity3, ComponentE())
-    entity4 = world.create_entity()
+    entity_with_component = world.create_entity()
+    world.add_component(entity_with_component, ComponentE())
+    empty_entity = world.create_entity()
 
-    assert entity3 == 3
-    world.delete_entity(entity3, immediate=True)
+    assert entity_with_component == 3
+    world.delete_entity(entity_with_component, immediate=True)
     with pytest.raises(KeyError):
-        world.components_for_entity(entity3)
+        world.components_for_entity(entity_with_component)
     with pytest.raises(KeyError):
         world.delete_entity(999, immediate=True)
-    with pytest.raises(KeyError):
-        world.delete_entity(entity4, immediate=True)
+    world.delete_entity(empty_entity, immediate=True)
 
 
 def test_component_for_entity(world):
@@ -256,17 +260,22 @@ def test_cache_results(world):
     assert len(list(query for query in world.get_components(ComponentB, ComponentC))) == 1
 
 
-def test_entity_exists(world):
-    dead_entity = world.create_entity(ComponentB())
-    world.delete_entity(dead_entity)
-    empty_entity = world.create_entity()
-    existent_entity = world.create_entity(ComponentA())
-    future_entity = existent_entity + 1
+class TestEntityExists:
+    def test_dead_entity(self, world):
+        dead_entity = world.create_entity(ComponentB())
+        world.delete_entity(dead_entity)
+        assert not world.entity_exists(dead_entity)
+
+    def test_not_created_entity(self, world):
+        assert not world.entity_exists(123)
+
+    def test_empty_entity(self, world):
+        empty_entity = world.create_entity()
+        assert world.entity_exists(empty_entity)
 
-    assert world.entity_exists(existent_entity)
-    assert not world.entity_exists(dead_entity)
-    assert not world.entity_exists(empty_entity)
-    assert not world.entity_exists(future_entity)
+    def test_entity_with_component(self, world):
+        entity_with_component = world.create_entity(ComponentA())
+        assert world.entity_exists(entity_with_component)
 
 
 def test_event_dispatch_no_handlers():