From 20006ed951333f64b998da7021d2cd16d4ccff2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Schr=C3=B6der?=
 <fschroeder@techfak.uni-bielefeld.de>
Date: Thu, 7 Mar 2024 17:46:09 +0100
Subject: [PATCH] Add constructor docstrings and type hints in classes

Added docstrings to constructors of several classes in various modules to improve code readability and maintainability. Also, explicit type hints were provided for the fields in these classes aiding in better understanding of the data types used across the codebase.
---
 cooperative_cuisine/effects.py      |  6 ++++++
 cooperative_cuisine/environment.py  | 11 ++++++++++
 cooperative_cuisine/game_server.py  |  5 +++++
 cooperative_cuisine/info_msg.py     | 19 ++++++++++++++---
 cooperative_cuisine/items.py        | 33 ++++++++++++++++++++++++++++-
 cooperative_cuisine/movement.py     | 22 +++++++++++++------
 cooperative_cuisine/orders.py       | 20 +++++++++++++++++
 cooperative_cuisine/player.py       |  7 ++++++
 cooperative_cuisine/recording.py    |  9 ++++++++
 cooperative_cuisine/scores.py       | 11 ++++++++++
 cooperative_cuisine/study_server.py |  8 +++++++
 cooperative_cuisine/validation.py   |  8 +++++++
 12 files changed, 149 insertions(+), 10 deletions(-)

