diff --git a/README.md b/README.md index b66de00..7374b7e 100644 --- a/README.md +++ b/README.md @@ -83,3 +83,5 @@ You can customize name and location of the fixture, but you will need to include identifier: my_fixture_name # optional; default = interface_tester ``` +## Upgrading from v1 +As `pytest-interface-tester` v2 is using `pydantic` v2 that introduces breaking changes to their API, you might need to adjust your tested charm to also support v2. See [migration guide](https://docs.pydantic.dev/latest/migration/) for more information. \ No newline at end of file diff --git a/interface_tester/collector.py b/interface_tester/collector.py index ba8f893..8f62a99 100644 --- a/interface_tester/collector.py +++ b/interface_tester/collector.py @@ -105,11 +105,6 @@ def load_schema_module(schema_path: Path) -> types.ModuleType: if module_name in sys.modules: del sys.modules[module_name] - # Otherwise we'll get an error when we re-run @validator - # fixme: is there a better way to do this? - logger.debug("Clearing pydantic.class_validators._FUNCS") - pydantic.class_validators._FUNCS.clear() # noqa - try: module = importlib.import_module(module_name) except ImportError: diff --git a/interface_tester/interface_test.py b/interface_tester/interface_test.py index 27c0545..4def3de 100644 --- a/interface_tester/interface_test.py +++ b/interface_tester/interface_test.py @@ -283,14 +283,14 @@ def assert_schema_valid(self, schema: Optional["DataBagSchema"] = None): errors = [] for relation in self._relations: try: - databag_schema.validate( + databag_schema.model_validate( { "unit": relation.local_unit_data, "app": relation.local_app_data, } ) except ValidationError as e: - errors.append(e.args[0]) + errors.append(e.errors()[0]) if errors: raise SchemaValidationError(errors) diff --git a/pyproject.toml b/pyproject.toml index c52f0b3..f5ad5e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ build-backend = "setuptools.build_meta" [project] name = "pytest-interface-tester" -version = "1.0.7" +version = "2.0.0" authors = [ { name = "Pietro Pasotti", email = "pietro.pasotti@canonical.com" }, ] @@ -20,7 +20,7 @@ license.text = "Apache-2.0" keywords = ["juju", "relation interfaces"] dependencies = [ - "pydantic>= 1.10.7, <2", + "pydantic>=2", "typer==0.7.0", "ops-scenario>=5.2", "pytest" diff --git a/tests/unit/test_collect_schemas.py b/tests/unit/test_collect_schemas.py index 5190da4..9500021 100644 --- a/tests/unit/test_collect_schemas.py +++ b/tests/unit/test_collect_schemas.py @@ -15,7 +15,7 @@ def test_load_schema_module(tmp_path): pth.write_text( dedent( """ -FOO = 1 +FOO: int = 1 """ ) ) @@ -35,7 +35,7 @@ def test_collect_schemas(tmp_path): """from interface_tester.schema_base import DataBagSchema class RequirerSchema(DataBagSchema): - foo = 1""" + foo: int = 1""" ) ) @@ -54,7 +54,7 @@ def test_collect_schemas_multiple(tmp_path): """from interface_tester.schema_base import DataBagSchema class RequirerSchema(DataBagSchema): - foo = 1""" + foo: int = 1""" ) ) @@ -65,13 +65,13 @@ class RequirerSchema(DataBagSchema): """from interface_tester.schema_base import DataBagSchema class RequirerSchema(DataBagSchema): - foo = 2""" + foo: int = 2""" ) ) tests = collect_tests(root) - assert tests["mytestinterfacea"]["v0"]["requirer"]["schema"].__fields__["foo"].default == 1 - assert tests["mytestinterfaceb"]["v0"]["requirer"]["schema"].__fields__["foo"].default == 2 + assert tests["mytestinterfacea"]["v0"]["requirer"]["schema"].model_fields["foo"].default == 1 + assert tests["mytestinterfaceb"]["v0"]["requirer"]["schema"].model_fields["foo"].default == 2 def test_collect_invalid_schemas(tmp_path): @@ -84,7 +84,7 @@ def test_collect_invalid_schemas(tmp_path): dedent( """from interface_tester.schema_base import DataBagSchema class ProviderSchema(DataBagSchema): - foo = 2""" + foo: int = 2""" ) ) @@ -95,9 +95,17 @@ class ProviderSchema(DataBagSchema): @pytest.mark.parametrize( "schema_source, schema_name", ( - (dedent("""Foo2=1"""), "Foo2"), - (dedent("""Bar='baz'"""), "Bar"), - (dedent("""Baz=[1,2,3]"""), "Baz"), + (dedent("""Foo2: int=1"""), "Foo2"), + (dedent("""Bar: str='baz'"""), "Bar"), + ( + dedent( + """ + from typing import List + + Baz: List[int]=[1,2,3]""" + ), + "Baz", + ), ), ) def test_get_schema_from_module_wrong_type(tmp_path, schema_source, schema_name): @@ -114,7 +122,7 @@ def test_get_schema_from_module_wrong_type(tmp_path, schema_source, schema_name) @pytest.mark.parametrize("schema_name", ("foo", "bar", "baz")) def test_get_schema_from_module_bad_name(tmp_path, schema_name): pth = Path(tmp_path) / "bar3.py" - pth.write_text("dead='beef'") + pth.write_text("dead: str='beef'") module = load_schema_module(pth) # fails because it's not found in the module