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
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
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
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
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
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)
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
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
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
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
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
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