From 7d5429303ed78ab56ba2e83bdbd33b420caf5b06 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 23 Nov 2025 23:11:12 +1100 Subject: [PATCH 1/3] Error messages (#10894) * Add INVE-E14 - Error in config file * Add INVE-E14 * Fix duplicate code * Fix numbering --- docs/docs/settings/error_codes.md | 14 +++++++++++++- src/backend/InvenTree/InvenTree/config.py | 4 +++- src/backend/InvenTree/manage.py | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) 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/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 From fcea1383d0c768548061b7c18dd95b0916c92c31 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Sun, 23 Nov 2025 22:12:21 +0000 Subject: [PATCH 2/3] Installer missing some required packages from REQS (#10897) Fixes #10813 --- contrib/install.sh | 2 +- contrib/installer/src/root_command.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 From 276041ae540dfd75193875a46666ae57c3faf046 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 24 Nov 2025 14:52:13 +1100 Subject: [PATCH 3/3] [bug] Migration test fix (#10899) * Pop instead of get * Better error handling for unit registry * Prevent caching during database migrations * Remove debug msg * Revert changes --- src/backend/InvenTree/InvenTree/conversion.py | 66 ++++++++++++------- src/backend/InvenTree/common/models.py | 2 +- 2 files changed, 43 insertions(+), 25 deletions(-) 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 a5671cfa77..7c7266c2ef 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -704,7 +704,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,