diff --git a/cooperative_cuisine/effects.py b/cooperative_cuisine/effects.py
index b9e04a3f..3688ce64 100644
--- a/cooperative_cuisine/effects.py
+++ b/cooperative_cuisine/effects.py
@@ -37,6 +37,12 @@ class EffectManager:
     """
 
     def __init__(self, hook: Hooks, random: Random) -> None:
+        """Constructor for EffectManager.
+
+        Args:
+            hook: An instance of the Hooks class representing the hooks in the environment.
+            random: An instance of the Random class representing the random number generator.
+        """
         self.effects = []
         """A list of ItemInfo objects representing the effects managed by the manager."""
         self.counters = []
diff --git a/cooperative_cuisine/environment.py b/cooperative_cuisine/environment.py
index c166aa2b..3b282618 100644
--- a/cooperative_cuisine/environment.py
+++ b/cooperative_cuisine/environment.py
@@ -110,6 +110,17 @@ class Environment:
         env_name: str = "overcooked_sim",
         seed: int = 56789223842348,
     ):
+        """Constructor of the Environment.
+
+        Args:
+            env_config: The path or string representation of the environment configuration file.
+            layout_config: The path or string representation of the layout configuration file.
+            item_info: The path or string representation of the item info file.
+            as_files: (optional) A flag indicating whether the configuration parameters are file paths.
+                      If True, the method will read the contents of the files. Defaults to True.
+            env_name: (optional) The name of the environment. Defaults to "overcooked_sim".
+            seed: (optional) The seed for generating random numbers. Defaults to 56789223842348.
+        """
         self.env_name = env_name
         """Reference to the run. E.g, the env id."""
         self.env_time: datetime = create_init_env_time()
diff --git a/cooperative_cuisine/game_server.py b/cooperative_cuisine/game_server.py
index 6cf18d8f..d27db578 100644
--- a/cooperative_cuisine/game_server.py
+++ b/cooperative_cuisine/game_server.py
@@ -124,6 +124,11 @@ class EnvironmentHandler:
     """Running several environments for a game server."""
 
     def __init__(self, env_step_frequency: int = 200):
+        """Constructor of EnvironmentHandler.
+
+        Args:
+            env_step_frequency (int): The frequency at which the environment steps. Defaults to 200.
+        """
         self.envs: dict[str, EnvironmentData] = {}
         """A dictionary of environment IDs and their respective data."""
         self.player_data: dict[str, PlayerData] = {}
diff --git a/cooperative_cuisine/info_msg.py b/cooperative_cuisine/info_msg.py
index 62b98a84..3d6d9525 100644
--- a/cooperative_cuisine/info_msg.py
+++ b/cooperative_cuisine/info_msg.py
@@ -54,10 +54,23 @@ class InfoMsgManager(HookCallbackClass):
         level: str = "Normal",
         **kwargs
     ):
+        """Constructor of InfoMsgManager.
+
+        Args:
+            name (str): The name of the instance.
+            env (Environment): The environment in which the instance exists.
+            msg (str): The message associated with the instance.
+            duration (int, optional): The duration of the instance (in seconds). Defaults to 5.
+            level (str, optional): The level of the instance. Defaults to "Normal".
+            **kwargs: Additional keyword arguments.
+        """
         super().__init__(name, env, **kwargs)
-        self.msg = msg
-        self.duration = timedelta(seconds=duration)
-        self.level = level
+        self.msg: str = msg
+        """Text message to display when the hook is called."""
+        self.duration: timedelta = timedelta(seconds=duration)
+        """Duration of the msg to display."""
+        self.level: str = level
+        """Level of the msg, e.g., "Normal", "Warning", "Success"."""
 
     def __call__(self, hook_ref: str, env: Environment, **kwargs):
         for player_id in env.players:
diff --git a/cooperative_cuisine/items.py b/cooperative_cuisine/items.py
index 1b563a15..da74f68a 100644
--- a/cooperative_cuisine/items.py
+++ b/cooperative_cuisine/items.py
@@ -150,6 +150,15 @@ class Item:
     def __init__(
         self, name: str, item_info: ItemInfo, uid: str = None, *args, **kwargs
     ):
+        """Constructor for Item.
+
+        Args:
+            name (str): The name of the item.
+            item_info (ItemInfo): The information about the item from the `item_info.yml` config.
+            uid (str, optional): A unique identifier for the item. Defaults to None.
+            *args: Variable length argument list.
+            **kwargs: Arbitrary keyword arguments.
+        """
         self.name: str = self.__class__.__name__ if name is None else name
         """The name of the item, e.g., `Tomato` or `ChoppedTomato`"""
         self.item_info: ItemInfo = item_info
@@ -225,6 +234,13 @@ class CookingEquipment(Item):
     item_category = COOKING_EQUIPMENT_ITEM_CATEGORY
 
     def __init__(self, transitions: dict[str, ItemInfo], *args, **kwargs):
+        """Constructor for CookingEquipment.
+
+        Args:
+            transitions: A dictionary that represents the transitions or steps needed to cook a meal or create another ingredient. The keys are the names of the transitions and the values are the ItemInfo objects that contain information about the transition.
+            *args: Variable length argument list.
+            **kwargs: Arbitrarily named keyword arguments.
+        """
         super().__init__(*args, **kwargs)
         self.transitions: dict[str, ItemInfo] = transitions
         """What is needed to cook a meal / create another ingredient."""
@@ -390,6 +406,14 @@ class Plate(CookingEquipment):
     """The plate can have to states: clean and dirty. In the clean state it can hold content/other items."""
 
     def __init__(self, transitions: dict[str, ItemInfo], clean: bool, *args, **kwargs):
+        """Constructor for Plate.
+
+        Args:
+            transitions: A dictionary mapping meal names to ItemInfo objects representing the transitions for each meal.
+            clean: A boolean indicating whether the plate is clean or dirty.
+            *args: Additional positional arguments.
+            **kwargs: Additional keyword arguments.
+        """
         self.clean: bool = clean
         """If the plate is clean or dirty."""
         self.meals: Set[str] = set(transitions.keys())
@@ -431,12 +455,19 @@ class Effect:
     """Effects on counters and items. Like Fire."""
 
     def __init__(self, name: str, item_info: ItemInfo, uid: str = None):
+        """Constructor for Effect.
+
+        Args:
+            name (str): The name of the effect.
+            item_info (ItemInfo): The item info for the effect, including effect manager, effect type, etc.
+            uid (str, optional): The unique ID of the effect instance. Defaults to None.
+        """
         self.uuid: str = uuid.uuid4().hex if uid is None else uid
         """ID of the effect instance."""
         self.name: str = name
         """Name of the effect"""
         self.item_info: ItemInfo = item_info
-        """Item info of the effect, effect manager, effect type, etc."""
+        """Item info for the effect, effect manager, effect type, etc."""
         self.progres_percentage: float = 0.0
         """For fire: how much the player still has to extinguish."""
 
diff --git a/cooperative_cuisine/movement.py b/cooperative_cuisine/movement.py
index 56956686..320ce086 100644
--- a/cooperative_cuisine/movement.py
+++ b/cooperative_cuisine/movement.py
@@ -24,20 +24,30 @@ class Movement:
     """World borders upper bounds."""
 
     def __init__(self, counter_positions, player_config, world_borders, hook: Hooks):
-        self.counter_positions = counter_positions
+        """Constructor of Movement.
+
+        Args:
+            counter_positions: Positions of all counters in an environment. Needs to be updated if the counters position changes.
+            player_config: Dictionary containing player configuration settings.
+            world_borders: The world border arrays. For easier numpy comparison with player position. The outer dimension needs to be equal to the number of players.
+            hook: Hook manager. Register callbacks and create hook points with additional kwargs.
+        """
+        self.counter_positions: npt.NDArray[float] = counter_positions
         """Positions of all counters in an environment. Needs to be updated if the counters position changes."""
-        self.player_radius = player_config["radius"]
+        self.player_radius: float = player_config["radius"]
         """The radius of a player (indicating its size and collision sphere). Relative to one grid cell, e.g., `0.4`."""
-        self.player_interaction_range = player_config["interaction_range"]
+        self.player_interaction_range: float = player_config["interaction_range"]
         """The range of how far a player can interact with the closest counter."""
-        self.player_movement_speed = player_config["speed_units_per_seconds"]
+        self.player_movement_speed: float | int = player_config[
+            "speed_units_per_seconds"
+        ]
         """How many grid cells a player can move in a second."""
-        self.world_borders = world_borders
+        self.world_borders: npt.NDArray[float] = world_borders
         """The world border arrays. For easier numpy comparison with player position. The outer dimension needs to be 
         equal to the number of player."""
         self.set_collision_arrays(1)
 
-        self.hook = hook
+        self.hook: Hooks = hook
         """Hook manager. Register callbacks and create hook points with additional kwargs."""
 
     def set_collision_arrays(self, number_players: int):
diff --git a/cooperative_cuisine/orders.py b/cooperative_cuisine/orders.py
index 416d78db..d65305e1 100644
--- a/cooperative_cuisine/orders.py
+++ b/cooperative_cuisine/orders.py
@@ -110,6 +110,13 @@ class OrderGeneration:
         random: Random,
         **kwargs,
     ):
+        """Constructor of OrderGeneration.
+
+        Args:
+            hook: An instance of Hooks class.
+            random: An instance of Random class.
+            **kwargs: Additional keyword arguments.
+        """
         self.available_meals: list[ItemInfo] | None = None
         """Available meals restricted through the `environment_config.yml`."""
         self.hook = hook
@@ -143,6 +150,12 @@ class OrderManager:
         hook: Hooks,
         random: Random,
     ):
+        """Constructor of OrderManager.
+        Args:
+            order_config: A dictionary containing the configuration for orders.
+            hook: An instance of the Hooks class.
+            random: An instance of the Random class.
+        """
         self.random = random
         """Random instance."""
         self.order_gen: OrderGeneration = order_config["order_gen_class"](
@@ -374,6 +387,13 @@ class RandomOrderGeneration(OrderGeneration):
         random: Random,
         **kwargs,
     ):
+        """Constructor of RandomOrderGeneration.
+
+        Args:
+            hook (Hooks): The hook object.
+            random (Random): The random object.
+            **kwargs: Additional keyword arguments.
+        """
         super().__init__(hook, random, **kwargs)
         self.kwargs: RandomOrderKwarg = RandomOrderKwarg(**kwargs["kwargs"])
         """Configuration og the RandomOrder genration. See `RandomOrderKwarg`"""
diff --git a/cooperative_cuisine/player.py b/cooperative_cuisine/player.py
index 6dc25caa..d6242a48 100644
--- a/cooperative_cuisine/player.py
+++ b/cooperative_cuisine/player.py
@@ -54,6 +54,13 @@ class Player:
         player_config: PlayerConfig,
         pos: Optional[npt.NDArray[float]] = None,
     ):
+        """Constructor of Player.
+
+        Args:
+            name: The name of the player.
+            player_config: The player's configuration object.
+            pos: The initial position of the player. Defaults to None.
+        """
         self.name: str = name
         """Reference for the player"""
         self.pos: npt.NDArray[float] | None = None
diff --git a/cooperative_cuisine/recording.py b/cooperative_cuisine/recording.py
index 490377ba..a3088199 100644
--- a/cooperative_cuisine/recording.py
+++ b/cooperative_cuisine/recording.py
@@ -68,6 +68,15 @@ class FileRecorder(HookCallbackClass):
         add_hook_ref: bool = False,
         **kwargs,
     ):
+        """Constructor of FileRecorder.
+
+        Args:
+            name (str): The name of the recorder. This name is used to replace the placeholder "LOG_RECORD_NAME" in the default log file path.
+            env (Environment): The environment in which the recorder is being used.
+            log_path (str, optional): The path to the log file. Defaults to "USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl".
+            add_hook_ref (bool, optional): Indicates whether to add a hook reference to the recorded data. Defaults to False.
+            **kwargs: Additional keyword arguments.
+        """
         super().__init__(name, env, **kwargs)
         self.add_hook_ref = add_hook_ref
         """Indicates whether to add a hook reference to the recorded data. Default value is False."""
diff --git a/cooperative_cuisine/scores.py b/cooperative_cuisine/scores.py
index b8cd11b7..5ae2c6ce 100644
--- a/cooperative_cuisine/scores.py
+++ b/cooperative_cuisine/scores.py
@@ -82,6 +82,17 @@ class ScoreViaHooks(HookCallbackClass):
         kwarg_filter: dict[str, Any] = None,
         **kwargs,
     ):
+        """Constructor of ScoreViaHooks.
+
+        Args:
+            name: A string representing the name of the method.
+            env: An instance of the Environment class.
+            static_score: A float representing the static score to be added if no other conditions are met. Default is 0.
+            score_map: A dictionary mapping hook references to scores. Default is None.
+            score_on_specific_kwarg: A string representing the specific keyword argument to score on. Default is None.
+            kwarg_filter: A dictionary representing the filtering condition for keyword arguments. Default is None.
+            **kwargs: Additional keyword arguments to be passed to the parent class.
+        """
         super().__init__(name, env, **kwargs)
         self.score_map = score_map
         """Mapping of hook references to scores."""
diff --git a/cooperative_cuisine/study_server.py b/cooperative_cuisine/study_server.py
index 57ae90e8..ba95e28e 100644
--- a/cooperative_cuisine/study_server.py
+++ b/cooperative_cuisine/study_server.py
@@ -87,6 +87,13 @@ class StudyConfig(BaseModel):
 
 class Study:
     def __init__(self, study_config_path: str | Path, game_url: str, game_port: int):
+        """Constructor of Study.
+
+        Args:
+            study_config_path: The file path or Path object of the study configuration file.
+            game_url: The URL of the game server.
+            game_port: The port number of the game server.
+        """
         with open(study_config_path, "r") as file:
             env_config_f = file.read()
 
@@ -356,6 +363,7 @@ class StudyManager:
     """Class which manages different studies, their creation and connecting participants to them."""
 
     def __init__(self):
+        """Constructor of the StudyManager class."""
         self.game_host: str
         """Host address of the game server where the studies are running their environments."""
         self.game_port: int
diff --git a/cooperative_cuisine/validation.py b/cooperative_cuisine/validation.py
index 2260d873..a76dc033 100644
--- a/cooperative_cuisine/validation.py
+++ b/cooperative_cuisine/validation.py
@@ -45,6 +45,14 @@ class Validation:
         order_manager: OrderManager,
         do_validation: bool,
     ):
+        """Constructor of the Validation class.
+
+        Args:
+            meals (list[ItemInfo]): A list of ItemInfo objects representing meals.
+            item_info (dict[str, ItemInfo]): All ItemInfos from the config.
+            order_manager (OrderManager): For the available meals for orders.
+            do_validation (bool): A boolean indicating whether to perform validation tasks.
+        """
         self.meals: list[ItemInfo] = meals
         """A list of ItemInfo objects representing meals."""
         self.item_info: dict[str, ItemInfo] = item_info
-- 
GitLab