예제 #1
0
    def descend_schema(self, walk, schema, meta):
        ref = schema.val.get("$ref")
        if ref is None:
            return None

        if ref in self.refs_descended:
            return schema

        if walk.resolver.is_remote_ref(ref):
            return schema

        self.refs_descended.add(ref)

        with walk.resolver.resolving(ref) as resolved:

            rinstance = JSONValue(resolved, ref)
            if not walk.is_type(rinstance, 'object'):
                raise SchemaError("'$ref' does not point to an object")

            result = walk.descend(rinstance, meta)

            resolved.clear()
            resolved.update(result.val)

        return schema
예제 #2
0
    def merge(self,
              walk,
              base,
              head,
              schema,
              meta,
              idRef="id",
              ignoreId=None,
              **kwargs):
        if not walk.is_type(head, "array"):
            raise HeadInstanceError(
                "Head for an 'arrayMergeById' merge strategy is not an array"
            )  # nopep8

        if base is None:
            base = []
        else:
            if not walk.is_type(base, "array"):
                raise BaseInstanceError(
                    "Base for an 'arrayMergeById' merge strategy is not an array"
                )  # nopep8
            base = list(base)

        subschema = None

        if schema:
            subschema = schema.get('items')

        if walk.is_type(subschema, "array"):
            raise SchemaError(
                "'arrayMergeById' not supported when 'items' is an array")

        for head_item in head:

            try:
                head_key = walk.resolver.resolve_fragment(head_item, idRef)
            except jsonschema.RefResolutionError:
                # Do nothing if idRef field cannot be found.
                continue

            if head_key == ignoreId:
                continue

            key_count = 0
            for i, base_item in enumerate(base):
                base_key = walk.resolver.resolve_fragment(base_item, idRef)
                if base_key == head_key:
                    key_count += 1
                    # If there was a match, we replace with a merged item
                    base[i] = walk.descend(subschema, base_item, head_item,
                                           meta)
            if key_count == 0:
                # If there wasn't a match, we append a new object
                base.append(walk.descend(subschema, None, head_item, meta))
            if key_count > 1:
                raise BaseInstanceError("Id was not unique")

        return base
예제 #3
0
    def merge(self, walk, base, head, schema, meta, idRef="id", ignoreId=None, **kwargs):
        if not walk.is_type(head, "array"):
            raise HeadInstanceError("Head for an 'arrayMergeById' merge strategy is not an array", head)  # nopep8

        if base.is_undef():
            base = JSONValue([], base.ref)
        else:
            if not walk.is_type(base, "array"):
                raise BaseInstanceError("Base for an 'arrayMergeById' merge strategy is not an array", base)  # nopep8
            base = JSONValue(list(base.val), base.ref)

        subschema = schema.get('items')

        if walk.is_type(subschema, "array"):
            raise SchemaError("'arrayMergeById' not supported when 'items' is an array", subschema)

        def iter_index_key_item(jv):
            for i, item in enumerate(jv):
                try:
                    key = walk.resolver.resolve_fragment(item.val, idRef)
                except jsonschema.RefResolutionError:
                    continue

                yield i, key, item

        for i, key_1, item_1 in iter_index_key_item(head):
            for j, key_2, item_2 in iter_index_key_item(head):
                if j < i:
                    if key_1 == key_2:
                        raise HeadInstanceError("Id '%s' was not unique in head" % (key_1,), item_1)
                else:
                    break

        for i, head_key, head_item in iter_index_key_item(head):

            if head_key == ignoreId:
                continue

            matching_j = []
            for j, base_key, base_item in iter_index_key_item(base):

                if base_key == head_key:
                    matching_j.append(j)
                    matched_item = base_item

            if len(matching_j) == 1:
                # If there was exactly one match, we replace it with a merged item
                j = matching_j[0]
                base[j] = walk.descend(subschema, matched_item, head_item, meta)
            elif len(matching_j) == 0:
                # If there wasn't a match, we append a new object
                base.append(walk.descend(subschema, JSONValue(undef=True), head_item, meta))
            else:
                j = matching_j[1]
                raise BaseInstanceError("Id '%s' was not unique in base" % (base_key,), base[j])

        return base
예제 #4
0
    def merge(self,
              walk,
              base,
              head,
              schema,
              meta,
              objclass_menu=None,
              objClass='_default',
              **kwargs):
        if not walk.is_type(head, "object"):
            raise HeadInstanceError(
                "Head for an 'object' merge strategy is not an object", head)

        if objclass_menu is None:
            objclass_menu = {'_default': dict}

        objcls = objclass_menu.get(objClass)
        if objcls is None:
            raise SchemaError("objClass '%s' not recognized" % objClass,
                              schema)

        if base.is_undef():
            base = JSONValue(objcls(), base.ref)
        else:
            if not walk.is_type(base, "object"):
                raise BaseInstanceError(
                    "Base for an 'object' merge strategy is not an object",
                    base)

            base = JSONValue(objcls(base.val), base.ref)

        for k, v in head.items():

            subschema = JSONValue(undef=True)

            # get subschema for this element
            if not schema.is_undef():
                p = schema.get('properties')
                if not p.is_undef():
                    subschema = p.get(k)

                if subschema.is_undef():
                    p = schema.get('patternProperties')
                    if not p.is_undef():
                        for pattern, s in p.items():
                            if re.search(pattern, k):
                                subschema = s

                if subschema.is_undef():
                    p = schema.get('additionalProperties')
                    # additionalProperties can be boolean in draft 4
                    if not p.is_undef() and walk.is_type(p, "object"):
                        subschema = p

            base[k] = walk.descend(subschema, base.get(k), v, meta)

        return base
