Skip to content

Commit c2e86ee

Browse files
committed
Fix calling Validator.evolve for some downstream users.
The broken case here was subclassing a validator class, something that isn't really a supported use of the Validator classes, but of course one can't blame anyone too much since doing so didn't raise an error or emit any warning. In the next release subclassing will warn, and at some point afterwards will become an explicit error. If you're a downstream user of this library looking for a way to avoid whichever inheritance is currently needed in your library feel free to reach out and I'll try to help. Closes: #982
1 parent 0c4aaaf commit c2e86ee

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

CHANGELOG.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
v4.10.1
2+
-------
3+
4+
* Fix Validator.evolve (and APIs like ``iter_errors`` which call it) for cases
5+
where the validator class has been subclassed. Doing so wasn't intended to be
6+
public API, but given it didn't warn or raise an error it's of course
7+
understandable. The next release however will make it warn (and a future one
8+
will make it error). If you need help migrating usage of inheriting from a
9+
validator class feel free to open a discussion and I'll try to give some
10+
guidance (#982).
11+
112
v4.10.0
213
-------
314

jsonschema/tests/test_validators.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,38 @@ def test_it_delegates_to_a_ref_resolver(self):
14631463
with self.assertRaises(exceptions.ValidationError):
14641464
validator.validate(None)
14651465

1466+
def test_evolve(self):
1467+
ref, schema = "someCoolRef", {"type": "integer"}
1468+
resolver = validators.RefResolver("", {}, store={ref: schema})
1469+
1470+
validator = self.Validator(schema, resolver=resolver)
1471+
new = validator.evolve(schema={"type": "string"})
1472+
1473+
expected = self.Validator({"type": "string"}, resolver=resolver)
1474+
1475+
self.assertEqual(new, expected)
1476+
self.assertNotEqual(new, validator)
1477+
1478+
def test_evolve_with_subclass(self):
1479+
"""
1480+
Subclassing validators isn't supported public API, but some users have
1481+
done it, because we don't actually error entirely when it's done :/
1482+
1483+
We need to deprecate doing so first to help as many of these users
1484+
ensure they can move to supported APIs, but this test ensures that in
1485+
the interim, we haven't broken those users.
1486+
"""
1487+
1488+
@attr.s
1489+
class OhNo(self.Validator):
1490+
foo = attr.ib(factory=lambda: [1, 2, 3])
1491+
1492+
validator = OhNo({})
1493+
self.assertEqual(validator.foo, [1, 2, 3])
1494+
1495+
new = validator.evolve(schema={"type": "integer"})
1496+
self.assertEqual(new.foo, [1, 2, 3])
1497+
14661498
def test_it_delegates_to_a_legacy_ref_resolver(self):
14671499
"""
14681500
Legacy RefResolvers support only the context manager form of

jsonschema/validators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def check_schema(cls, schema):
203203

204204
def evolve(self, **changes):
205205
schema = changes.setdefault("schema", self.schema)
206-
NewValidator = validator_for(schema, default=Validator)
206+
NewValidator = validator_for(schema, default=self.__class__)
207207

208208
# Essentially reproduces attr.evolve, but may involve instantiating
209209
# a different class than this one.

0 commit comments

Comments
 (0)