Repository: shuup/shuup

Issue:
System check to verify Parler sanity
Shuup should check that the Parler configuration is sane before starting.

@JsseL and @juhakujala puzzled over an unrelated exception (`'shuup.admin.modules.services.behavior_form_part.BehaviorFormSet object' has no attribute 'empty_form'`) for a while – turns out it was an `AttributeError` ([which, as we unfortunately know, are hidden within `@property`s](https://github.com/shuup/shuup/blob/5584ebf912bae415fe367ea0c00ad4c5cff49244/shuup/utils/form_group.py#L86-L100)) within `FormSet.empty_form` calls that happens due to `PARLER_DEFAULT_LANGUAGE_CODE` being undefined:

```
Traceback (most recent call last):
  File "~/django/forms/formsets.py", line 187, in empty_form
    empty_permitted=True,
  File "~/shuup/admin/modules/services/behavior_form_part.py", line 49, in form
    kwargs.setdefault("default_language", settings.PARLER_DEFAULT_LANGUAGE_CODE)
  File "~/django/conf/__init__.py", line 49, in __getattr__
    return getattr(self._wrapped, name)
AttributeError: 'Settings' object has no attribute 'PARLER_DEFAULT_LANGUAGE_CODE'
```

My suggestion is to add a simple system check in [ShuupCoreAppConfig.ready()](https://github.com/shuup/shuup/blob/5584ebf912bae415fe367ea0c00ad4c5cff49244/shuup/core/__init__.py#L11) that throws an exception if some of the Parler settings (`PARLER_DEFAULT_LANGUAGE_CODE` and `PARLER_LANGUAGES`) are unset -- or perhaps it could automatically derive them based on the Django `LANGUAGES` setting, as "sane defaults" go?



Discussion:

Resolving patch:
diff --git a/shuup/core/__init__.py b/shuup/core/__init__.py
--- a/shuup/core/__init__.py
+++ b/shuup/core/__init__.py
@@ -6,6 +6,7 @@
 # This source code is licensed under the AGPLv3 license found in the
 # LICENSE file in the root directory of this source tree.
 from shuup.apps import AppConfig
+from shuup.core.excs import MissingSettingException
 
 
 class ShuupCoreAppConfig(AppConfig):
@@ -27,5 +28,12 @@ class ShuupCoreAppConfig(AppConfig):
         ],
     }
 
+    def ready(self):
+        from django.conf import settings
+        if not getattr(settings, "PARLER_DEFAULT_LANGUAGE_CODE", None):
+            raise MissingSettingException("PARLER_DEFAULT_LANGUAGE_CODE must be set.")
+        if not getattr(settings, "PARLER_LANGUAGES", None):
+            raise MissingSettingException("PARLER_LANGUAGES must be set.")
+
 
 default_app_config = "shuup.core.ShuupCoreAppConfig"
diff --git a/shuup/core/excs.py b/shuup/core/excs.py
--- a/shuup/core/excs.py
+++ b/shuup/core/excs.py
@@ -32,6 +32,10 @@ class InvalidRefundAmountException(Exception):
     pass
 
 
+class MissingSettingException(Exception):
+    pass
+
+
 class ProductNotOrderableProblem(Problem):
     pass
 


Test patch:
diff --git a/shuup_tests/core/test_settings.py b/shuup_tests/core/test_settings.py
new file mode 100644
--- /dev/null
+++ b/shuup_tests/core/test_settings.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# This file is part of Shuup.
+#
+# Copyright (c) 2012-2016, Shoop Ltd. All rights reserved.
+#
+# This source code is licensed under the AGPLv3 license found in the
+# LICENSE file in the root directory of this source tree.
+import pytest
+from django.apps import apps
+from django.test import override_settings
+
+from shuup.core import MissingSettingException
+
+
+@pytest.mark.parametrize("setting_key, value, should_raise", [
+    ("PARLER_DEFAULT_LANGUAGE_CODE", None, True),
+    ("PARLER_DEFAULT_LANGUAGE_CODE", False, True),
+    ("PARLER_DEFAULT_LANGUAGE_CODE", "", True),
+    ("PARLER_DEFAULT_LANGUAGE_CODE", "en", False),
+    ("PARLER_LANGUAGES", None, True),
+    ("PARLER_LANGUAGES", False, True),
+    ("PARLER_LANGUAGES", "", True),
+    ("PARLER_LANGUAGES", {}, True),
+    ("PARLER_LANGUAGES", {None: [1,2]}, False),
+    ("PARLER_LANGUAGES", {"en": [1,2]}, False),
+])
+@pytest.mark.django_db
+def test_parler_language_code(setting_key, value, should_raise):
+    kwargs = {setting_key: value}
+    with override_settings(**kwargs):
+        if should_raise:
+            with pytest.raises(MissingSettingException):
+                apps.get_app_config('shuup').ready()