diff --git a/arches/app/utils/compatibility.py b/arches/app/utils/compatibility.py
deleted file mode 100644
index b4a462c3456..00000000000
--- a/arches/app/utils/compatibility.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import arches
-import logging
-import semantic_version
-from arches.app.models.system_settings import settings
-from django.utils.translation import gettext as _
-
-logger = logging.getLogger(__name__)
-
-
-def is_compatible_with_arches(
- min_arches=settings.MIN_ARCHES_VERSION,
- max_arches=settings.MAX_ARCHES_VERSION,
- target="project",
-):
- """
- Check if the current version of arches falls between a min and max version.
-
- Keyword arguments
- min_arches -- A semvar string representing the minimum supported arches version
- max_arches -- A semver string representing the maximum supported arches version
- target -- A description of what is being checked for compatibility
-
- """
-
- try:
- arches_version = semantic_version.Version(arches.__version__)
- except ValueError:
- arches_version = semantic_version.Version.coerce(arches.__version__)
-
- min_is_valid = True
- max_is_valid = True
-
- versions = {"minimum": min_arches, "maximum": max_arches}
-
- for key, value in versions.items():
- if value:
- try:
- sem_version = semantic_version.Version(value)
- except ValueError:
- sem_version = semantic_version.Version.coerce(value)
- except Exception as e:
- logger.error(e)
- return False
- if key == "minimum":
- min_is_valid = sem_version <= arches_version
- if key == "maximum":
- max_is_valid = sem_version >= arches_version
- else:
- logger.warning(
- _(
- "A {0} Arches version is not specified. Unable to check {0} version {1} compatibility".format(
- key, target
- )
- )
- )
- return min_is_valid and max_is_valid
-
-
-class CompatibilityError(Exception):
- def __init__(self, message, code=None):
- self.message = message
- self.code = code
-
- def __str__(self):
- return repr(self.message)
diff --git a/arches/app/views/base.py b/arches/app/views/base.py
index 9c30289fd6e..ecb9d9f9ddb 100644
--- a/arches/app/views/base.py
+++ b/arches/app/views/base.py
@@ -16,12 +16,10 @@
along with this program. If not, see .
"""
-from arches import __version__
from arches.app.models import models
from arches.app.models.system_settings import settings
from arches.app.models.resource import Resource
from arches.app.utils.betterJSONSerializer import JSONSerializer, JSONDeserializer
-from arches.app.utils.compatibility import is_compatible_with_arches, CompatibilityError
from django.utils.translation import gettext as _
from django.views.generic import TemplateView
from arches.app.datatypes.datatypes import DataTypeFactory
@@ -35,10 +33,6 @@
class BaseManagerView(TemplateView):
- if is_compatible_with_arches() is False:
- message = _("This project is incompatible with Arches {0}.").format(__version__)
- raise CompatibilityError(message)
-
template_name = ""
def get_context_data(self, **kwargs):
diff --git a/arches/apps.py b/arches/apps.py
index 3c00e54dfcd..97edac4c174 100644
--- a/arches/apps.py
+++ b/arches/apps.py
@@ -1,7 +1,14 @@
+import tomllib
import warnings
+from importlib.metadata import PackageNotFoundError, requires
+from pathlib import Path
+from django.apps import apps
from django.conf import settings
from django.core.checks import register, Tags, Error, Warning
+from semantic_version import SimpleSpec, Version
+
+from arches import __version__
### GLOBAL DEPRECATIONS ###
FILE_TYPE_CHECKING_MSG = (
@@ -51,3 +58,62 @@ def check_cache_backend(app_configs, **kwargs):
)
)
return errors
+
+
+@register(Tags.compatibility)
+def check_arches_compatibility(app_configs, **kwargs):
+ try:
+ arches_version = Version(__version__)
+ except ValueError:
+ arches_version = Version.coerce(__version__)
+
+ if app_configs is None:
+ app_configs = apps.get_app_configs()
+
+ errors = []
+ for config in app_configs:
+ if not getattr(config, "is_arches_application", False):
+ continue
+ try:
+ project_requirements = requires(config.name)
+ except PackageNotFoundError:
+ # Not installed by pip: read pyproject.toml directly
+ toml_path = Path(config.path).parent / "pyproject.toml"
+ if not toml_path.exists():
+ raise ValueError
+ with open(toml_path, "rb") as f:
+ data = tomllib.load(f)
+ try:
+ project_requirements = data["project"]["dependencies"]
+ except KeyError:
+ raise ValueError from None
+ try:
+ for requirement in project_requirements:
+ if requirement.lower().startswith("arches"):
+ parsed_arches_requirement = SimpleSpec(
+ requirement.lower().replace("arches", "").lstrip()
+ )
+ break
+ else:
+ raise ValueError
+ except ValueError:
+ errors.append(
+ Error(
+ f"Invalid or missing arches requirement",
+ obj=config.name,
+ hint=project_requirements,
+ id="arches.E002",
+ )
+ )
+ continue
+ if arches_version not in parsed_arches_requirement:
+ errors.append(
+ Error(
+ f"Incompatible arches requirement for Arches version: {arches_version}",
+ obj=config.name,
+ hint=requirement,
+ id="arches.E003",
+ )
+ )
+
+ return errors
diff --git a/arches/install/arches-templates/project_name/settings.py-tpl b/arches/install/arches-templates/project_name/settings.py-tpl
index 3a6009aa5aa..fc9bd25be6d 100644
--- a/arches/install/arches-templates/project_name/settings.py-tpl
+++ b/arches/install/arches-templates/project_name/settings.py-tpl
@@ -2,10 +2,7 @@
Django settings for {{ project_name }} project.
"""
-import json
import os
-import sys
-import arches
import inspect
import semantic_version
from datetime import datetime, timedelta
@@ -19,9 +16,6 @@ except ImportError:
APP_NAME = '{{ project_name }}'
APP_VERSION = semantic_version.Version(major=0, minor=0, patch=0)
APP_ROOT = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
-MIN_ARCHES_VERSION = arches.__version__
-MAX_ARCHES_VERSION = arches.__version__
-
WEBPACK_LOADER = {
"DEFAULT": {
diff --git a/arches/install/arches-templates/tests/test_settings.py-tpl b/arches/install/arches-templates/tests/test_settings.py-tpl
index e9b2f320e3f..efc7ea97ae2 100644
--- a/arches/install/arches-templates/tests/test_settings.py-tpl
+++ b/arches/install/arches-templates/tests/test_settings.py-tpl
@@ -16,10 +16,10 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
"""
-from arches.settings import *
-import arches
import os
+from arches.settings import *
+
try:
from django.utils.translation import gettext_lazy as _
except ImportError: # unable to import prior to installing requirements
@@ -35,9 +35,6 @@ ROOT_URLCONF = '{{ project_name }}.urls'
ARCHES_APPLICATIONS = ()
-MIN_ARCHES_VERSION = arches.__version__
-MAX_ARCHES_VERSION = arches.__version__
-
# LOAD_V3_DATA_DURING_TESTS = True will engage the most extensive the of the v3
# data migration tests, which could add over a minute to the test process. It's
# recommended that this setting only be set to True in tests/settings_local.py
diff --git a/arches/settings.py b/arches/settings.py
index c6de9b89f2a..be959b32324 100644
--- a/arches/settings.py
+++ b/arches/settings.py
@@ -636,8 +636,6 @@
APP_NAME = "Arches"
APP_VERSION = None
-MIN_ARCHES_VERSION = None
-MAX_ARCHES_VERSION = None
APP_TITLE = "Arches | Heritage Data Management"
COPYRIGHT_TEXT = "All Rights Reserved."
diff --git a/releases/7.6.0.md b/releases/7.6.0.md
index b67465229aa..ece0adf7870 100644
--- a/releases/7.6.0.md
+++ b/releases/7.6.0.md
@@ -43,6 +43,7 @@ Arches 7.6.0 Release Notes
- 10911 Styling fix in resource model manage menu
- 11118 Harden SystemSettings model against too-early access #11118
- 10726 Upgrade openpyxl package to 3.1.2 and fixes ETL modules
+- 11114 Implement arches version compatibility check as a Django system check
- 9191 Adds unlocalized string datatype
- 10597 Fix internationalized string/json field entry problems in the Django admin
- 10787 Search Export: data exportable as "system values" (e.g. concept valueids) instead of "display values" (e.g. string preflabel)
@@ -169,7 +170,7 @@ Minor incompatibilities:
is now a more attractive target for overriding than `run_load_task()`.
- `unzip_file()` moved from `arches.setup` to `arches.app.utils.zip`
- Version-related utils moved from `arches.setup` to `arches.version`
-
+- `arches.app.utils.compatibility` was removed in favor of a Django system check.
### Deprecations
diff --git a/tests/test_settings.py b/tests/test_settings.py
index 599a6b3b45e..03214b251c7 100644
--- a/tests/test_settings.py
+++ b/tests/test_settings.py
@@ -16,10 +16,10 @@
along with this program. If not, see .
"""
-from arches.settings import *
-import arches
import os
+from arches.settings import *
+
try:
from django.utils.translation import gettext_lazy as _
except ImportError: # unable to import prior to installing requirements
@@ -31,9 +31,6 @@
ARCHES_APPLICATIONS = ()
-MIN_ARCHES_VERSION = arches.__version__
-MAX_ARCHES_VERSION = arches.__version__
-
# LOAD_V3_DATA_DURING_TESTS = True will engage the most extensive the of the v3
# data migration tests, which could add over a minute to the test process. It's
# recommended that this setting only be set to True in tests/settings_local.py