Coverage for src/backend/InvenTree/common/settings.py: 52%

76 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-07 17:47 +0000

1"""User-configurable settings for the common app.""" 

2 

3import json 

4from os import environ 

5from typing import Optional 

6 

7from django.core.exceptions import AppRegistryNotReady 

8 

9import structlog 

10 

11import InvenTree.ready 

12 

13logger = structlog.get_logger('inventree') 

14 

15 

16def plugin_setting_overrides(slug: str) -> dict: 

17 """Return a dictionary of plugin setting overrides for the given plugin slug. 

18 

19 These values are set via environment variables or configuration file. 

20 """ 

21 from django.conf import settings 

22 

23 if hasattr(settings, 'PLUGIN_SETTING_OVERRIDES'): 23 ↛ 26line 23 didn't jump to line 26 because the condition on line 23 was always true

24 return settings.PLUGIN_SETTING_OVERRIDES.get(slug, {}) or {} 

25 

26 return {} 

27 

28 

29def global_setting_overrides() -> dict: 

30 """Return a dictionary of global settings overrides. 

31 

32 These values are set via environment variables or configuration file. 

33 """ 

34 from django.conf import settings 

35 

36 if hasattr(settings, 'GLOBAL_SETTINGS_OVERRIDES'): 36 ↛ 39line 36 didn't jump to line 39 because the condition on line 36 was always true

37 return settings.GLOBAL_SETTINGS_OVERRIDES or {} 

38 

39 return {} 

40 

41 

42def get_global_setting(key, backup_value=None, environment_key=None, **kwargs): 

43 """Return the value of a global setting using the provided key.""" 

44 import InvenTree.ready 

45 from common.models import InvenTreeSetting 

46 

47 if environment_key: 

48 value = environ.get(environment_key) 

49 if value: 49 ↛ 50line 49 didn't jump to line 50 because the condition on line 49 was never true

50 return value 

51 

52 if backup_value is not None: 

53 kwargs['backup_value'] = backup_value 

54 

55 # Prevent database writes if we are in a read-only command 

56 if InvenTree.ready.isReadOnlyCommand(): 56 ↛ 57line 56 didn't jump to line 57 because the condition on line 56 was never true

57 kwargs['create'] = False 

58 

59 return InvenTreeSetting.get_setting(key, **kwargs) 

60 

61 

62def set_global_setting(key, value, change_user=None, create=True, **kwargs): 

63 """Set the value of a global setting using the provided key.""" 

64 from common.models import InvenTreeSetting 

65 from InvenTree.ready import canAppAccessDatabase 

66 

67 if not canAppAccessDatabase(allow_shell=True, allow_test=True): 67 ↛ 68line 67 didn't jump to line 68 because the condition on line 67 was never true

68 logger.info(f'Cannot set global setting "{key}" - database is not accessible') 

69 return False 

70 

71 kwargs['change_user'] = change_user 

72 kwargs['create'] = create 

73 

74 if get_global_setting(key, create=False, cache=False) == value: 

75 logger.debug( 

76 f'Global setting "{key}" already has the desired value, no update needed' 

77 ) 

78 return True 

79 

80 return InvenTreeSetting.set_setting(key, value, **kwargs) 

81 

82 

83class GlobalWarningCode: 

84 """Warning codes that reflect to the status of the instance.""" 

85 

86 UNCOMMON_CONFIG = 'INVE-W10' 

87 TEST_KEY = '_TEST' 

88 

89 

90def set_global_warning(key: str, options: Optional[dict] = None) -> bool: 

91 """Set a global warning for a code. 

92 

93 Args: 

94 key (str): The key for the warning. 

95 options (dict or bool): Options for the warning, or True to set a default warning. 

96 

97 Returns: 

98 bool: True if the warning was checked / set successfully, False if no check was performed. 

99 

100 Raises: 

101 ValueError: If the key is not provided. 

102 """ 

103 if not key: 

104 raise ValueError('Key must be provided for global warning setting.') 

105 

106 # Ensure DB is ready 

107 if not InvenTree.ready.canAppAccessDatabase(allow_test=True): 

108 return False 

109 try: 

110 from common.models import InvenTreeSetting 

111 from common.setting.system import SystemSetId 

112 except AppRegistryNotReady: 

113 # App registry not ready, cannot set global warning 

114 return False 

115 

116 # Get and write (if necessary) the current global settings warning 

117 global_dict = get_global_setting(SystemSetId.GLOBAL_WARNING, '{}', create=False) 

118 try: 

119 global_dict = json.loads(global_dict) 

120 except json.JSONDecodeError: 

121 global_dict = {} 

122 if global_dict is None or not isinstance(global_dict, dict): 

123 global_dict = {} 

124 if key not in global_dict or global_dict[key] != options: 

125 global_dict[key] = options if options is not None else True 

126 try: 

127 global_dict_val = json.dumps(global_dict) 

128 except TypeError: 

129 # If the options cannot be serialized, we will set an empty the warning 

130 global_dict_val = 'true' 

131 logger.warning( 

132 f'Failed to serialize global warning options for key "{key}". Setting to True.' 

133 ) 

134 InvenTreeSetting.set_setting( 

135 SystemSetId.GLOBAL_WARNING, global_dict_val, change_user=None, create=True 

136 ) 

137 return True 

138 

139 

140def stock_expiry_enabled(): 

141 """Returns True if the stock expiry feature is enabled.""" 

142 from common.models import InvenTreeSetting 

143 

144 return InvenTreeSetting.get_setting('STOCK_ENABLE_EXPIRY', False, create=False) 

145 

146 

147def prevent_build_output_complete_on_incompleted_tests(): 

148 """Returns True if the completion of the build outputs is disabled until the required tests are passed.""" 

149 from common.models import InvenTreeSetting 

150 

151 return InvenTreeSetting.get_setting( 

152 'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS', False, create=False 

153 )