Exemple #1
0
    def __init__(self, directive, arguments, options, content, lineno, content_offset, block_text, state, state_machine):
        assert directive == 'jsonschema'

        self.options = options
        self.state = state
        self.lineno = lineno
        self.statemachine = state_machine

        if len(arguments) == 1:
            filename, pointer = self._splitpointer(arguments[0])
            if filename != '':
                self._load_external(filename)
            else:
                self._load_internal(content)
            if pointer:
                self.schema = resolve_pointer(self.schema, pointer)
        else:
            self._load_internal(content)

        hidden_paths = self.options.get('hide')
        if hidden_paths is not None:
            orig_schema = json.loads(json.dumps(self.schema))

            for hidden_path in hidden_paths.split(' '):
                ptr = JsonPointer(hidden_path)
                parent, name = ptr.to_last(self.schema)
                del parent[name]

            shown_paths = self.options.get('show')

            for shown_path in shown_paths.split(' '):
                ptr = JsonPointer(shown_path)

                orig_parent = orig_schema
                current_parent = self.schema

                for part in ptr.parts[:-1]:
                    orig_parent = ptr.walk(orig_parent, part)

                    try:
                        current_parent = ptr.walk(current_parent, part)
                    except JsonPointerException:
                        if isinstance(orig_parent, Sequence):
                            new_entry = []
                        elif isinstance(orig_parent, Mapping):
                            new_entry = OrderedDict()
                        else:
                            raise Exception('Unsupported type parent')

                        if isinstance(current_parent, MutableSequence):
                            current_parent.append(new_entry)
                        elif isinstance(current_parent, MutableMapping):
                            current_parent[part] = new_entry

                        current_parent = new_entry

                if isinstance(current_parent, MutableSequence):
                    current_parent.append(ptr.resolve(orig_schema))
                elif isinstance(current_parent, MutableMapping):
                    current_parent[ptr.parts[-1]] = ptr.resolve(orig_schema)
                else:
                    raise Exception('Unsupported type parent')
Exemple #2
0
def _set_val(
    pointer: str,
    val: object,
    context: dict,
    root: Union[dict, None] = None,
    context_pointer: Union[str, None] = None,
):
    """
    This function given a *pointer* (jsonpointer RFC 6901 or relative json pointer)
    to a property in a python object, sets the supplied value
    in-place in the *context* object within *root* object.
    The object we are adding data to is *root*. The object
    may or may not have any of the intermediate structure
    to fully insert the desired property.
    For example: consider
    pointer = "0/prop1/prop2"
    val = {"more": "props"}
    context = {"Pid": 1}
    root = {"participants": [context]}
    context_pointer = "/participants/0"


    First we see an `0` in pointer which denotes update
    should be within context. So no need to jump higher than context.

    So we truncate path to = "prop1/prop2"
    We see it's a string, so we know we are entering object's *prop1* as a property:
        {
            "participants": [{
                "prop1": ...
            }]
        }
    It's our whole Trial object, and ... here denotes our current descend.
    Now we truncate path one step further to = "prop2"
    Go down there and set `val={"more": "props"}` :
        {
            "participants": [{
                "prop1": {
                    "prop2": {"more": "props"}
                }
            }]
        }
    While context is a sub-part of that:
            {
                "prop1": {
                    "prop2": {"more": "props"}
                }
            }

    Args:
        pointer: relative jsonpointer to the property being set within current `context`
        val: the value being set
        context: the python object relatively to which val is being set
        root: the whole python object being constructed, contains `context`
        context_pointer: jsonpointer of `context` within `root`. Needed to jump up.
    Returns:
       Nothing
    """

    # don't do anything for None value, asserting None is permissable
    # is handled by the "allow_empty" functionality.
    if val is None:
        return

    # special case to set context doc itself
    if pointer.rstrip("#") == "":
        context.update(val)
        return

    # fill defaults
    if root is None:
        root = context
    if context_pointer is None:
        context_pointer = "/"

    # first we need to convert pointer to an absolute one
    # if it was a relative one (https://tools.ietf.org/id/draft-handrews-relative-json-pointer-00.html)
    if pointer.startswith("/"):
        jpoint = JsonPointer(pointer)
        doc = context

    else:
        # parse "relative" jumps up
        jumpups, slash, rem_pointer = pointer.partition("/")
        try:
            jumpups = int(jumpups.rstrip("#"))
        except ValueError:
            jumpups = 0

        # check that we don't have to jump up more than we dived in already
        assert jumpups <= context_pointer.rstrip("/").count(
            "/"
        ), f"Can't set value for pointer {pointer} too many jumps up from current context: {context_pointer}"

        # and we'll go down remaining part of `pointer` from there
        jpoint = JsonPointer(slash + rem_pointer)
        if jumpups > 0:
            # new context pointer
            higher_context_pointer = "/".join(
                context_pointer.strip("/").split("/")[: -1 * jumpups]
            )
            # making jumps up, by going down context_pointer but no all the way down
            if higher_context_pointer == "":
                doc = root
                assert (
                    len(jpoint.parts) > 0
                ), f"Can't update root object (pointer {pointer})"
            else:
                try:
                    doc = resolve_pointer(root, "/" + higher_context_pointer)
                except Exception as e:
                    raise Exception(e)
        else:
            doc = context

    jp_parts = jpoint.parts

    # then we update it
    for i, part in enumerate(jp_parts[:-1]):

        try:
            doc = jpoint.walk(doc, part)

        except (JsonPointerException, IndexError) as e:
            # means that there isn't needed sub-object in place, so create one

            # look ahead to figure out a proper type that needs to be created
            next_thing = __jpointer_get_next_thing(jp_parts[i + 1])

            # insert it
            __jpointer_insert_next_thing(doc, jpoint, part, next_thing)

            # and `walk` it again - this time should be OK
            doc = jpoint.walk(doc, part)

        if isinstance(doc, EndOfList):
            actual_doc = __jpointer_get_next_thing(jp_parts[i + 1])
            __jpointer_insert_next_thing(doc.list_, jpoint, "-", actual_doc)
            doc = actual_doc

    __jpointer_insert_next_thing(doc, jpoint, jp_parts[-1], val)