<commit_before>"""Implementation of the XBlock facility.

This code is in the Runtime layer, because it is authored once by edX
and used by all runtimes.

"""
import copy
import functools
import inspect
try:
    import simplesjson as json  # pylint: disable=F0401
except ImportError:
    import json
from collections import namedtuple
from webob import Response

from .plugin import Plugin


class KeyValueMultiSaveError(Exception):
    """
    Raised to indicated an error in saving multiple fields in a KeyValueStore
    """
    def __init__(self, saved_field_names):
        """
        Create a new KeyValueMultiSaveError

        `saved_field_names` - an iterable of field names (strings) that were
        successfully saved before the exception occured
        """
        super(KeyValueMultiSaveError, self).__init__()
        self.saved_field_names = saved_field_names


class XBlockSaveError(Exception):
    """
    Raised to indicated an error in saving an XBlock
    """
    def __init__(self, saved_fields, dirty_fields):
        """
        Create a new XBlockSaveError

        `saved_fields` - a set of fields that were successfully
        saved before the error occured
        `dirty_fields` - a set of fields that were left dirty after the save
        """
        super(XBlockSaveError, self).__init__()
        self.saved_fields = saved_fields
        self.dirty_fields = dirty_fields


UNSET = object()


class ModelData(object):
    """
    An interface allowing access to an XBlock's field values indexed by field names
    """
    def get(self, name, default=UNSET):
        """
        Retrieve the value for the field named `name`.

        If a value is provided for `default`, then it will be
        returned if no value is set
        """
        raise NotImplementedError

    def set(self, name, value):
        """
        Set the value of the field named `name`
        """
        raise NotImplementedError

    def delete(self, name):
        """
        Reset the value of the field named `name` to the default
        """
        raise NotImplementedError

    def has(self, name):
        """
        Return whether or not the field named `name` has a non-default value
        """
        raise NotImplementedError

    def set_many(self, update_dict):
        """Update the underlying model with the correct values."""
        for key, value in update_dict.items():
            self.set(key, value)

    def default(self, name):
        """
        Get the default value for this field which may depend on context or may just be the field's global
        default. The default behavior is to raise KeyError which will cause the caller to return the field's
        global default.
        :param _name: the field's name
        """
        raise NotImplementedError

class BlockScope(object):
    """Enumeration defining BlockScopes"""
    USAGE, DEFINITION, TYPE, ALL = xrange(4)


class Sentinel(object):
    """
    Class for implementing sentinel objects (only equal to themselves).
    """
    def __init__(self, name):
        """
        `name` is the name used to identify the sentinel (which will
            be displayed as the __repr__) of the sentinel.
        """
        self.name = name

    def __repr__(self):
        return self.name


ScopeBase = namedtuple('ScopeBase', 'user block')  # pylint: disable=C0103<commit_msg>default raises KeyError rather than NotImplementedError<commit_after>"""Implementation of the XBlock facility.

This code is in the Runtime layer, because it is authored once by edX
and used by all runtimes.

"""
import copy
import functools
import inspect
try:
    import simplesjson as json  # pylint: disable=F0401
except ImportError:
    import json
from collections import namedtuple
from webob import Response

from .plugin import Plugin


class KeyValueMultiSaveError(Exception):
    """
    Raised to indicated an error in saving multiple fields in a KeyValueStore
    """
    def __init__(self, saved_field_names):
        """
        Create a new KeyValueMultiSaveError

        `saved_field_names` - an iterable of field names (strings) that were
        successfully saved before the exception occured
        """
        super(KeyValueMultiSaveError, self).__init__()
        self.saved_field_names = saved_field_names


class XBlockSaveError(Exception):
    """
    Raised to indicated an error in saving an XBlock
    """
    def __init__(self, saved_fields, dirty_fields):
        """
        Create a new XBlockSaveError

        `saved_fields` - a set of fields that were successfully
        saved before the error occured
        `dirty_fields` - a set of fields that were left dirty after the save
        """
        super(XBlockSaveError, self).__init__()
        self.saved_fields = saved_fields
        self.dirty_fields = dirty_fields


UNSET = object()


class ModelData(object):
    """
    An interface allowing access to an XBlock's field values indexed by field names
    """
    def get(self, name, default=UNSET):
        """
        Retrieve the value for the field named `name`.

        If a value is provided for `default`, then it will be
        returned if no value is set
        """
        raise NotImplementedError

    def set(self, name, value):
        """
        Set the value of the field named `name`
        """
        raise NotImplementedError

    def delete(self, name):
        """
        Reset the value of the field named `name` to the default
        """
        raise NotImplementedError

    def has(self, name):
        """
        Return whether or not the field named `name` has a non-default value
        """
        raise NotImplementedError

    def set_many(self, update_dict):
        """Update the underlying model with the correct values."""
        for key, value in update_dict.items():
            self.set(key, value)

    def default(self, _name):
        """
        Get the default value for this field which may depend on context or may just be the field's global
        default. The default behavior is to raise KeyError which will cause the caller to return the field's
        global default.
        :param _name: the field's name
        """
        raise KeyError

class BlockScope(object):
    """Enumeration defining BlockScopes"""
    USAGE, DEFINITION, TYPE, ALL = xrange(4)


class Sentinel(object):
    """
    Class for implementing sentinel objects (only equal to themselves).
    """
    def __init__(self, name):
        """
        `name` is the name used to identify the sentinel (which will
            be displayed as the __repr__) of the sentinel.
        """
        self.name = name

    def __repr__(self):
        return self.name


ScopeBase = namedtuple('ScopeBase', 'user block')  # pylint: disable=C0103
{'fraction_non_alphanumeric': 0.07384524860253015, 'fraction_numerical': 0.00264783759929391, 'mean_word_length': 2.5448383733055264, 'pattern_counts': {'":': 0, '<': 3, '<?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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5850825', 'n_tokens_mistral': 1823, 'n_tokens_neox': 1758, 'n_words': 722}