From dd766ff21737b75c530179bbdfa68eac7b7efcf5 Mon Sep 17 00:00:00 2001 From: K <111819113+KennySwayzee93@users.noreply.github.com> Date: Sun, 22 Jun 2025 10:52:11 -0400 Subject: [PATCH] env variable support --- puzzle-generator/.env.example | 5 + .../src/utils/EnvironmentManager.py | 104 ++++++++++++++++++ puzzle-generator/src/utils/SystemSpecs.py | 13 ++- puzzle-generator/src/utils/__init__.py | 3 +- 4 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 puzzle-generator/src/utils/EnvironmentManager.py diff --git a/puzzle-generator/.env.example b/puzzle-generator/.env.example index ee29e47..a759e84 100644 --- a/puzzle-generator/.env.example +++ b/puzzle-generator/.env.example @@ -5,3 +5,8 @@ DATABASE_USER= # Required for PostgreSQL, leave blank for SQ DATABASE_PASSWORD= # Required for PostgreSQL, leave blank for SQLite DATABASE_HOST=localhost # Required for PostgreSQL, typically "localhost" or an IP address DATABASE_PORT=5432 # Default PostgreSQL port, leave as-is or set if using a different port + +# System resource configuration +PARALLELISM_DIVISOR=1 # Controls CPU core usage: CPU cores / PARALLELISM_DIVISOR = cores used + # Example: 16 cores with PARALLELISM_DIVISOR=2 will use 8 cores + # Default is 2 if not specified, set to 1 to use all available cores diff --git a/puzzle-generator/src/utils/EnvironmentManager.py b/puzzle-generator/src/utils/EnvironmentManager.py new file mode 100644 index 0000000..222eb3b --- /dev/null +++ b/puzzle-generator/src/utils/EnvironmentManager.py @@ -0,0 +1,104 @@ +"""Utility class for environment variable management.""" + +import os +from enum import Enum +from typing import Any, cast + + +class EnvVarType(Enum): + """Types of environment variables.""" + INT = "int" + STRING = "str" + BOOL = "bool" + + +class EnvironmentVariables(Enum): + """ + Enum of known environment variables used in the application. + + Each enum value is a tuple of (env_var_name, default_value, type). + """ + PARALLELISM_DIVISOR = ("PARALLELISM_DIVISOR", 2, EnvVarType.INT) + + def __init__(self, env_name: str, default_value: Any, var_type: EnvVarType): + self.env_name = env_name + self.default_value = default_value + self.var_type = var_type + + +class EnvironmentManager: + """Static utility class for environment variable management.""" + + @staticmethod + def get_value(env_var: EnvironmentVariables, override_default: Any = None) -> Any: + """ + Get a value from an environment variable with appropriate type conversion. + + Args: + env_var: The environment variable to retrieve + override_default: Optional value to override the default defined in the enum + + Returns: + The value of the environment variable or the default with appropriate type + """ + # Use override_default if provided, otherwise use the enum's default + default = override_default if override_default is not None else env_var.default_value + + # Get the value from environment + value = os.environ.get(env_var.env_name) + if value is None: + return default + + # Convert to appropriate type + if env_var.var_type == EnvVarType.INT: + try: + return int(value) + except ValueError: + # Log warning here if needed + return default + elif env_var.var_type == EnvVarType.BOOL: + return value.lower() in ('true', 'yes', '1', 'y') + else: # STRING or any other type + return value + + @staticmethod + def get_int(env_var: EnvironmentVariables, default = None) -> int: + """ + Get an integer value from an environment variable. + + Args: + env_var: The environment variable to retrieve + default: Optional value to override the default defined in the enum + + Returns: + int: The value of the environment variable or the default + """ + return cast(int, EnvironmentManager.get_value(env_var, default)) + + @staticmethod + def get_string(env_var: EnvironmentVariables, default = None) -> str: + """ + Get a string value from an environment variable. + + Args: + env_var: The environment variable to retrieve + default: Optional value to override the default defined in the enum + + Returns: + str: The value of the environment variable or the default + """ + return cast(str, EnvironmentManager.get_value(env_var, default)) + + @staticmethod + def get_bool(env_var: EnvironmentVariables, default = None) -> bool: + """ + Get a boolean value from an environment variable. + + Args: + env_var: The environment variable to retrieve + default: Optional value to override the default defined in the enum + + Returns: + bool: The value of the environment variable or the default + """ + return cast(bool, EnvironmentManager.get_value(env_var, default)) diff --git a/puzzle-generator/src/utils/SystemSpecs.py b/puzzle-generator/src/utils/SystemSpecs.py index 8c4dbe4..617d4ce 100644 --- a/puzzle-generator/src/utils/SystemSpecs.py +++ b/puzzle-generator/src/utils/SystemSpecs.py @@ -1,6 +1,7 @@ """Utility class for system specifications and resource management.""" import multiprocessing +from .EnvironmentManager import EnvironmentManager, EnvironmentVariables class SystemSpecs: @@ -11,10 +12,16 @@ def get_num_parallel_processes() -> int: """ Calculate the optimal number of parallel processes to use. - Returns half the number of CPU cores, with a minimum of 1. + Returns the number of CPU cores divided by the parallelization divisor, + with a minimum of 1. + + The parallelization divisor can be configured via the PARALLELISM_DIVISOR + environment variable. Default is 2. Returns: int: Number of parallel processes to use """ - parallelization_denominator = 2 # if cpu has 16 cores and parallelization denominator is 2 then this codebase will use 8 cores - return multiprocessing.cpu_count() // parallelization_denominator or 1 # default to 1 if only 1 core available + parallelism_divisor = EnvironmentManager.get_int( + EnvironmentVariables.PARALLELISM_DIVISOR + ) + return multiprocessing.cpu_count() // parallelism_divisor or 1 # default to 1 if only 1 core available diff --git a/puzzle-generator/src/utils/__init__.py b/puzzle-generator/src/utils/__init__.py index d3d10ee..9d27307 100644 --- a/puzzle-generator/src/utils/__init__.py +++ b/puzzle-generator/src/utils/__init__.py @@ -1,5 +1,6 @@ """Utility modules for the puzzle generator.""" from .SystemSpecs import SystemSpecs +from .EnvironmentManager import EnvironmentManager, EnvironmentVariables -__all__ = ["SystemSpecs"] +__all__ = ["SystemSpecs", "EnvironmentManager", "EnvironmentVariables"]