def test_config_interpolation_lists(): # Test that lists are preserved correctly c_str = """[a]\nb = 1\n\n[c]\nd = ["hello ${a.b}", "world"]""" config = Config().from_str(c_str, interpolate=False) assert config["c"]["d"] == ["hello ${a.b}", "world"] config = config.interpolate() assert config["c"]["d"] == ["hello 1", "world"] c_str = """[a]\nb = 1\n\n[c]\nd = [${a.b}, "hello ${a.b}", "world"]""" config = Config().from_str(c_str) assert config["c"]["d"] == [1, "hello 1", "world"] config = Config().from_str(c_str, interpolate=False) # NOTE: This currently doesn't work, because we can't know how to JSON-load # the uninterpolated list [${a.b}]. # assert config["c"]["d"] == ["${a.b}", "hello ${a.b}", "world"] # config = config.interpolate() # assert config["c"]["d"] == [1, "hello 1", "world"] c_str = """[a]\nb = 1\n\n[c]\nd = ["hello", ${a}]""" config = Config().from_str(c_str) assert config["c"]["d"] == ["hello", {"b": 1}] c_str = """[a]\nb = 1\n\n[c]\nd = ["hello", "hello ${a}"]""" with pytest.raises(ConfigValidationError): Config().from_str(c_str) config_str = """[a]\nb = 1\n\n[c]\nd = ["hello", {"x": ["hello ${a.b}"], "y": 2}]""" config = Config().from_str(config_str) assert config["c"]["d"] == ["hello", {"x": ["hello 1"], "y": 2}] config_str = """[a]\nb = 1\n\n[c]\nd = ["hello", {"x": [${a.b}], "y": 2}]""" with pytest.raises(ConfigValidationError): Config().from_str(c_str)
def test_config_no_interpolation(d): """Test that interpolation is correctly preserved. The parametrized value is the final divider (${a.b} vs. ${a:b}). Both should now work and be valid. The double {{ }} in the config strings are required to prevent the references from being interpreted as an actual f-string variable. """ c_str = f"""[a]\nb = 1\n\n[c]\nd = ${{a{d}b}}\ne = \"hello${{a{d}b}}"\nf = ${{a}}""" config = Config().from_str(c_str, interpolate=False) assert not config.is_interpolated assert config["c"]["d"] == f"${{a{d}b}}" assert config["c"]["e"] == f'"hello${{a{d}b}}"' assert config["c"]["f"] == "${a}" config2 = Config().from_str(config.to_str(), interpolate=True) assert config2.is_interpolated assert config2["c"]["d"] == 1 assert config2["c"]["e"] == "hello1" assert config2["c"]["f"] == {"b": 1} config3 = config.interpolate() assert config3.is_interpolated assert config3["c"]["d"] == 1 assert config3["c"]["e"] == "hello1" assert config3["c"]["f"] == {"b": 1} # Bad non-serializable value cfg = {"x": {"y": numpy.asarray([[1, 2], [4, 5]], dtype="f"), "z": f"${{x{d}y}}"}} with pytest.raises(ConfigValidationError): Config(cfg).interpolate()
def test_config_is_interpolated(): """Test that a config object correctly reports whether it's interpolated.""" config_str = """[a]\nb = 1\n\n[c]\nd = ${a:b}\ne = \"hello${a:b}"\nf = ${a}""" config = Config().from_str(config_str, interpolate=False) assert not config.is_interpolated config = config.merge(Config({"x": {"y": "z"}})) assert not config.is_interpolated config = Config(config) assert not config.is_interpolated config = config.interpolate() assert config.is_interpolated config = config.merge(Config().from_str(config_str, interpolate=False)) assert not config.is_interpolated
def test_config_fill_extra_fields(): """Test that filling a config from a schema removes extra fields.""" class TestSchemaContent(BaseModel): a: str b: int class Config: extra = "forbid" class TestSchema(BaseModel): cfg: TestSchemaContent config = Config({"cfg": {"a": "1", "b": 2, "c": True}}) with pytest.raises(ConfigValidationError): my_registry.fill_config(config, schema=TestSchema) filled = my_registry.fill_config(config, schema=TestSchema, validate=False)["cfg"] assert filled == {"a": "1", "b": 2} config2 = config.interpolate() filled = my_registry.fill_config(config2, schema=TestSchema, validate=False)["cfg"] assert filled == {"a": "1", "b": 2} config3 = Config({"cfg": {"a": "1", "b": 2, "c": True}}, is_interpolated=False) filled = my_registry.fill_config(config3, schema=TestSchema, validate=False)["cfg"] assert filled == {"a": "1", "b": 2} class TestSchemaContent2(BaseModel): a: str b: int class Config: extra = "allow" class TestSchema2(BaseModel): cfg: TestSchemaContent2 filled = my_registry.fill_config(config, schema=TestSchema2, validate=False)["cfg"] assert filled == {"a": "1", "b": 2, "c": True}