Repository: PSLmodels/ParamTools

Issue:
Scalar values are set as zero dimension arrays
When `array_first` is `True`, scalar values are set to zero dimension NumPy arrays. For the most part, these values act like normal Python `int`s or `float`s, but they cause problems in edge cases. Further, this behavior may confusing for new users. I'll open a PR this week to fix this.

Discussion:

Patch:
diff --git a/paramtools/parameters.py b/paramtools/parameters.py
index a44fc7c..1d91538 100644
--- a/paramtools/parameters.py
+++ b/paramtools/parameters.py
@@ -369,10 +369,14 @@ class Parameters:
                 f"\nYou may be able to describe this parameter's values with additional "
                 f"labels\nand the 'label_to_extend' operator."
             )
-        elif not shape:
-            exp_full_shape = 1
-        else:
-            exp_full_shape = reduce(lambda x, y: x * y, shape)
+        elif not shape and number_dims == 0:
+            data_type = self._numpy_type(param)
+            value = value_items[0]["value"]
+            if data_type == object:
+                return value
+            else:
+                return data_type(value)
+        exp_full_shape = reduce(lambda x, y: x * y, shape)
         if len(value_items) != exp_full_shape:
             # maintains label value order over value objects.
             exp_grid = list(itertools.product(*value_order.values()))


Test patch:
diff --git a/paramtools/tests/test_parameters.py b/paramtools/tests/test_parameters.py
index 4d91777..d001829 100644
--- a/paramtools/tests/test_parameters.py
+++ b/paramtools/tests/test_parameters.py
@@ -833,7 +833,7 @@ class TestArrayFirst:
             [datetime.date(2018, 1, 15)]
         ]
         assert af_params.int_dense_array_param.tolist() == [[[4, 5, 6]]]
-        assert af_params.str_choice_param.tolist() == "value0"
+        assert af_params.str_choice_param == "value0"
 
     def test_from_array(self, af_params):
         exp = [
@@ -894,6 +894,31 @@ class TestArrayFirst:
         with pytest.raises(ParamToolsError):
             params.adjust({"arr": [{"label1": 1, "value": [4, 5, 6]}]})
 
+    def test_array_first_with_zero_dim(self):
+        class ZeroDim(Parameters):
+            defaults = {
+                "myint": {
+                    "title": "my int",
+                    "description": "",
+                    "type": "int",
+                    "value": 2,
+                },
+                "mystring": {
+                    "title": "my string",
+                    "description": "",
+                    "type": "str",
+                    "value": "hello world",
+                },
+            }
+            array_first = True
+
+        params = ZeroDim()
+        assert params.myint == 2.0
+        assert isinstance(params.myint, np.int64)
+
+        assert params.mystring == "hello world"
+        assert isinstance(params.mystring, str)
+
 
 class TestCollisions:
     def test_collision_list(self):