예제 #1
0
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)
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
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
예제 #5
0
    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
예제 #6
0
    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
예제 #7
0
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
예제 #8
0
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