예제 #5
0
    def merge(self,
              walk,
              base,
              head,
              schema,
              limit=None,
              unique=None,
              ignoreDups=True,
              metadata=None,
              **kwargs):

        # backwards compatibility
        if unique is False:
            ignoreDups = False

        if metadata is not None:
            if not walk.is_type(JSONValue(val=metadata), "object"):
                raise SchemaError(
                    "'metadata' option does not contain an object")

        if base.is_undef():
            base = JSONValue(val=[], ref=base.ref)
            last_entry = JSONValue(undef=True)
        else:
            if not walk.is_type(base, "array"):
                raise BaseInstanceError(
                    "Base is not an array. "
                    "Base not previously generated with this strategy?", base)

            base = JSONValue(list(base.val), base.ref)

            if base.val:
                last_entry = base[-1]

                if not walk.is_type(last_entry, "object"):
                    raise BaseInstanceError(
                        "Last entry in the versioned array is not an object. "
                        "Base not previously generated with this strategy?",
                        last_entry)

                if 'value' not in last_entry.val:
                    raise BaseInstanceError(
                        "Last entry in the versioned array has no 'value' property. "
                        "Base not previously generated with this strategy?",
                        last_entry)
            else:
                last_entry = JSONValue(undef=True)

        if not ignoreDups or last_entry.is_undef(
        ) or last_entry['value'].val != head.val:
            base.val.append(self.add_metadata(head.val, metadata))
            if limit is not None:
                base.val = base.val[-limit:]

        return base
예제 #6
0
    def merge(self, walk, base, head, schema, meta, idRef="id", ignoreId=None, **kwargs):
        if not walk.is_type(head, "array"):
            raise HeadInstanceError("Head for an 'arrayMergeById' merge strategy is not an array")  # nopep8

        if base.is_undef():
            base = JSONValue([], base.ref)
        else:
            if not walk.is_type(base, "array"):
                raise BaseInstanceError("Base for an 'arrayMergeById' merge strategy is not an array")  # nopep8
            base = JSONValue(list(base.val), base.ref)

        subschema = schema.get('items')

        if walk.is_type(subschema, "array"):
            raise SchemaError("'arrayMergeById' not supported when 'items' is an array")

        def iter_index_key_item(jv):
            for i, item in enumerate(jv):
                try:
                    key = walk.resolver.resolve_fragment(item.val, idRef)
                except jsonschema.RefResolutionError:
                    continue

                yield i, key, item

        for i, key_1, item_1 in iter_index_key_item(head):
            for j, key_2, item_2 in iter_index_key_item(head):
                if j < i:
                    if key_1 == key_2:
                        raise HeadInstanceError("Id was not unique")
                else:
                    break

        for i, head_key, head_item in iter_index_key_item(head):

            if head_key == ignoreId:
                continue

            key_count = 0
            for j, base_key, base_item in iter_index_key_item(base):

                if base_key == head_key:
                    key_count += 1
                    # If there was a match, we replace with a merged item
                    base.val[j] = walk.descend(subschema, base_item, head_item, meta).val

            if key_count == 0:
                # If there wasn't a match, we append a new object
                base.val.append(walk.descend(subschema, JSONValue(undef=True), head_item, meta).val)
            if key_count > 1:
                raise BaseInstanceError("Id was not unique")

        return base
    def descend(self, schema):
        allOf = schema.get("allOf")
        anyOf = schema.get("anyOf")
        if allOf.is_undef() and anyOf.is_undef():
            return None

        # We must have a strategy defined on this level, or we can't know which
        # subschema to descend to.
        if not schema.get("mergeStrategy").is_undef():
            return None

        raise SchemaError("Can't descend to 'allOf' and 'anyOf' keywords", schema)
예제 #8
0
    def descend(self, schema, *args):
        assert isinstance(schema, JSONValue)
        self.lvl += 1

        log.debug("descend: %sschema %s" % (
            self._indent(),
            schema.ref,
        ))

        if not schema.is_undef():
            with self.resolver.resolving(schema.ref) as resolved:
                assert schema.val is resolved

        # backwards compatibility jsonmerge<=1.6.0
        opts = {'meta': None}

        if not schema.is_undef():

            for descender in self.descenders:
                rv = self.call_descender(descender, schema, *args)
                if rv is not None:
                    self.lvl -= 1
                    return rv

            name = schema.val.get("mergeStrategy")

            for v in (self.merge_options.get(name),
                      schema.val.get("mergeOptions")):
                if v is not None:
                    opts.update(v)
        else:
            name = None

        if name is None:
            name = self.default_strategy(schema, *args, **opts)

        log.debug("descend: %sinvoke strategy %s" % (self._indent(), name))

        try:
            strategy = self.merger.strategies[name]
        except KeyError:
            raise SchemaError("Unknown strategy '%s'" % name, schema)

        try:
            rv = self.work(strategy, schema, *args, **opts)
        except JSONMergeError as exc:
            if exc.strategy_name is None:
                exc.strategy_name = name
            raise

        self.lvl -= 1
        return rv
