diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0795665e5..add473fbe 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,14 @@ +v4.10.1 +------- + +* Fix Validator.evolve (and APIs like ``iter_errors`` which call it) for cases + where the validator class has been subclassed. Doing so wasn't intended to be + public API, but given it didn't warn or raise an error it's of course + understandable. The next release however will make it warn (and a future one + will make it error). If you need help migrating usage of inheriting from a + validator class feel free to open a discussion and I'll try to give some + guidance (#982). + v4.10.0 ------- diff --git a/jsonschema/tests/test_validators.py b/jsonschema/tests/test_validators.py index 064336216..87fa1edeb 100644 --- a/jsonschema/tests/test_validators.py +++ b/jsonschema/tests/test_validators.py @@ -1463,6 +1463,38 @@ def test_it_delegates_to_a_ref_resolver(self): with self.assertRaises(exceptions.ValidationError): validator.validate(None) + def test_evolve(self): + ref, schema = "someCoolRef", {"type": "integer"} + resolver = validators.RefResolver("", {}, store={ref: schema}) + + validator = self.Validator(schema, resolver=resolver) + new = validator.evolve(schema={"type": "string"}) + + expected = self.Validator({"type": "string"}, resolver=resolver) + + self.assertEqual(new, expected) + self.assertNotEqual(new, validator) + + def test_evolve_with_subclass(self): + """ + Subclassing validators isn't supported public API, but some users have + done it, because we don't actually error entirely when it's done :/ + + We need to deprecate doing so first to help as many of these users + ensure they can move to supported APIs, but this test ensures that in + the interim, we haven't broken those users. + """ + + @attr.s + class OhNo(self.Validator): + foo = attr.ib(factory=lambda: [1, 2, 3]) + + validator = OhNo({}) + self.assertEqual(validator.foo, [1, 2, 3]) + + new = validator.evolve(schema={"type": "integer"}) + self.assertEqual(new.foo, [1, 2, 3]) + def test_it_delegates_to_a_legacy_ref_resolver(self): """ Legacy RefResolvers support only the context manager form of diff --git a/jsonschema/validators.py b/jsonschema/validators.py index 4d6ced011..c799d4075 100644 --- a/jsonschema/validators.py +++ b/jsonschema/validators.py @@ -203,7 +203,7 @@ def check_schema(cls, schema): def evolve(self, **changes): schema = changes.setdefault("schema", self.schema) - NewValidator = validator_for(schema, default=Validator) + NewValidator = validator_for(schema, default=self.__class__) # Essentially reproduces attr.evolve, but may involve instantiating # a different class than this one.