<commit_before>import dpath.path
import dpath.exceptions
import traceback
from collections import MutableSequence, MutableMapping

MERGE_REPLACE=(1 << 1)
MERGE_ADDITIVE=(1 << 2)
MERGE_TYPESAFE=(1 << 3)

def __safe_path__(path, separator):
    """
    Given a path and separator, return a list of path components. If path
    is already a list, return it.

    Note that a string path with the separator at index[0] will have the
    separator stripped off. If you pass a list path, the separator is
    ignored, and is assumed to be part of each key glob. It will not be
    stripped.
    """
    if issubclass(path.__class__, (MutableSequence)):
        return path
    path = path.lstrip(separator).split(separator)
    validated = []
    for elem in path:
        key = elem[0]
        strkey = str(key)
        if (separator and (separator in strkey)):
            raise dpath.exceptions.InvalidKeyName("{0} at {1} contains the separator {2}"
                                                  "".format(strkey,
                                                            separator.join(validated),
                                                            separator))
        validated.append(strkey)
    return path

def new(obj, path, value, separator="/"):
    """
    Set the element at the terminus of path to value, and create
    it if it does not exist (as opposed to 'set' that can only
    change existing keys).

    path will NOT be treated like a glob. If it has globbing
    characters in it, they will become part of the resulting
    keys
    """
    pathlist = __safe_path__(path, separator)
    pathobj = dpath.path.path_types(obj, pathlist)
    return dpath.path.set(obj, pathobj, value, create_missing=True)

def delete(obj, glob, separator="/", afilter=None):
    """
    Given a path glob, delete all elements that match the glob.

    Returns the number of deleted objects. Raises PathNotFound if no paths are
    found to delete.
    """
    deleted = 0
    paths = []
    globlist = __safe_path__(glob, separator)
    for path in _inner_search(obj, globlist, separator):
        # These are yielded back, don't mess up the dict.
        paths.append(path)

    for path in paths:
        cur = obj
        prev = None
        for item in path:
            prev = cur
            try:
                cur = cur[item[0]]
            except AttributeError as e:
                # This only happens when we delete X/Y and the next
                # item in the paths is X/Y/Z
                pass
        if (not afilter) or (afilter and afilter(prev[item[0]])):
            prev.pop(item[0])
        deleted += 1
    if not deleted:
        raise dpath.exceptions.PathNotFound("Could not find {0} to delete it".format(glob))
    return deleted<commit_msg>Fixed bug when deleting more than one item in the same list<commit_after>import dpath.path
import dpath.exceptions
import traceback
from collections import MutableSequence, MutableMapping

MERGE_REPLACE=(1 << 1)
MERGE_ADDITIVE=(1 << 2)
MERGE_TYPESAFE=(1 << 3)

def __safe_path__(path, separator):
    """
    Given a path and separator, return a list of path components. If path
    is already a list, return it.

    Note that a string path with the separator at index[0] will have the
    separator stripped off. If you pass a list path, the separator is
    ignored, and is assumed to be part of each key glob. It will not be
    stripped.
    """
    if issubclass(path.__class__, (MutableSequence)):
        return path
    path = path.lstrip(separator).split(separator)
    validated = []
    for elem in path:
        key = elem[0]
        strkey = str(key)
        if (separator and (separator in strkey)):
            raise dpath.exceptions.InvalidKeyName("{0} at {1} contains the separator {2}"
                                                  "".format(strkey,
                                                            separator.join(validated),
                                                            separator))
        validated.append(strkey)
    return path

def new(obj, path, value, separator="/"):
    """
    Set the element at the terminus of path to value, and create
    it if it does not exist (as opposed to 'set' that can only
    change existing keys).

    path will NOT be treated like a glob. If it has globbing
    characters in it, they will become part of the resulting
    keys
    """
    pathlist = __safe_path__(path, separator)
    pathobj = dpath.path.path_types(obj, pathlist)
    return dpath.path.set(obj, pathobj, value, create_missing=True)

def delete(obj, glob, separator="/", afilter=None):
    """
    Given a path glob, delete all elements that match the glob.

    Returns the number of deleted objects. Raises PathNotFound if no paths are
    found to delete.
    """
    deleted = 0
    paths = []
    globlist = __safe_path__(glob, separator)
    for path in _inner_search(obj, globlist, separator):
        # These are yielded back, don't mess up the dict.
        paths.append(path)

    paths.reverse()
    for path in paths:
        cur = obj
        prev = None
        for item in path:
            prev = cur
            try:
                cur = cur[item[0]]
            except AttributeError as e:
                # This only happens when we delete X/Y and the next
                # item in the paths is X/Y/Z
                pass
        if (not afilter) or (afilter and afilter(prev[item[0]])):
            prev.pop(item[0])
        deleted += 1
    if not deleted:
        raise dpath.exceptions.PathNotFound("Could not find {0} to delete it".format(glob))
    return deleted
{'fraction_non_alphanumeric': 0.08078835227272728, 'fraction_numerical': 0.006036931818181818, 'mean_word_length': 2.068082788671024, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1298893', 'n_tokens_mistral': 1569, 'n_tokens_neox': 1509, 'n_words': 605}