-
-
Notifications
You must be signed in to change notification settings - Fork 86
[change] Merging with wrong format now raises Validation error #351 #355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cc04ab9
e14de58
a9969bf
f007bd0
ada4cbd
9d0c8b1
aae7645
afb97cc
21df8d7
b87a1ea
68343b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,10 @@ | |
| from collections import OrderedDict | ||
| from copy import deepcopy | ||
|
|
||
| from jsonschema import ValidationError as JsonSchemaError | ||
|
|
||
| from .exceptions import ValidationError | ||
|
|
||
|
|
||
| def merge_config(template, config, list_identifiers=None): | ||
| """ | ||
|
|
@@ -19,14 +23,27 @@ def merge_config(template, config, list_identifiers=None): | |
| :param config: config ``dict`` | ||
| :param list_identifiers: ``list`` or ``None`` | ||
| :returns: merged ``dict`` | ||
| :raises ValidationError: if incompatible types are found | ||
| """ | ||
| result = deepcopy(template) | ||
| for key, value in config.items(): | ||
| if isinstance(value, dict): | ||
| node = result.get(key, OrderedDict()) | ||
| result[key] = merge_config(node, value) | ||
| elif isinstance(value, list) and isinstance(result.get(key), list): | ||
| result[key] = merge_list(result[key], value, list_identifiers) | ||
| existing = result.get(key) | ||
| if isinstance(value, dict) and isinstance(existing, dict): | ||
| result[key] = merge_config(existing, value, list_identifiers) | ||
| elif isinstance(value, list) and isinstance(existing, list): | ||
| result[key] = merge_list(existing, value, list_identifiers) | ||
| elif ( | ||
| existing is not None | ||
| and isinstance(existing, (dict, list)) | ||
| and isinstance(value, (dict, list)) | ||
| and type(value) is not type(existing) | ||
| ): | ||
| raise ValidationError( | ||
| JsonSchemaError( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This constructs a |
||
| f"Incompatible type for '{key}': expected {type(existing).__name__}, " | ||
| f"got {type(value).__name__}." | ||
| ) | ||
| ) | ||
| else: | ||
| result[key] = value | ||
| return result | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This guard applies at every recursive merge level, not only to the top level package shape conflict from issue 351. It now rejects cases where a matched custom UCI block overrides a list option with a scalar option, even though the merge contract says simple values in the config overwrite values in the template. For example, a template dnsmasq block with
server: ["1.1.1.1"]and device config withserver: "8.8.8.8"used to merge, but now raises becauseexistingis a list andvalueis a string. Please scope the validation to the package shape conflict or other cases that would otherwise crash, unless this broader behavior change is intentional and documented.