Repository: XLSForm/pyxform
Pull request #456 (2020-07-11 05:30:56)

Fix 454 calculate with dynamic default
Closes #
#454 
#### Why is this the best possible solution? Were any other approaches considered?
I think this is the simplest solution.
#### What are the regression risks?
I don't think there is any.
#### Does this change require updates to documentation? If so, please file an issue [here](https://github.com/XLSForm/xlsform.github.io) and include the link below.
No
#### Before submitting this PR, please make sure you have:
- [x] included test cases for core behavior and edge cases in `tests_v1`
- [x] run `nosetests` and verified all tests pass
- [x] run `black pyxform` to format code
- [x] verified that any code or assets from external sources are properly credited in comments


Patch:
diff --git a/pyxform/xls2json.py b/pyxform/xls2json.py
index a7b273d..a386cb3 100644
--- a/pyxform/xls2json.py
+++ b/pyxform/xls2json.py
@@ -819,7 +819,10 @@ def workbook_to_json(
 
         if question_type == "calculate":
             calculation = row.get("bind", {}).get("calculate")
-            if not calculation:
+            question_default = row.get("default")
+            if not calculation and not (
+                question_default and default_is_dynamic(question_default, question_type)
+            ):
                 raise PyXFormError(
                     row_format_string % row_number + " Missing calculation."
                 )


Test patch:
diff --git a/pyxform/tests_v1/test_typed_calculates.py b/pyxform/tests_v1/test_typed_calculates.py
index a58ecd6..e596f27 100644
--- a/pyxform/tests_v1/test_typed_calculates.py
+++ b/pyxform/tests_v1/test_typed_calculates.py
@@ -90,3 +90,39 @@ class TypedCalculatesTest(PyxformTestCase):
             errored=True,
             error__contains="The survey element named 'a' has no label or hint.",
         )
+
+    def test_calculate_without_calculation_without_default(self):
+        self.assertPyxformXform(
+            name="calculate-without-calculation-without-default",
+            md="""
+        | survey |            |      |             |             |         |
+        |        | type       | name | label       | calculation | default |
+        |        | calculate  | a    |             |             |         |
+        """,
+            errored=True,
+            error__contains="Missing calculation",
+        )
+
+    def test_calculate_without_calculation_with_default_without_dynamic_default(self):
+        self.assertPyxformXform(
+            name="calculate-without-calculation-with-default-without-dynamic-default",
+            md="""
+        | survey |            |      |             |             |         |
+        |        | type       | name | label       | calculation | default |
+        |        | calculate  | a    |             |             | foo     |
+        """,
+            errored=True,
+            error__contains="Missing calculation",
+        )
+
+    def test_calculate_without_calculation_with_dynamic_default(self):
+        self.assertPyxformXform(
+            name="calculate-without-calculation-with-dynamic-default",
+            md="""
+        | survey |            |      |             |             |          |
+        |        | type       | name | label       | calculation | default  |
+        |        | calculate  | a    |             |             | random() |
+        """,
+            errored=False,
+            instance__contains=["<a/>"],
+        )