예제 #9
0
    def merge(self, walk, base, head, schema, idRef="id", ignoreId=None, **kwargs):
        if not walk.is_type(head, "array"):
            raise HeadInstanceError("Head is not an array", head)  # nopep8

        if base.is_undef():
            base = JSONValue([], base.ref)
        else:
            if not walk.is_type(base, "array"):
                raise BaseInstanceError("Base is not an array", base)  # nopep8
            base = JSONValue(list(base.val), base.ref)

        subschema = schema.get('items')

        if walk.is_type(subschema, "array"):
            raise SchemaError("This strategy is not supported when 'items' is an array", subschema)

        for i, key_1, item_1 in self.iter_index_key_item(walk, head, idRef):
            for j, key_2, item_2 in self.iter_index_key_item(walk, head, idRef):
                if j < i:
                    if key_1 == key_2:
                        raise HeadInstanceError("Id '%s' was not unique in head" % (key_1,), item_1)
                else:
                    break

        for i, head_key, head_item in self.iter_index_key_item(walk, head, idRef):

            if head_key == ignoreId:
                continue

            matching_j = []
            for j, base_key, base_item in self.iter_index_key_item(walk, base, idRef):

                if base_key == head_key:
                    matching_j.append(j)
                    matched_item = base_item

            if len(matching_j) == 1:
                # If there was exactly one match, we replace it with a merged item
                j = matching_j[0]
                base[j] = walk.descend(subschema, matched_item, head_item)
            elif len(matching_j) == 0:
                # If there wasn't a match, we append a new object
                base.append(walk.descend(subschema, JSONValue(undef=True), head_item))
            else:
                j = matching_j[1]
                raise BaseInstanceError("Id '%s' was not unique in base" % (base_key,), base[j])

        return base
예제 #10
0
    def descend(self, schema, *args):
        assert isinstance(schema, JSONValue)
        self.lvl += 1

        log.debug("descend: %sschema %s" % (
            self._indent(),
            schema.ref,
        ))

        if not schema.is_undef():
            with self.resolver.resolving(schema.ref) as resolved:
                assert schema.val == resolved

        if not schema.is_undef():

            for descender in self.descenders:
                rv = self.call_descender(descender, schema, *args)
                if rv is not None:
                    self.lvl -= 1
                    return rv

            name = schema.val.get("mergeStrategy")
            opts = schema.val.get("mergeOptions")
            if opts is None:
                opts = {}
        else:
            name = None
            opts = {}

        if name is None:
            name = self.default_strategy(schema, *args, **opts)

        log.debug("descend: %sinvoke strategy %s" % (self._indent(), name))

        try:
            strategy = self.merger.strategies[name]
        except KeyError:
            raise SchemaError("Unknown strategy '%s'" % name, schema)

        rv = self.work(strategy, schema, *args, **opts)

        self.lvl -= 1
        return rv
예제 #11
0
    def get_schema(self, walk, schema, meta, **kwargs):

        for forbidden in ("oneOf", "allOf", "anyOf"):
            if forbidden in schema:
                raise SchemaError("Type ambiguous schema")

        schema2 = dict(schema)

        def descend_keyword(keyword):
            p = schema.get(keyword)
            if p is not None:
                for k, v in p.items():
                    schema2[keyword][k] = walk.descend(v, meta)

        descend_keyword("properties")
        descend_keyword("patternProperties")
        descend_keyword("additionalProperties")

        return schema2
예제 #12
0
    def get_schema(self, walk, schema, meta, **kwargs):

        for forbidden in ("oneOf", "allOf", "anyOf"):
            if forbidden in schema.val:
                raise SchemaError("Type ambiguous schema")

        schema2 = JSONValue(dict(schema.val), schema.ref)

        def descend_keyword(keyword):
            p = schema.get(keyword)
            if not p.is_undef():
                for k, v in p.items():
                    schema2.val[keyword][k] = walk.descend(v, meta).val

        descend_keyword("properties")
        descend_keyword("patternProperties")

        p = schema.get("additionalProperties")
        if not p.is_undef():
            schema2.val["additionalProperties"] = walk.descend(p, meta).val

        return schema2
예제 #13
0
 def descend(self, schema):
     for forbidden in ("allOf", "anyOf"):
         if forbidden in schema.val:
             raise SchemaError(
                 "Can't descend to 'allOf' and 'anyOf' keywords")
     return None