diff --git a/contrib/install.sh b/contrib/install.sh index 58e1a26c6a..6c56feccc3 100755 --- a/contrib/install.sh +++ b/contrib/install.sh @@ -15,7 +15,7 @@ root_command() { no_call=${args[--no-call]} dry_run=${args[--dry-run]} - REQS="wget apt-transport-https" + REQS="wget apt-transport-https curl gpg" function do_call() { if [[ $dry_run ]]; then diff --git a/contrib/installer/src/root_command.sh b/contrib/installer/src/root_command.sh index cfcc5dd31e..5519d14c1d 100644 --- a/contrib/installer/src/root_command.sh +++ b/contrib/installer/src/root_command.sh @@ -5,7 +5,7 @@ publisher=${args[publisher]} no_call=${args[--no-call]} dry_run=${args[--dry-run]} -REQS="wget apt-transport-https" +REQS="wget apt-transport-https curl gpg" function do_call() { if [[ $dry_run ]]; then diff --git a/docs/docs/settings/error_codes.md b/docs/docs/settings/error_codes.md index 057fedabd2..75dc200d80 100644 --- a/docs/docs/settings/error_codes.md +++ b/docs/docs/settings/error_codes.md @@ -83,6 +83,18 @@ This is a security measure to prevent plugins from changing the core functionali An error occurred when discovering or initializing a machine type from a plugin. This likely indicates a faulty or incompatible plugin. +#### INVE-E13 + +**Error reading InvenTree configuration file** + +An error occurred while reading the InvenTree configuration file. This might be caused by a syntax error or invalid value in the configuration file. + +#### INVE-E14 + +**Could not import Django** + +Django is not installed in the current Python environment. This means that the InvenTree backend is not running within the correct [python virtual environment](../start/index.md#virtual-environment) or that the required Python packages were not installed correctly. + ### INVE-W (InvenTree Warning) Warnings - These are non-critical errors which should be addressed when possible. @@ -153,7 +165,7 @@ The warning text will show the recommended command for intended use. #### INVE-W10 **Config not in recommended directory - Backend** -A configuration file is not in the recommended directory. This might lead to issues with the deployment method you are using. It might also lead to confusinon. +A configuration file is not in the recommended directory. This might lead to issues with the deployment method you are using. It might also lead to confusion. The warning text will show the recommended directory for your deployment method. diff --git a/src/backend/InvenTree/InvenTree/config.py b/src/backend/InvenTree/InvenTree/config.py index 0f0770ab1f..7392543441 100644 --- a/src/backend/InvenTree/InvenTree/config.py +++ b/src/backend/InvenTree/InvenTree/config.py @@ -200,7 +200,9 @@ def load_config_data(set_cache: bool = False) -> map | None: data = yaml.safe_load(cfg) except yaml.parser.ParserError as error: logger.error( - "Error reading InvenTree configuration file '%s': %s", cfg_file, error + "INVE-E13: Error reading InvenTree configuration file '%s': %s", + cfg_file, + error, ) sys.exit(1) diff --git a/src/backend/InvenTree/InvenTree/conversion.py b/src/backend/InvenTree/InvenTree/conversion.py index 42274ca552..aedf416883 100644 --- a/src/backend/InvenTree/InvenTree/conversion.py +++ b/src/backend/InvenTree/InvenTree/conversion.py @@ -24,6 +24,22 @@ logger = structlog.get_logger('inventree') logging.getLogger('pint').setLevel(logging.ERROR) +def can_cache_registry() -> bool: + """Return True if it is appropriate to cache the unit registry. + + Prevent caching under certain conditions (such as database migration) + to prevent database access. + """ + import InvenTree.ready + + return not any([ + InvenTree.ready.isImportingData(), + InvenTree.ready.isRunningBackup(), + InvenTree.ready.isRunningMigrations(), + InvenTree.ready.isInTestMode(), + ]) + + def get_unit_registry_hash(): """Return a hash representing the current state of the unit registry. @@ -53,6 +69,9 @@ def set_unit_registry_hash(registry_hash: str): global _unit_registry_hash _unit_registry_hash = registry_hash + if not can_cache_registry(): + return + # Save to both the global settings and the session cache set_global_setting('_UNIT_REGISTRY_HASH', registry_hash) set_session_cache(_UNIT_REG_CACHE_KEY, registry_hash) @@ -68,7 +87,7 @@ def get_unit_registry(): return reload_unit_registry() # Check if the unit registry has changed - if _unit_registry_hash != get_unit_registry_hash(): + if can_cache_registry() and _unit_registry_hash != get_unit_registry_hash(): logger.info('Unit registry hash has changed, reloading unit registry') return reload_unit_registry() @@ -103,33 +122,32 @@ def reload_unit_registry(): reg.define('thousand = 1000') # Allow for custom units to be defined in the database + # Calculate a hash of all custom units + hash_md5 = md5() + try: from common.models import CustomUnit - # Calculate a hash of all custom units - hash_md5 = md5() - - for cu in CustomUnit.objects.all(): - try: - fmt = cu.fmt_string() - reg.define(fmt) - - hash_md5.update(fmt.encode('utf-8')) - - except Exception as e: - logger.exception( - 'Failed to load custom unit: %s - %s', cu.fmt_string(), e - ) - - # Once custom units are loaded, save registry - _unit_registry = reg - - # Update the unit registry hash - set_unit_registry_hash(hash_md5.hexdigest()) - + custom_units = list(CustomUnit.objects.all()) except Exception: - # Database is not ready, or CustomUnit model is not available - pass + # Database is likely not ready + custom_units = [] + + for cu in custom_units: + try: + fmt = cu.fmt_string() + reg.define(fmt) + + hash_md5.update(fmt.encode('utf-8')) + + except Exception as e: + logger.exception('Failed to load custom unit: %s - %s', cu.fmt_string(), e) + + # Once custom units are loaded, save registry + _unit_registry = reg + + # Update the unit registry hash + set_unit_registry_hash(hash_md5.hexdigest()) dt = time.time() - t_start logger.debug('Loaded unit registry in %.3f s', dt) diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py index 638dadceb5..7d2454ea67 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -707,7 +707,7 @@ class BaseInvenTreeSetting(models.Model): ): # pragma: no cover return - attempts = int(kwargs.get('attempts', 3)) + attempts = int(kwargs.pop('attempts', 3)) filters = { 'key__iexact': key, diff --git a/src/backend/InvenTree/manage.py b/src/backend/InvenTree/manage.py index bc489b085a..988cd61e3f 100755 --- a/src/backend/InvenTree/manage.py +++ b/src/backend/InvenTree/manage.py @@ -13,7 +13,7 @@ def main(): from django.core.management import execute_from_command_line except ImportError as exc: # pragma: no cover raise ImportError( - "Couldn't import Django. Are you sure it's installed and " + "INVE-E14: Could not import Django. Are you sure it's installed and " 'available on your PYTHONPATH environment variable? Did you ' 'forget to activate a virtual environment?' ) from exc