diff --git a/src/config.py b/src/config.py index 31dc7912..51929e72 100644 --- a/src/config.py +++ b/src/config.py @@ -382,7 +382,8 @@ def merge(metadata: dict[str, Any], base, settings, *path: str, return value elif settings_type == "float": - if settings is not Empty and not isinstance(settings, float): + # Treat literal ints as floats too for ease of writing settings + if settings is not Empty and not isinstance(settings, float) and type(settings) is not int: raise TypeError("Expected type float for path '{}', got {} instead".format(".".join(path), type(settings))) # float supports three merge types: replace (default), max, min if merge_type is None: @@ -398,6 +399,8 @@ def merge(metadata: dict[str, Any], base, settings, *path: str, else: value = metadata["_default"] + if type(value) is int: + value = float(value) assert isinstance(value, float) if merge_type == "replace": return value diff --git a/test/test_config_merge.py b/test/test_config_merge.py index f6e6c6ff..939a2e5f 100644 --- a/test/test_config_merge.py +++ b/test/test_config_merge.py @@ -368,7 +368,7 @@ def test_invalid_float(self): with self.subTest("value required"): self.assertRaises(TypeError, merge, metadata, Empty, Empty) with self.subTest("invalid type"): - self.assertRaises(TypeError, merge, metadata, Empty, 2) + # ints are also valid floats, so do not test for that here self.assertRaises(TypeError, merge, metadata, Empty, "2.0") self.assertRaises(TypeError, merge, metadata, Empty, []) self.assertRaises(TypeError, merge, metadata, Empty, {}) @@ -540,7 +540,26 @@ def test_default_multitype(self): metadata = {"_type": ["int", "float"], "_default": None} with self.subTest("first"): metadata["_default"] = 3 - self.assertEqual(merge(metadata, Empty, Empty), 3) + test = merge(metadata, Empty, Empty) + self.assertEqual(test, 3) + self.assertIsInstance(test, int) with self.subTest("second"): metadata["_default"] = 2.7 self.assertEqual(merge(metadata, Empty, Empty), 2.7) + + def test_coerce_int_to_float(self): + metadata = {"_type": "float", "_default": None} + with self.subTest("as default"): + metadata["_default"] = 1 + test = merge(metadata, Empty, Empty) + self.assertEqual(test, 1.0) + self.assertIsInstance(test, float) + with self.subTest("as base"): + metadata["_default"] = 1.0 + test = merge(metadata, 2, Empty) + self.assertEqual(test, 2.0) + self.assertIsInstance(test, float) + with self.subTest("as settings"): + test = merge(metadata, Empty, 3) + self.assertEqual(test, 3.0) + self.assertIsInstance(test, float)