Repository: inventree/InvenTree

Issue:
[FR] Add typecasting to certain settings
Typecasting in the settings for:

Looks like there are 6 envs that need to be int (that I can find)
- [x] INVENTREE_LOGIN_CONFIRM_DAYS
- [x] INVENTREE_LOGIN_ATTEMPTS
- [x] INVENTREE_EMAIL_PORT
- [x] INVENTREE_DB_PORT
- [x] INVENTREE_CACHE_PORT
~~INVENTREE_WEB_PORT~~

_Originally posted by @stavros-k in https://github.com/inventree/InvenTree/issues/3655#issuecomment-1259866326_
      
[FR] Add typecasting to certain settings
Typecasting in the settings for:

Looks like there are 6 envs that need to be int (that I can find)
- [x] INVENTREE_LOGIN_CONFIRM_DAYS
- [x] INVENTREE_LOGIN_ATTEMPTS
- [x] INVENTREE_EMAIL_PORT
- [x] INVENTREE_DB_PORT
- [x] INVENTREE_CACHE_PORT
~~INVENTREE_WEB_PORT~~

_Originally posted by @stavros-k in https://github.com/inventree/InvenTree/issues/3655#issuecomment-1259866326_
      


Discussion:

Resolving patch:
diff --git a/InvenTree/InvenTree/config.py b/InvenTree/InvenTree/config.py
--- a/InvenTree/InvenTree/config.py
+++ b/InvenTree/InvenTree/config.py
@@ -58,7 +58,7 @@ def load_config_data() -> map:
     return data
 
 
-def get_setting(env_var=None, config_key=None, default_value=None):
+def get_setting(env_var=None, config_key=None, default_value=None, typecast=None):
     """Helper function for retrieving a configuration setting value.
 
     - First preference is to look for the environment variable
@@ -69,15 +69,24 @@ def get_setting(env_var=None, config_key=None, default_value=None):
         env_var: Name of the environment variable e.g. 'INVENTREE_STATIC_ROOT'
         config_key: Key to lookup in the configuration file
         default_value: Value to return if first two options are not provided
-
+        typecast: Function to use for typecasting the value
     """
+    def try_typecasting(value):
+        """Attempt to typecast the value"""
+        if typecast is not None:
+            # Try to typecast the value
+            try:
+                return typecast(value)
+            except Exception as error:
+                logger.error(f"Failed to typecast '{env_var}' with value '{value}' to type '{typecast}' with error {error}")
+        return value
 
     # First, try to load from the environment variables
     if env_var is not None:
         val = os.getenv(env_var, None)
 
         if val is not None:
-            return val
+            return try_typecasting(val)
 
     # Next, try to load from configuration file
     if config_key is not None:
@@ -96,10 +105,10 @@ def get_setting(env_var=None, config_key=None, default_value=None):
             cfg_data = cfg_data[key]
 
         if result is not None:
-            return result
+            return try_typecasting(result)
 
     # Finally, return the default value
-    return default_value
+    return try_typecasting(default_value)
 
 
 def get_boolean_setting(env_var=None, config_key=None, default_value=False):
diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -346,6 +346,12 @@
     env_var = os.environ.get(env_key, None)
 
     if env_var:
+        # Make use PORT is int
+        if key == 'PORT':
+            try:
+                env_var = int(env_var)
+            except ValueError:
+                logger.error(f"Invalid number for {env_key}: {env_var}")
         # Override configuration value
         db_config[key] = env_var
 
@@ -503,7 +509,7 @@
 
 # Cache configuration
 cache_host = get_setting('INVENTREE_CACHE_HOST', 'cache.host', None)
-cache_port = get_setting('INVENTREE_CACHE_PORT', 'cache.port', '6379')
+cache_port = get_setting('INVENTREE_CACHE_PORT', 'cache.port', '6379', typecast=int)
 
 if cache_host:  # pragma: no cover
     # We are going to rely upon a possibly non-localhost for our cache,
@@ -670,7 +676,7 @@
 # Email configuration options
 EMAIL_BACKEND = get_setting('INVENTREE_EMAIL_BACKEND', 'email.backend', 'django.core.mail.backends.smtp.EmailBackend')
 EMAIL_HOST = get_setting('INVENTREE_EMAIL_HOST', 'email.host', '')
-EMAIL_PORT = int(get_setting('INVENTREE_EMAIL_PORT', 'email.port', 25))
+EMAIL_PORT = get_setting('INVENTREE_EMAIL_PORT', 'email.port', 25, typecast=int)
 EMAIL_HOST_USER = get_setting('INVENTREE_EMAIL_USERNAME', 'email.username', '')
 EMAIL_HOST_PASSWORD = get_setting('INVENTREE_EMAIL_PASSWORD', 'email.password', '')
 EMAIL_SUBJECT_PREFIX = get_setting('INVENTREE_EMAIL_PREFIX', 'email.prefix', '[InvenTree] ')
@@ -719,8 +725,8 @@
 SOCIALACCOUNT_STORE_TOKENS = True
 
 # settings for allauth
-ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = get_setting('INVENTREE_LOGIN_CONFIRM_DAYS', 'login_confirm_days', 3)
-ACCOUNT_LOGIN_ATTEMPTS_LIMIT = get_setting('INVENTREE_LOGIN_ATTEMPTS', 'login_attempts', 5)
+ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = get_setting('INVENTREE_LOGIN_CONFIRM_DAYS', 'login_confirm_days', 3, typecast=int)
+ACCOUNT_LOGIN_ATTEMPTS_LIMIT = get_setting('INVENTREE_LOGIN_ATTEMPTS', 'login_attempts', 5, typecast=int)
 ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
 ACCOUNT_PREVENT_ENUMERATION = True
 


Test patch: