Fix parsing dict variables from env (#4438)

* fix parsing dict variables from env

The INVENTREE_SOCIAL_PROVIDERS variable has been parsed as a string from
the environment which resulted in an attribute error as dict was the
expected variable type. To circumvent this error, parsing JSON strings
as dictionary values from the environment has been added

* add unit tests for env typecasting to dict
This commit is contained in:
Philipp Fruck 2023-03-02 23:47:15 +00:00 committed by GitHub
parent f4bb7c29c7
commit 31f4045465
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 4 deletions

View File

@ -1,6 +1,7 @@
"""Helper functions for loading InvenTree configuration options."""
import datetime
import json
import logging
import os
import random
@ -32,6 +33,28 @@ def to_list(value, delimiter=','):
return [x.strip() for x in value.split(delimiter)]
def to_dict(value):
"""Take a configuration setting and make sure it is a dict.
For example, we might have a configuration setting taken from the .config file,
which is already an object/dict.
However, the same setting may be specified via an environment variable,
using a valid JSON string!
"""
if value is None:
return {}
if type(value) == dict:
return value
try:
return json.loads(value)
except Exception as error:
logger.error(f"Failed to parse value '{value}' as JSON with error {error}. Ensure value is a valid JSON string.")
return {}
def is_true(x):
"""Shortcut function to determine if a value "looks" like a boolean"""
return str(x).strip().lower() in ['1', 'y', 'yes', 't', 'true', 'on']
@ -125,6 +148,10 @@ def get_setting(env_var=None, config_key=None, default_value=None, typecast=None
if typecast is list:
value = to_list(value)
# Valid JSON string is required
elif typecast is dict:
value = to_dict(value)
elif typecast is not None:
# Try to typecast the value
try:

View File

@ -816,10 +816,7 @@ SOCIAL_BACKENDS = get_setting('INVENTREE_SOCIAL_BACKENDS', 'social_backends', []
for app in SOCIAL_BACKENDS:
INSTALLED_APPS.append(app) # pragma: no cover
SOCIALACCOUNT_PROVIDERS = get_setting('INVENTREE_SOCIAL_PROVIDERS', 'social_providers', None)
if SOCIALACCOUNT_PROVIDERS is None:
SOCIALACCOUNT_PROVIDERS = {}
SOCIALACCOUNT_PROVIDERS = get_setting('INVENTREE_SOCIAL_PROVIDERS', 'social_providers', None, typecast=dict)
SOCIALACCOUNT_STORE_TOKENS = True

View File

@ -830,6 +830,17 @@ class TestSettings(helpers.InvenTreeTestCase):
with self.in_env_context({TEST_ENV_NAME: '321'}):
self.assertEqual(config.get_setting(TEST_ENV_NAME, None), '321')
# test typecasting to dict - None should be mapped to empty dict
self.assertEqual(config.get_setting(TEST_ENV_NAME, None, None), {})
# test typecasting to dict - valid JSON string should be mapped to corresponding dict
with self.in_env_context({TEST_ENV_NAME: '{"a": 1}'}):
self.assertEqual(config.get_setting(TEST_ENV_NAME, None), {"a": 1})
# test typecasting to dict - invalid JSON string should be mapped to empty dict
with self.in_env_context({TEST_ENV_NAME: "{'a': 1}"}):
self.assertEqual(config.get_setting(TEST_ENV_NAME, None), {})
class TestInstanceName(helpers.InvenTreeTestCase):
"""Unit tests for instance name."""