Package jsondata :: Module jsondata :: Class JSONData
[hide private]
[frames] | no frames]

Class JSONData

[apisource code


Representation of a JSON based object data tree.

The common node address parameters are defined as: ::

   sourcenode := <commonnode>|<indata> # depends on the interface

   targetnode := <innode>              # target within the represented
                                       # JSON structure

   commonnode := (anydata | indata)

   anydata  := (                       # any data hook - within
                                       # self.data or external
       JSONData                        # - adds to the contained data
                                       #   of the reference
     | <json-array-list>               # - adds to JSON array
     | <json-object-dict>              # - adds to JSON object
   )

   indata := (                         # within self.data
       JSONPointer                     # - adds to the node within
                                       #   self.data [RFC6901]_
     | <rfc6901-string>                # - pointer string within self.data [RFC6901]_
     | <relative-pointer-string>)      # - relative pointer within self.data [RELPOINTER]_
   )

**REMARK**:
    The RFC7159 permits any JSON type as a node, while the RFC4627
    permits array and object as node reference only.

Instance Methods [hide private]
 
__bool__(self)
The boolean value of the contained data status *JSONData*.
[apisource code
 
__call__(self, *args, **kargs)
Evaluates the pointed value from the document.
[apisource code
 
__delitem__(self, k)
Deletes an item of *self.data*.
[apisource code
 
__enter__(self)
Context for processing of specific parameter setups.
[apisource code
 
__eq__(self, x)
Compares this JSONData.data with x.
[apisource code
 
__exit__(self, exc_type, exc_value, traceback)
Resets the context to the parameter setup before the last call of 'enter'.
[apisource code
 
__getitem__(self, sel)
Gets an entry of *self.data*.
[apisource code
 
__init__(self, jdata, **kargs)
Creates and validates a new object from the provided JSON data.
[apisource code
 
__iter__(self)
Provides an iterator for contained native data.
[apisource code
 
__len__(self) [apisource code
 
__ne__(self, x)
Compares this JSONData with x.
[apisource code
 
__nonzero__(self)
The boolean value of the contained data status *JSONData*.
[apisource code
 
__repr__(self)
Dump data.
[apisource code
 
__setitem__(self, k, v)
Assigns a value to an item of *self.data*.
[apisource code
 
__str__(self)
Dumps data by pretty print.
[apisource code
 
branch_add(self, sourcenode, targetnode='', key=None, **kargs)
Add a complete branch into a target structure of type object.
[apisource code
 
branch_copy(self, sourcenode, targetnode='/', key=None, force=True)
Copies the source branch to the target node.
[apisource code
 
branch_create(self, branchpath, targetnode=None, padding_value=None)
Creates an abitrary relative branch from a path description located at *targetnode*.
[apisource code
 
branch_move(self, sourcenode, targetnode=None, key=None, force=False)
Moves a branch to the target node.
[apisource code
 
branch_remove(self, targetnode, key=None, rfc6902=True)
Removes a branch from a contained data in self.
[apisource code
 
branch_replace(self, sourcenode, targetnode, key=None, rfc6902=True)
Replaces the value of the target node by the copy of the source branch.
[apisource code
 
branch_superpose(self, sourcenode, targetnode=None, key=None, **kargs)
Superposes a branch recursively on to the current data tree *self.data* with defined constraints.
[apisource code
 
branch_test(self, targetnode, value)
Tests match in accordance to RFC6902.
[apisource code
 
clear(self)
Clears the contained data.
[apisource code
 
copy(self)
Creates a shallow copy of self.
[apisource code
 
deepcopy(self)
Creates a deep copy of self, including referenced data.
[apisource code
 
dump_data(self, pretty=0, **kargs)
Prints structured data.
[apisource code
 
dump_schema(self, pretty=True, **kargs)
Prints structured schema.
[apisource code
 
get(self, key, default=None)
Transparently passes the 'get()' call to 'self.data'.
[apisource code
 
get_canonical_value(self, node)
Fetches a copy of the canonical value represented by the node.
[apisource code
 
get_data(self)
Returns the reference to data.
[apisource code
 
get_data_items(self)
Returns a dictionary for objects as well as arrays.
[apisource code
 
get_data_keys(self)
Returns a list of keys for objects, or a list of indexes for arrays, thus enabling common access.
[apisource code
 
get_schema(self)
Returns the reference to schema.
[apisource code
 
pop(self, key)
Transparently passes the 'pop()' call to 'self.data'.
[apisource code
 
set_schema(self, schemafile=None, targetnode=None, **kargs)
Sets schema or inserts a new branch into the current assigned schema.
[apisource code
 
setkargs(self, **kargs)
Sets key arguments.
[apisource code
 
validate(self, data, schema, validator=None)
Validate data with schema by selected validator.
[apisource code

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __sizeof__, __subclasshook__

Instance Variables [hide private]
  indent_str
for __str__
  jsonsyntax
controls context parameter restoration
  saveContext
controls context parameter restoration
  schema
The internal object schema for the framework - a fixed set of files as final MS_DRAFT4.
  sort_keys
for __str__
Properties [hide private]

Inherited from object: __class__

Method Details [hide private]

__bool__(self)

[apisource code 
The boolean value of the contained data status *JSONData*.

Args:
    None

Returns:
    True:  has any data
    False: no data contained, this is also the case for empty *list* and *dict*

__call__(self, *args, **kargs)
(Call operator)

[apisource code 
Evaluates the pointed value from the document.

The operation::

   z = S(x)

Returns the top node referenced by the JSON-Pointer 'x' in accordance to RFC6901::

   z = ( S => x )

Args:
    *args:

        args[0]:
            An optional valid JSONPointer.

            default:='' => top, see [RFC6901]_

    **kargs:

        **copydata**:
            Use of input parameters for processing. ::

               copydata := (
                    C_DEEP     | 'deep'
                  | C_REF      | 'ref'
                  | C_SHALLOW  | 'shallow')

            default := C_REF

Returns:
    The pointed value, or None.

Raises:
    JSONPointerError

__delitem__(self, k)
(Index deletion operator)

[apisource code 
Deletes an item of *self.data*.

Args:
    k:
        Key or index of *self.data*.
        If *None* the *self.data* is assigned *None*.

Returns:
    None

Raises:
    JSONDataKeyError

    IndexError

__enter__(self)

[apisource code 
Context for processing of specific parameter setups.

Args:

    Context Parameters:
        See setargs. ::

           copy, rtype, saveContext


Returns:

Raises:

__eq__(self, x)
(Equality operator)

[apisource code 
Compares this JSONData.data with x.

The operations: ::

   S == x

Returns the result of comparison: ::

   z = ( S == x )

Args:

    x: A valid JSONData.

Context Parameters:

    See setargs.

Returns:

    True or False

Raises:

    JSONDataError

__getitem__(self, sel)
(Indexing operator)

[apisource code 
Gets an  entry of *self.data*.

Args:
    sel:
        Selector, either a key, or an index.

Returns:
    The entry at the location,
    or raises en exception.

Raises:
    JSONDataKeyError(KeyError)

    JSONDataIndexError(IndexError)

__init__(self, jdata, **kargs)
(Constructor)

[apisource code 
Creates and validates a new object from the provided JSON data.
Arbitrary additional JSON data could be added as branches.

Args:
    **jdata**:
        The initial data of current instance. The accepted formats
        are in-memory representation of JSON data compatible with
        the standard library *json* [json]_. The permitted input
        types vary in accordance to the selected operations mode
        of either *RFC4627* or *RFC7159*. ::

           type(jdata) := (
                list,       # json-array
              | dict,       # json-object
              | JSONData    # copy constructor
              | int         # RFC7159 only
              | float       # RFC7159 only
              | unicode     # RFC7159 only
           )

        .. note::

           Further branches could be added to json-objects,
           and json-arrays only, while values in RFC7159 and RFC8259
           mode permit replacement only. Objects support string indexes,
           arrays integer indexes.

    kargs:
        For the complete set of call parameters refer to
        the method **JSONData.setkargs()**.

        **mode**:
            The mode of JSON processing: ::

               mode := (
                    MJ_RFC4627
                  | MJ_RFC7493  # currently not supported, mapped to RFC7159
                  | MJ_RFC7159
                  | MJ_RFC8259
                  | MJ_ECMA404  # same as RFC8259
               )

            default := MJ_RFC7159

        **schema**:
            A valid in-memory JSONschema.

            default:= None

        **validator**:
            Sets schema validator for the data file.
            Curren release relies on *jsonschema*, which
            supports at the time of writing draft-03 and
            draft-04.

            The values are: ::

                validator := (
                      MS_DRAFT3           | 'draft3'
                    | MS_DRAFT4           | 'draft4'
                    | MS_ON               | 'on'
                    | MS_OFF              | 'off'
                    | MODE_SCHEMA_DEFAULT | 'default'
                )

            default:= MS_OFF

Returns:

    Results in an initialized object.

Raises:

    NameError

    JSONDataValueError

    jsonschema.ValidationError

    jsonschema.SchemaError

Overrides: object.__init__

__ne__(self, x)

[apisource code 
Compares this JSONData with x.

Args:
    x:
        Valid JSONData.

Returns:
    True or False

Raises:
    JSONDataError

__nonzero__(self)
(Boolean test operator)

[apisource code 
The boolean value of the contained data status *JSONData*.

Args:
    None

Returns:
    True:  has any data
    False: no data contained, this is also the case for empty *list* and *dict*

__repr__(self)
(Representation operator)

[apisource code 

Dump data.

Overrides: object.__repr__

__str__(self)
(Informal representation operator)

[apisource code 

Dumps data by pretty print.

The data representation is controlled by the variable 'self.jsonsyn' :

  JSONData.jsonscope := (JSYN_NATIVE | JSYN_PYTHON)

  JSYN_NATIVE: "Literally in accordance to standards."
  JSYN_PYTHON: "Python in-memory syntax representation."
Overrides: object.__str__

branch_add(self, sourcenode, targetnode='', key=None, **kargs)

[apisource code 
Add a complete branch into a target structure of type object.
Present branches are replaced, non-existent branches are
added.

The parent of the insertion point has to exist by default,
see [RFC6902]_. If the target is an array, the source is either
appended, or inserted [RFC6902]_.

Args:
    **sourcenode**:
        Source branch to be inserted into the target tree.
        Either from within self-data, or an external source: ::

          sourcenode := <commonnode>       # see class header

    **targetnode**:
        Target node within self-data, where the branch is to be inserted. ::

          targetnode := <innode>           # see class header

        default := ''                      # the top of the 'whole document'

    **key**:
        Hook for the insertion within the target node. If not
        provided the contents of the target node itself are
        replaced by the source node.

        default := None

    kargs:
        **copydata**:
            The type of creation of the added branch. ::

                copydata := (
                      C_REF        # copy the reference only
                    | C_DEEP       # call copy.deepcopy()
                    | C_SHALLOW    # call copy.copy()
                )

            default := C_DEEP

Returns:
    When successful returns *True*, else returns
    either *False*, or raises an exception.

Raises:
    JSONDataNodeError:
        The target node is not contained in current object.

    JSONDataNodeTypeError:
        The types mismatch.

    JSONDataKeyError:
        Key mismatch.

branch_copy(self, sourcenode, targetnode='/', key=None, force=True)

[apisource code 
Copies the source branch to the target node.
The *branch_copy* is internally mapped to the call *branch_add*,
thus shares basically the same parameters and behavior.

Args:

    **sourcenode**:
        Source branch to be copied into target tree.
        Either from within self-data, or an external source: ::

          sourcenode := <commonnode>       # see class header

    **targetnode**:
        Target node for the branch. Either from within self-data,
        or an external source: ::

          targetnode := <innode>           # see class header

        default := '/'

    **key**:
        Optional key for the insertion point within target
        node, if not provided the target node itself.

    **force**:
        If true present are replaced, else only non-present
        targets are copied.

        default := True

Returns:
    When successful returns *True*, else returns either *False*,
    or raises an exception.

Raises:
    JSONDataError

    pass-through

branch_create(self, branchpath, targetnode=None, padding_value=None)

[apisource code 
Creates an abitrary relative branch from a path description
located at *targetnode*. Intermediate nodes are created automatically
when missing.

The requested branch is created as the relative child branch
of the provided *targetnode*. The *targetnode* must exist,
while the child node - *branchpath[0]* - must not.

Args:

    **branchpath**:
        New branch to be created in the target node.
        A Pointer address path relative to the *targetnode*. ::

          branchpath := <commonnode>           # see class header

    **targetnode**:
        Base node for the created branch, must exist
        and located within the data tree of current object. ::

          targetnode := <innode>           # see class header

        default := "/"

    **padding_value**:
        Optional default value, either an atomic type or a sub-branch
        itself. This value is only used for a new leaf, in case of
        an existent node the value is ignored.

        default := "null" / *None*

Returns:
    When successful returns the created node, else returns
    either *None*, or raises an exception.

Raises:
    JSONDataError

    JSONDataKeyError

    JSONDataNodeTypeError

    JSONDataParameterError

    JSONDataPathError

branch_move(self, sourcenode, targetnode=None, key=None, force=False)

[apisource code 
Moves a branch to the target node.

Args:

    **sourcenode**:
        Source branch to be moved into the target node.
        Must be member of the self-data structure, else use
        either *branch_add* or *branch_copy*.
        Either from within self-data, or an external source: ::

          sourcenode := <innode>       # see class header

    **targetnode**:
        Target node for the branch. ::

          targetnode := <innode>       # see class header

        default := '/'

    **key**:
        Optional key for the insertion point within target
        node, if not provided the target node itself.

    **force**:
        If true present are replaced, else only non-present
        are copied.

        default := True

Returns:
    When successful returns *True*, else returns either
    *None*, or raises an exception.

Raises:
    JSONDataError

    JSONDataKeyError

branch_remove(self, targetnode, key=None, rfc6902=True)

[apisource code 
Removes a branch from a contained data in self.

Args:

    **targetnode**:
        Container with item to be removed. ::

          targetnode := <innode>       # see class header

    **key**:
        Key of insertion point within target node, if not
        provided the target node itself.

    **rfc6902**:
        If *True* the removed element has to be present,
        else non-present is simply ignored.

Returns:
    When successful returns *True*, else returns
    either *False*, or raises an exception.

Raises:
    JSONDataKeyError

    JSONDataNodeTypeError

branch_replace(self, sourcenode, targetnode, key=None, rfc6902=True)

[apisource code 
Replaces the value of the target node by the copy
of the source branch.

Requires in order to RFC6902, all items to be replaced
has to be present. Thus fails by default if at least one
is missing.

Internally the 'branch_add()' call is used with a deep copy.
When a swallow copy is required the 'branch_move()' has to be used.

Args:
    **sourcenode**:
        Source branch to be inserted into target tree.
        Either from within self-data, or an external source: ::

          sourcenode := <commonnode>   # see class header

    **targetnode**:
        Target where the branch is inserted. ::

          targetnode := <innode>       # see class header

    **key**:
        Key of insertion point within target node, if not
        provided the target node itself.

    **rfc6902**:
        If *True* the removed element has to be present,
        else non-present is simply ignored.

Returns:
    When successful returns *True*, else returns
    either *False*, or raises an exception.

Raises:
    JSONDataError

branch_superpose(self, sourcenode, targetnode=None, key=None, **kargs)

[apisource code 
Superposes a branch recursively on to the current data tree 
*self.data* with defined constraints. Provides partial mapping 
in dependence of parameters and data entries of source and/or 
target.

The processing is controlled by logic operations on node 
structures, which maps a logical tree of JSON nodes from the
source node onto the subtree of JSON nodes defined by the target
target node. The provided logic operators are related to structure,
though the types of nodes, not the contents.

For the provided logic operators refer to parameter *map*.

Args:

    **sourcenode**:
        Value struct to be inserted.

        default := None

    **targetnode**:
        Data node within current document to be superposed.

        default := None  # whole document *self.data*

    **key**:
        Hook selector within the data tree spanned by the targetnode .

        default := None  # top of the targetnode

    kargs:
        **copy**:
            Create a copy of the sourcenode. ::

               copy := (
                    C_DEEP      # insert from copy.deepcopy() 
                  | C_SHALLOW   # insert from copy.copy()
                  | C_REF       # insert from the provided parameter
                  )

            default := C_REF  # no copy, work on input

        **depth**: 
            Sets the default behavior for the operators
            on the data branches. Controls, whether the hook
            only or the complete branch is processed in 
            depth node-by-node. ::

              0:  the hook of the branch
              #n: the level of the branch as integer, the 
                  remaining sub-branch is treated by it's hook
              -1: the complete branch

            default:= 0

        **ignore**:
            Ignores attributes including subtrees contained 
            in the list. ::

               ignore := [<list-of-rfc6901-path-items>]

        **map**:
            Sets the default behavior for the mapping of
            branches by operators. This is also influenced 
            by the parameter 'op_depth'. ::

              B_AND:  replace corresponding leafs only when any target node is present
              B_OR:   replace corresponding items of source leafs
              B_XOR:  insert only when no target node is present

            default:= B_OR

        **use**:
            Considers the listed attributes only as white list. ::

               use := [<list-of-rfc6901-path-items>]

Returns:
    *True* for success, else *False* or raises exception.

Raises:
    JSONDataError

    JSONDataIndexError
    
    pass-through

branch_test(self, targetnode, value)

[apisource code 
Tests match in accordance to RFC6902.

Args:
    **targetnode**:
        Node to be compared with the value. Due to
        ambiguity the automated conversion is not
        reliable, thus it has to be valid. ::

          targetnode := <innode>       # see class header

    **value**:
        Expected value for the given node.

Returns:
    When successful returns 'True', else returns 'False'.

Raises:
    JSONDataError

deepcopy(self)

[apisource code 

Creates a deep copy of self, including referenced data. The schema is kept as a shared reference.

dump_data(self, pretty=0, **kargs)

[apisource code 
Prints structured data.

Args:

    **pretty**:
        Activates pretty printer, else flat. ::

           format := (
                PJ_TREE    # tree view JSON syntax
              | PJ_FLAT    # flat print JSON syntax
              | PJ_PYTREE  # tree view Python syntax
              | PJ_PYFLAT  # flat print Python syntax
              | PJ_REPR    # repr() - raw string, Python syntax
              | PJ_STR     # str() - formatted string, Python syntax
           )

    kargs:
        **source**:
            Prints data within 'source'.

            default:=self.data

Returns:
    When successful returns 'True', else returns either
    'False', or raises an exception.

Raises:
    pass-through

dump_schema(self, pretty=True, **kargs)

[apisource code 
Prints structured schema.

Args:

    **pretty**:
        Activates pretty printer for treeview,
        else flat.

    kargs:
        **source**:
            Prints schema within 'source'.

            default:=self.schema

Returns:
    When successful returns 'True', else returns
    either 'False', or raises an exception.

Raises:
    pass-through

get_canonical_value(self, node)

[apisource code 
Fetches a copy of the canonical value represented by
the node. The actual value could be either an atomic value,
a node representing a branch, or a reference to
an atomic value.
Creates a deep copy, thus references are no longer
valid.

Args:
    **value**:
        Value pointer to be evaluated to the actual
        value. Valid input types are:

            int,str,unicode:
                Integer, kept as an atomic integer
                value.

            dict,list:
                Assumed to be a valid node for 'json'
                package, used by reference.

            JSONPointer:
                A JSON pointer in accordance to
                RFC6901.

Returns:
    When successful returns the value, else returns
    either 'False', or raises an exception.

Raises:
    JSONDataError

get_data_items(self)

[apisource code 

Returns a dictionary for objects as well as arrays. Arrays are returned as a *dict* with interger indexes as keys, while objects - *dict* - are returned by the native *items()* call.

If required else use the attributes directly.

get_data_keys(self)

[apisource code 
Returns a list of keys for objects, or a list of indexes
for arrays, thus enabling common access.

Args:
    None

Returns:
    For objects - dict - a list of keys,
    for arrays - list - a list of integer indexes.

Raises:
    pass-through

set_schema(self, schemafile=None, targetnode=None, **kargs)

[apisource code 
Sets schema or inserts a new branch into the current
assigned schema.

The main schema(targetnode==None) is the schema related
to the current instance. Additional branches could be added
by importing the specific schema definitions into the main
schema. These could either kept volatile as a temporary
runtime extension, or stored into a new schema file in order
as extension of the original for later combined reuse.

Args:
    **schemafile**:
        JSON-Schema filename for validation of the
        subtree/branch. See also **kargs['schema'].

    **targetnode**:
        Target container hook for the inclusion of
        the loaded branch.

    kargs:
        **schema**:
            In-memory JSON-Schema as an alternative
            to schemafile. When provided the 'schemafile'
            is ignored.

            default:=None

        **validator**:
            Sets schema validator for the data file.
            The values are: ::

               validator := (
                    default = validate,
                  | draft3  = Draft3Validator,
                  | off     = None.
               )

            default:= validate

        **persistent**:
            Stores the 'schema' persistently into 'schemafile'
            after completion of update including addition of
            branches. Requires valid 'schemafile'.

            default:=False

Returns:
    When successful returns 'True', else returns either
    'False', or raises an exception.

Raises:

    JSONDataError

    JSONDataSourceFileError

    JSONDataValueError

setkargs(self, **kargs)

[apisource code 
Sets key arguments.

Args:

    kargs:

        **copydata**:
            Controls the assignment policy for JSON data.
            The schema is copied by reference only, once
            read. ::

               copydata := (
                    C_REF       # by reference
                  | C_DEEP      # by copy.deepcopy()
                  | C_SHALLOW   # by copy.copy()
               )

        **debug**:
            Displays extended state data for developers.
            Requires __debug__==True.

        **depth**:
            Sets the default behavior for the operators.
            Controls, whether the hook only or the complete
            branch is processed in depth node-by-node. ::

               0:  the hook of the branch
               #n: the level of the branch as integer, the
                   remaining sub-branch is treated by it's hook
               -1: the complete branch

            default:= 0

        **indent_str**:
            Defied the indentation of 'str'.

            default:= 4

        **jsonsyntax**:
            The display syntax for JSON data with
            *__str__*. ::

               jsonsyntax := (
                    JSYN_NATIVE | 'json'
                  | JSYN_PYTHON | 'python'
               )

               JSYN_NATIVE: Native standards syntax.
               JSYN_PYTHON: Python in-memory syntax.

        **mode**:
            The mode of JSON processing: ::

               mode := (
                    MJ_RFC4627 | 'rfc4627'
                  | MJ_RFC7493 | 'rfc7493'  # currently not supported, mapped to RFC7159
                  | MJ_RFC7159 | 'rfc7159'
                  | MJ_RFC8259 | 'rfc8259'
                  | MJ_ECMA404 | 'ecma404'  # same as RFC8259
               )

            default := MJ_RFC7159

        **rtype**:
            Sets the data type of the returned result. ::

               rtype := (
                    data    # returns the data record only - self.data
                  | jdata   # returns an object of class JSONData
                  | obj     # returns an object of own class
               )

            default := obj

        **saveContext**:
            Saves and restores the defined context
            parameters when entering a context call.

            default:= True

        **schema**:
            A valid in-memory JSONschema.

            default:= None

        **sortstr**:
            Sort display of 'str()' by key. ::

                sortstr := (True | False)

            default := True

        **validator**:
            Sets schema validator for the data file.
            Curren release relies on *jsonschema*, which
            supports at the time of writing draft-03 and
            draft-04.

            The values are: ::

                validator := (
                      MS_DRAFT3           | 'draft3'
                    | MS_DRAFT4           | 'draft4'
                    | MS_ON               | 'on'
                    | MS_OFF              | 'off'
                    | MODE_SCHEMA_DEFAULT | 'default'
                )

            default:= MS_OFF

        **verbose**:
            Extends the amount of the display of
            processing data.

Returns:
    instance/None

Raises:

    NameError:

    JSONDataValueError

    jsonschema.ValidationError:

    jsonschema.SchemaError:

validate(self, data, schema, validator=None)

[apisource code 
Validate data with schema by selected validator.

Args:

    **data**:
        JSON-Data.

    **schema**:
        JSON-Schema for validation.

    **validator**:
        Validator to be applied, current supported:

            schema:

                In-memory JSON-Schema as an alternative
                to schemafile. When provided the 'schemafile'
                is ignored.

                default:=None

        **validator**: [default, draft3, draft4, off, on, ]
            Sets schema validator for the data file.

                default|MS_ON:
                    The current default.

                draft3|MS_DRAFT3:
                    The first supported JSONSchema IETF-Draft.

                draft4|MS_DRAFT4:
                    The current supported JSONSchema IETF-Draft.

                off|MS_OFF:
                    No validation.

            default:= MS_DRAFT4

Returns:
    When successful returns 'True', else returns
    either 'False', or raises an exception.

Raises:

    JSONDataValidationError

    JSONDataSchemaError

    JSONDataValueError