Example #1
0
    def add(data, target_path, value, fail_on_exists=True, update=False):
        # type errors can occur here ...
        # e.g. you try to go to a string
        if not [_ for _ in (list, tuple) if isinstance(target_path, _)]:
            raise TypeError(f'target_path is not a list or tuple! {type(target_path)}')
        target_prefixes = target_path[:-1]
        target_key = target_path[-1]
        target = data
        for target_name in target_prefixes:
            if target_name not in target:  # TODO list indicies
                target[target_name] = {}

            target = target[target_name]

        if update:
            pass
        elif fail_on_exists and target_key in target:
            raise exc.TargetPathExistsError(f'A value already exists at path {target_path}\n'
                                            f'{lj(data)}')

        target[target_key] = value
Example #2
0
    def add(data, target_path, value, fail_on_exists=True, update=False):
        """ Note on semantics when target_path contains the type int.
            Normally when adding a path all the parents are added because
            we are expecting a direct path down. However, if the path
            contains int then it implicitly expects the list to alread
            exist. Therefore any failure on the way TO a list will
            immediately abort and not add the keys to the non-existent list.
            This is consistent with the approach where keys are not required
            but if their value is a list it must not be empty. Thus we abort
            so that we don't go around creating a bunch of empty lists that
            will show up later as errors when validating the schema. """
        # type errors can occur here ...
        # e.g. you try to go to a string
        if not [_ for _ in (list, tuple) if isinstance(target_path, _)]:
            msg = f'target_path is not a list or tuple! {type(target_path)}'
            raise TypeError(msg)

        if False and target_path == ['@context', '@base']:
            # use to debug TargetPathExistsError issues
            if '@tracker' not in data:
                data['@tracker'] = []
            try:
                raise BaseException('tracker')
            except BaseException as e:
                data['@tracker'].append(e)

            if '@context' in data and '@base' in data['@context']:
                log.critical(f'target present {data["id"]}')
            else:
                log.critical(f'target not present {data["id"]}')

        target_prefixes = target_path[:-1]
        target_key = target_path[-1]
        target = data
        is_subpath_add = int in target_path
        for i, target_name in enumerate(target_prefixes):
            if target_name is int:  # add same value to all objects in list
                if not is_list_or_tuple(target):
                    msg = (f'attempt to add to all elements of not a list '
                           f'{type(target)} target_path was {target_path} '
                           f'target_name was {target_name}')
                    raise TypeError(msg)
                # LOL PYTHON namespaces
                [AtomicDictOperations.add(subtarget, target_path[i + 1:], value)
                 for subtarget in target]
                return  # int terminates this level of an add

            if target_name not in target:  # TODO list indicies XXX that is really append though ...
                if is_subpath_add:
                    # if we are targeting objects in a list for addition
                    # abort the first time we would have to create a key
                    # because we will eventually create an empty list
                    # which we won't be able to add anything to and will
                    # likely cause schema validation errors
                    return

                target[target_name] = {}

            target = target[target_name]

        if update:
            pass
        elif fail_on_exists and target_key in target:
            msg = f'A value already exists at path {target_path} in\n{lj(data)}'
            raise exc.TargetPathExistsError(msg)

        target[target_key] = value