Whole file
keleshev/schema
The author described this change as “Fix custom error on a key schema being lost for wrong keys”. It counts as a record because the check below fails on the code as it stood at 27e268d4f and passes on 15158c539, with nothing else changed between the two runs.
Projectkeleshev/schema
Fix saved2026-06-15
Sharing licenceMIT · LICENSE-MIT
Change size+21 −3
What the code was meant to do, written into the code itself as a save note
Fix custom error on a key schema being lost for wrong keys
The change
| 459 | 459 | if hasattr(skey, "reset"): | |
| 460 | 460 | exitstack.callback(skey.reset) | |
| 461 | 461 | ||
| 462 | + | # Custom errors from key schemas that rejected a data key, kept so | |
| 463 | + | # they can be surfaced if that key ends up being a wrong key. | |
| 464 | + | key_errors: Dict = {} | |
| 462 | 465 | with exitstack: | |
| 463 | 466 | # Evaluate dictionaries last | |
| 464 | 467 | data_items = sorted( | |
| ⋯ | |||
| 469 | 472 | svalue = s[skey] | |
| 470 | 473 | try: | |
| 471 | 474 | nkey = Schema(skey, error=e).validate(key, **kwargs) | |
| 472 | - | except SchemaError: | |
| 473 | - | pass | |
| 475 | + | except SchemaError as x: | |
| 476 | + | # If the rejecting key schema carries a custom error, | |
| 477 | + | # remember it in case this data key is reported as wrong. | |
| 478 | + | if getattr(skey, "_error", None) is not None: | |
| 479 | + | key_errors[key] = x.code | |
| 474 | 480 | else: | |
| 475 | 481 | if isinstance(skey, Hook): | |
| 476 | 482 | # As the content of the value makes little sense for | |
| ⋯ | |||
| 525 | 531 | data, | |
| 526 | 532 | ) | |
| 527 | 533 | message = self._prepend_schema_name(message) | |
| 528 | - | raise SchemaWrongKeyError(message, e.format(data) if e else None) | |
| 534 | + | # Surface any custom error from the key schema(s) that rejected | |
| 535 | + | # the wrong key(s), so an explicit `error=` is not silently lost. | |
| 536 | + | custom_errors = [ | |
| 537 | + | key_errors[k] | |
| 538 | + | for k in sorted(wrong_keys, key=repr) | |
| 539 | + | if k in key_errors | |
| 540 | + | ] | |
| 541 | + | errors: Union[List, str, None] = ( | |
| 542 | + | [e.format(data) if e else None] + custom_errors | |
| 543 | + | if custom_errors | |
| 544 | + | else (e.format(data) if e else None) | |
| 545 | + | ) | |
| 546 | + | raise SchemaWrongKeyError(message, errors) | |
| 529 | 547 | ||
| 530 | 548 | # Apply default-having optionals that haven't been used: | |
| 531 | 549 | defaults = ( | |
The check that tells the two apart
fail→pass·test_schema.py::test_wrong_key_reports_key_schema_error
Check file test_schema.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.
Origin and history
The code before it27e268d4fc36a169b9a3296fe03d3b897fc0bf2f
Broken version dated2026-06-13
Moduleschema.__init__
Units changedSchema
Fingerprint0f3dc1fd1d934307
Checked2026-08-18 by goldset/0.1
Every field above is generated by our program. None of it is written by hand.
Other bugs found in keleshev/schema
- 2026-06-13Fix TypeError when building the key error message for a tuple key
- 2025-02-27fix: JSON Schema missing title in subschemas
- 2017-01-17fix: Schema can be inherited (#127)
- 2016-02-16add strict flag in Schema class to skip wrong key validation without wildcard
- 2015-09-26Fix reliance on `__name__` of callables
- 2014-02-03Handle wrong keys better. Fixes #3 and #15