def _set_default_object_properties(properties, instance, include_yaml_comments, yaml_indent): """ Helper for extend_with_default_without_validation(). Inject default values for the given object properties on the given instance. """ for property_name, subschema in properties.items(): if instance == "{{NO_DEFAULT}}": continue if "default" in subschema: default = copy.deepcopy(subschema["default"]) if isinstance(default, list): try: # Lists of numbers should use 'flow style' # and so should lists-of-lists of numbers # (e.g. bounding boxes like [[0,0,0],[1,2,3]]) if (subschema["items"]["type"] in ("integer", "number") or (subschema["items"]["type"] == "array" and subschema["items"]["items"]["type"] in ("integer", "number"))): default = flow_style(default) except KeyError: pass if include_yaml_comments and isinstance(default, dict): default = CommentedMap(default) # To keep track of the current indentation level, # we just monkey-patch this member onto the dict. default.key_indent = instance.key_indent + yaml_indent default.from_default = True if include_yaml_comments and isinstance(default, list): if not isinstance(default, CommentedSeq): default = CommentedSeq(copy.copy(default)) # To keep track of the current indentation level, # we just monkey-patch this member onto the dict. default.key_indent = instance.key_indent + yaml_indent default.from_default = True if isinstance(instance, Mapping) and property_name not in instance: instance[property_name] = default else: if isinstance(instance, Mapping) and property_name not in instance: instance[property_name] = "{{NO_DEFAULT}}" if include_yaml_comments and "description" in subschema: comment = '\n' + subschema["description"] if comment[-1] == '\n': comment = comment[:-1] instance.yaml_set_comment_before_after_key(property_name, comment, instance.key_indent)
def set_default_object_properties(validator, properties, instance, schema): for property, subschema in properties.items(): if instance == "{{NO_DEFAULT}}": continue if "default" in subschema: default = copy.deepcopy(subschema["default"]) if isinstance(default, list): try: # Lists of numbers should use 'flow style' # and so should lists-of-lists of numbers # (e.g. bounding boxes like [[0,0,0],[1,2,3]]) if (subschema["items"]["type"] in ("integer", "number") or (subschema["items"]["type"] == "array" and subschema["items"]["items"]["type"] in ("integer", "number"))): default = flow_style(default) except KeyError: pass if include_yaml_comments and isinstance(default, dict): default = CommentedMap(default) # To keep track of the current indentation level, # we just monkey-patch this member onto the dict. default.key_indent = instance.key_indent + yaml_indent default.from_default = True if include_yaml_comments and isinstance(default, list): if not isinstance(default, CommentedSeq): default = CommentedSeq(copy.copy(default)) # To keep track of the current indentation level, # we just monkey-patch this member onto the dict. default.key_indent = instance.key_indent + yaml_indent default.from_default = True if property not in instance: instance[property] = default else: if property not in instance: instance[property] = "{{NO_DEFAULT}}" if include_yaml_comments and "description" in subschema: comment = '\n' + subschema["description"] if comment[-1] == '\n': comment = comment[:-1] instance.yaml_set_comment_before_after_key( property, comment, instance.key_indent) for _error in validate_properties(validator, properties, instance, schema): # Ignore validation errors pass
def set_default_object_properties(validator, properties, instance, schema): for property, subschema in properties.items(): if instance == "{{NO_DEFAULT}}": continue if "default" in subschema: default = copy.deepcopy(subschema["default"]) if isinstance(default, list): try: # Lists of numbers should use 'flow style' # and so should lists-of-lists of numbers # (e.g. bounding boxes like [[0,0,0],[1,2,3]]) if ( subschema["items"]["type"] in ("integer", "number") or ( subschema["items"]["type"] == "array" and subschema["items"]["items"]["type"] in ("integer", "number") ) ): default = flow_style(default) except KeyError: pass if include_yaml_comments and isinstance(default, dict): default = CommentedMap(default) # To keep track of the current indentation level, # we just monkey-patch this member onto the dict. default.key_indent = instance.key_indent + yaml_indent default.from_default = True if include_yaml_comments and isinstance(default, list): if not isinstance(default, CommentedSeq): default = CommentedSeq(copy.copy(default)) # To keep track of the current indentation level, # we just monkey-patch this member onto the dict. default.key_indent = instance.key_indent + yaml_indent default.from_default = True if property not in instance: instance[property] = default else: if property not in instance: instance[property] = "{{NO_DEFAULT}}" if include_yaml_comments and "description" in subschema: comment = '\n' + subschema["description"] if comment[-1] == '\n': comment = comment[:-1] instance.yaml_set_comment_before_after_key(property, comment, instance.key_indent) for _error in validate_properties(validator, properties, instance, schema): # Ignore validation errors pass
def inject_defaults(instance, schema, include_yaml_comments=False, yaml_indent=2, cls=None, *args, **kwargs): """ Like the above validate_and_inject_defaults, but: 1. Ignore schema validation errors and 'required' property errors 2. If no default is given for a property, inject '{{NO_DEFAULT}}', even if the property isn't supposed to be a string. 3. If include_yaml_comments is True, insert CommentedMap objects instead of ordinary dicts, and insert a comment above each key, with the contents of the property "description" in the schema. Args: instance: The Python object to inject defaults into. May be an empty dict ({}). schema: The schema data to pull defaults from include_yaml_comments: Whether or not to return ruamel.yaml-compatible dicts so that comments will be written when the data is dumped to YAML. yaml_indent: To ensure correctly indented comments, you must specify the indent step you plan to use when this data is eventually dumped as yaml. Returns: A copy of instance, with default values injected, and comments if specified. """ if cls is None: cls = validators.validator_for(schema) cls.check_schema(schema) # Add default-injection behavior to the validator extended_cls = extend_with_default_without_validation( cls, include_yaml_comments, yaml_indent) if include_yaml_comments: instance = CommentedMap(instance) instance.key_indent = 0 # monkey-patch! else: instance = dict(instance) # Inject defaults. extended_cls(schema, *args, **kwargs).validate(instance) return instance
def fill_in_default_array_items(validator, items, instance, schema): if include_yaml_comments and items["type"] == "object": new_items = [] for item in instance: new_item = CommentedMap(item) new_item.key_indent = instance.key_indent + yaml_indent new_items.append(new_item) instance.clear() instance.extend(new_items) # Descend into array list for _error in validate_items(validator, items, instance, schema): # Ignore validation errors pass
def inject_defaults(instance, schema, include_yaml_comments=False, yaml_indent=2, cls=None, *args, **kwargs): """ Like the above validate_and_inject_defaults, but: 1. Ignore schema validation errors and 'required' property errors 2. If no default is given for a property, inject '{{NO_DEFAULT}}', even if the property isn't supposed to be a string. 3. If include_yaml_comments is True, insert CommentedMap objects instead of ordinary dicts, and insert a comment above each key, with the contents of the property "description" in the schema. Args: instance: The Python object to inject defaults into. May be an empty dict ({}). schema: The schema data to pull defaults from include_yaml_comments: Whether or not to return ruamel.yaml-compatible dicts so that comments will be written when the data is dumped to YAML. yaml_indent: To ensure correctly indented comments, you must specify the indent step you plan to use when this data is eventually dumped as yaml. Returns: A copy of instance, with default values injected, and comments if specified. """ if cls is None: cls = validators.validator_for(schema) cls.check_schema(schema) # Add default-injection behavior to the validator extended_cls = extend_with_default_without_validation(cls, include_yaml_comments, yaml_indent) if include_yaml_comments: instance = CommentedMap(instance) instance.key_indent = 0 # monkey-patch! else: instance = dict(instance) # Inject defaults. extended_cls(schema, *args, **kwargs).validate(instance) return instance
def emit_defaults(schema, include_yaml_comments=False, yaml_indent=2, base_cls=None, *args, **kwargs): """ Emit all default values for the given schema. Similar to calling ``validate({}, schema, inject_defaults=True)``, except: 1. Ignore schema validation errors and 'required' property errors 2. If no default is given for a property, inject ``"{{NO_DEFAULT}}"``, even if the property isn't supposed to be a string. 3. If ``include_yaml_comments`` is True, insert ``CommentedMap`` objects instead of ordinary dicts, and insert a comment above each key, with the contents of the property ``"description"`` in the schema. Args: schema: The schema data to pull defaults from include_yaml_comments: Whether or not to return ``ruamel.yaml`` objects so that comments will be written when the data is dumped to YAML. yaml_indent: To ensure correctly indented comments, you must specify the indent step you plan to use when this data is eventually dumped as yaml. Returns: A copy of instance, with default values injected, and comments if specified. """ instance = {} if include_yaml_comments: instance = CommentedMap(instance) instance.key_indent = 0 # monkey-patch! if "description" in schema: instance.yaml_set_start_comment('\n' + schema["description"] + '\n\n') else: instance = dict(instance) if base_cls is None: base_cls = validators.validator_for(schema) base_cls.check_schema(schema) def is_object(checker, instance): return (base_cls.TYPE_CHECKER.is_type(instance, "object") or isinstance(instance, (ordereddict, CommentedMap))) def is_array(checker, instance): return (base_cls.TYPE_CHECKER.is_type(instance, "array") or isinstance(instance, CommentedSeq)) # By default, jsonschema expects JSON objects to be of type 'dict'. # We also want to permit ruamel.yaml.comments.CommentedSeq and CommentedMap type_checker = base_cls.TYPE_CHECKER.redefine_many({ "object": is_object, "array": is_array }) cls = validators.extend(base_cls, type_checker=type_checker) # Add default-injection behavior to the validator cls = extend_with_default_without_validation(cls, include_yaml_comments, yaml_indent) extended_validator = cls(schema, *args, **kwargs) # Inject defaults. extended_validator.validate(instance) return instance